1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +02:00

Add range selection ability on list contexts

This adds range select ability in two ways:
1) Sticky: like what we already have with the staging view i.e. press v then use arrow keys
2) Non-sticky: where you just use shift+up/down to expand the range

The state machine works like this:
(no range, press 'v') -> sticky range
(no range, press arrow) -> no range
(no range, press shift+arrow) -> nonsticky range
(sticky range, press 'v') -> no range
(sticky range, press arrow) -> sticky range
(sticky range, press shift+arrow) -> nonsticky range
(nonsticky range, press 'v') -> no range
(nonsticky range, press arrow) -> no range
(nonsticky range, press shift+arrow) -> nonsticky range
This commit is contained in:
Jesse Duffield
2024-01-07 19:44:19 +11:00
parent e887a2eb3c
commit 24a4302c52
42 changed files with 533 additions and 213 deletions

View File

@ -201,6 +201,9 @@ keybinding:
toggleWhitespaceInDiffView: '<c-w>' toggleWhitespaceInDiffView: '<c-w>'
increaseContextInDiffView: '}' increaseContextInDiffView: '}'
decreaseContextInDiffView: '{' decreaseContextInDiffView: '{'
toggleRangeSelect: 'v'
rangeSelectUp: '<s-up>'
rangeSelectDown: '<s-down>'
status: status:
checkForUpdate: 'u' checkForUpdate: 'u'
recentRepos: '<enter>' recentRepos: '<enter>'
@ -263,8 +266,6 @@ keybinding:
commitFiles: commitFiles:
checkoutCommitFile: 'c' checkoutCommitFile: 'c'
main: main:
toggleDragSelect: 'v'
toggleDragSelect-alt: 'V'
toggleSelectHunk: 'a' toggleSelectHunk: 'a'
pickBothHunks: 'b' pickBothHunks: 'b'
submodules: submodules:

View File

@ -3,8 +3,9 @@
* [Configuration](./Config.md). * [Configuration](./Config.md).
* [Custom Commands](./Custom_Command_Keybindings.md) * [Custom Commands](./Custom_Command_Keybindings.md)
* [Custom Pagers](./Custom_Pagers.md) * [Custom Pagers](./Custom_Pagers.md)
* [Dev docs](./dev)
* [Keybindings](./keybindings) * [Keybindings](./keybindings)
* [Undo/Redo](./Undoing.md) * [Undo/Redo](./Undoing.md)
* [Range Select](./Range_Select.md)
* [Searching/Filtering](./Searching.md) * [Searching/Filtering](./Searching.md)
* [Stacked Branches](./Stacked_Branches.md) * [Stacked Branches](./Stacked_Branches.md)
* [Dev docs](./dev)

14
docs/Range_Select.md Normal file
View File

@ -0,0 +1,14 @@
# Range Select
Some actions can be performed on a range of contiguous items. For example:
* staging multiple files at once
* squashing multiple commits at once
* copying (for cherry-pick) multiple commits at once
There are two ways to select a range of items:
1. Sticky range select: Press 'v' to toggle range select, then expand the selection using the up/down arrow key. To reset the selection, press 'v' again.
2. Non-sticky range select: Press shift+up or shift+down to expand the selection. To reset the selection, press up/down without shift.
The sticky option will be more familiar to vim users, and the second option will feel more natural to users who aren't used to doing things in a modal way.
In order to perform an action on a range of items, simply press the normal key for that action. If the action only works on individual items, it will raise an error. This is a new feature and the plan is to incrementally support range select for more and more actions. If there is an action you would like to support range select which currently does not, please raise an issue in the repo.

6
go.mod
View File

@ -16,7 +16,7 @@ require (
github.com/integrii/flaggy v1.4.0 github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20240103192639-2874168c14db github.com/jesseduffield/gocui v0.3.1-0.20240118234343-2d41754af383
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
@ -74,8 +74,8 @@ require (
github.com/xanzy/ssh-agent v0.2.1 // indirect github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.7.0 // indirect golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.15.0 // indirect golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
) )

10
go.sum
View File

@ -187,8 +187,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20240103192639-2874168c14db h1:ihJdYk85/XQLGiG3b6m8P2z+RUohRMtPmX74YR9IT8s= github.com/jesseduffield/gocui v0.3.1-0.20240118234343-2d41754af383 h1:twcgVo+K7UTXwrsNtlCvTi8AyCp7CuBX//+j4wWkivQ=
github.com/jesseduffield/gocui v0.3.1-0.20240103192639-2874168c14db/go.mod h1:9zkyjnUmdL3+sUknJrQy/3HweUu8mVln/3J2wRF/l8M= github.com/jesseduffield/gocui v0.3.1-0.20240118234343-2d41754af383/go.mod h1:9zkyjnUmdL3+sUknJrQy/3HweUu8mVln/3J2wRF/l8M=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
@ -469,13 +469,15 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -304,6 +304,9 @@ type KeybindingUniversalConfig struct {
ScrollRight string `yaml:"scrollRight"` ScrollRight string `yaml:"scrollRight"`
GotoTop string `yaml:"gotoTop"` GotoTop string `yaml:"gotoTop"`
GotoBottom string `yaml:"gotoBottom"` GotoBottom string `yaml:"gotoBottom"`
ToggleRangeSelect string `yaml:"toggleRangeSelect"`
RangeSelectDown string `yaml:"rangeSelectDown"`
RangeSelectUp string `yaml:"rangeSelectUp"`
PrevBlock string `yaml:"prevBlock"` PrevBlock string `yaml:"prevBlock"`
NextBlock string `yaml:"nextBlock"` NextBlock string `yaml:"nextBlock"`
PrevBlockAlt string `yaml:"prevBlock-alt"` PrevBlockAlt string `yaml:"prevBlock-alt"`
@ -441,11 +444,9 @@ type KeybindingCommitFilesConfig struct {
} }
type KeybindingMainConfig struct { type KeybindingMainConfig struct {
ToggleDragSelect string `yaml:"toggleDragSelect"` ToggleSelectHunk string `yaml:"toggleSelectHunk"`
ToggleDragSelectAlt string `yaml:"toggleDragSelect-alt"` PickBothHunks string `yaml:"pickBothHunks"`
ToggleSelectHunk string `yaml:"toggleSelectHunk"` EditSelectHunk string `yaml:"editSelectHunk"`
PickBothHunks string `yaml:"pickBothHunks"`
EditSelectHunk string `yaml:"editSelectHunk"`
} }
type KeybindingSubmodulesConfig struct { type KeybindingSubmodulesConfig struct {
@ -704,6 +705,9 @@ func GetDefaultConfig() *UserConfig {
ScrollRight: "L", ScrollRight: "L",
GotoTop: "<", GotoTop: "<",
GotoBottom: ">", GotoBottom: ">",
ToggleRangeSelect: "v",
RangeSelectDown: "<s-down>",
RangeSelectUp: "<s-up>",
PrevBlock: "<left>", PrevBlock: "<left>",
NextBlock: "<right>", NextBlock: "<right>",
PrevBlockAlt: "h", PrevBlockAlt: "h",
@ -833,11 +837,9 @@ func GetDefaultConfig() *UserConfig {
CheckoutCommitFile: "c", CheckoutCommitFile: "c",
}, },
Main: KeybindingMainConfig{ Main: KeybindingMainConfig{
ToggleDragSelect: "v", ToggleSelectHunk: "a",
ToggleDragSelectAlt: "V", PickBothHunks: "b",
ToggleSelectHunk: "a", EditSelectHunk: "E",
PickBothHunks: "b",
EditSelectHunk: "E",
}, },
Submodules: KeybindingSubmodulesConfig{ Submodules: KeybindingSubmodulesConfig{
Init: "i", Init: "i",

View File

@ -32,6 +32,14 @@ func (self *ListContextTrait) FocusLine() {
self.GetViewTrait().FocusPoint( self.GetViewTrait().FocusPoint(
self.ModelIndexToViewIndex(self.list.GetSelectedLineIdx())) self.ModelIndexToViewIndex(self.list.GetSelectedLineIdx()))
selectRangeIndex, isSelectingRange := self.list.GetRangeStartIdx()
if isSelectingRange {
selectRangeIndex = self.ModelIndexToViewIndex(selectRangeIndex)
self.GetViewTrait().SetRangeSelectStart(selectRangeIndex)
} else {
self.GetViewTrait().CancelRangeSelect()
}
// If FocusPoint() caused the view to scroll (because the selected line // If FocusPoint() caused the view to scroll (because the selected line
// was out of view before), we need to rerender the view port again. // was out of view before), we need to rerender the view port again.
// This can happen when pressing , or . to scroll by pages, or < or > to // This can happen when pressing , or . to scroll by pages, or < or > to
@ -84,7 +92,7 @@ func (self *ListContextTrait) HandleFocusLost(opts types.OnFocusLostOpts) error
// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view // OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view
func (self *ListContextTrait) HandleRender() error { func (self *ListContextTrait) HandleRender() error {
self.list.RefreshSelectedIdx() self.list.ClampSelection()
content := self.renderLines(-1, -1) content := self.renderLines(-1, -1)
self.GetViewTrait().SetContent(content) self.GetViewTrait().SetContent(content)
self.c.Render() self.c.Render()

View File

@ -9,13 +9,34 @@ type HasLength interface {
Len() int Len() int
} }
type RangeSelectMode int
const (
// None means we are not selecting a range
RangeSelectModeNone RangeSelectMode = iota
// Sticky range select is started by pressing 'v', then the range is expanded
// when you move up or down. It is cancelled by pressing 'v' again.
RangeSelectModeSticky
// Nonsticky range select is started by pressing shift+arrow and cancelled
// when pressing up/down without shift, or by pressing 'v'
RangeSelectModeNonSticky
)
type ListCursor struct { type ListCursor struct {
selectedIdx int selectedIdx int
list HasLength rangeSelectMode RangeSelectMode
// value is ignored when rangeSelectMode is RangeSelectModeNone
rangeStartIdx int
list HasLength
} }
func NewListCursor(list HasLength) *ListCursor { func NewListCursor(list HasLength) *ListCursor {
return &ListCursor{selectedIdx: 0, list: list} return &ListCursor{
selectedIdx: 0,
rangeStartIdx: 0,
rangeSelectMode: RangeSelectModeNone,
list: list,
}
} }
var _ types.IListCursor = (*ListCursor)(nil) var _ types.IListCursor = (*ListCursor)(nil)
@ -25,24 +46,86 @@ func (self *ListCursor) GetSelectedLineIdx() int {
} }
func (self *ListCursor) SetSelectedLineIdx(value int) { func (self *ListCursor) SetSelectedLineIdx(value int) {
self.selectedIdx = self.clampValue(value)
}
func (self *ListCursor) clampValue(value int) int {
clampedValue := -1 clampedValue := -1
if self.list.Len() > 0 { if self.list.Len() > 0 {
clampedValue = utils.Clamp(value, 0, self.list.Len()-1) clampedValue = utils.Clamp(value, 0, self.list.Len()-1)
} }
self.selectedIdx = clampedValue return clampedValue
} }
// moves the cursor up or down by the given amount // Moves the cursor up or down by the given amount.
func (self *ListCursor) MoveSelectedLine(delta int) { // If we are in non-sticky range select mode, this will cancel the range select
self.SetSelectedLineIdx(self.selectedIdx + delta) func (self *ListCursor) MoveSelectedLine(change int) {
if self.rangeSelectMode == RangeSelectModeNonSticky {
self.CancelRangeSelect()
}
self.SetSelectedLineIdx(self.selectedIdx + change)
} }
// to be called when the model might have shrunk so that our selection is not not out of bounds // Moves the cursor up or down by the given amount, and also moves the range start
func (self *ListCursor) RefreshSelectedIdx() { // index by the same amount
self.SetSelectedLineIdx(self.selectedIdx) func (self *ListCursor) MoveSelection(delta int) {
self.selectedIdx = self.clampValue(self.selectedIdx + delta)
if self.IsSelectingRange() {
self.rangeStartIdx = self.clampValue(self.rangeStartIdx + delta)
}
}
// To be called when the model might have shrunk so that our selection is not out of bounds
func (self *ListCursor) ClampSelection() {
self.selectedIdx = self.clampValue(self.selectedIdx)
self.rangeStartIdx = self.clampValue(self.rangeStartIdx)
} }
func (self *ListCursor) Len() int { func (self *ListCursor) Len() int {
return self.list.Len() return self.list.Len()
} }
func (self *ListCursor) GetRangeStartIdx() (int, bool) {
if self.IsSelectingRange() {
return self.rangeStartIdx, true
}
return 0, false
}
func (self *ListCursor) CancelRangeSelect() {
self.rangeSelectMode = RangeSelectModeNone
}
func (self *ListCursor) IsSelectingRange() bool {
return self.rangeSelectMode != RangeSelectModeNone
}
func (self *ListCursor) GetSelectionRange() (int, int) {
if self.IsSelectingRange() {
return utils.MinMax(self.selectedIdx, self.rangeStartIdx)
}
return self.selectedIdx, self.selectedIdx
}
func (self *ListCursor) ToggleStickyRange() {
if self.IsSelectingRange() {
self.CancelRangeSelect()
} else {
self.rangeStartIdx = self.selectedIdx
self.rangeSelectMode = RangeSelectModeSticky
}
}
func (self *ListCursor) ExpandNonStickyRange(change int) {
if !self.IsSelectingRange() {
self.rangeStartIdx = self.selectedIdx
}
self.rangeSelectMode = RangeSelectModeNonSticky
self.SetSelectedLineIdx(self.selectedIdx + change)
}

View File

@ -21,6 +21,14 @@ func (self *ViewTrait) FocusPoint(yIdx int) {
self.view.FocusPoint(self.view.OriginX(), yIdx) self.view.FocusPoint(self.view.OriginX(), yIdx)
} }
func (self *ViewTrait) SetRangeSelectStart(yIdx int) {
self.view.SetRangeSelectStart(yIdx)
}
func (self *ViewTrait) CancelRangeSelect() {
self.view.CancelRangeSelect()
}
func (self *ViewTrait) SetViewPortContent(content string) { func (self *ViewTrait) SetViewPortContent(content string) {
_, y := self.view.Origin() _, y := self.view.Origin()
self.view.OverwriteLines(y, content) self.view.OverwriteLines(y, content)

View File

@ -71,9 +71,25 @@ func (self *ListController) scrollHorizontal(scrollFunc func()) error {
} }
func (self *ListController) handleLineChange(change int) error { func (self *ListController) handleLineChange(change int) error {
before := self.context.GetList().GetSelectedLineIdx() return self.handleLineChangeAux(
self.context.GetList().MoveSelectedLine(change) self.context.GetList().MoveSelectedLine, change,
after := self.context.GetList().GetSelectedLineIdx() )
}
func (self *ListController) HandleRangeSelectChange(change int) error {
return self.handleLineChangeAux(
self.context.GetList().ExpandNonStickyRange, change,
)
}
func (self *ListController) handleLineChangeAux(f func(int), change int) error {
list := self.context.GetList()
rangeBefore := list.IsSelectingRange()
before := list.GetSelectedLineIdx()
f(change)
rangeAfter := list.IsSelectingRange()
after := list.GetSelectedLineIdx()
if err := self.pushContextIfNotFocused(); err != nil { if err := self.pushContextIfNotFocused(); err != nil {
return err return err
@ -81,7 +97,8 @@ func (self *ListController) handleLineChange(change int) error {
// doing this check so that if we're holding the up key at the start of the list // doing this check so that if we're holding the up key at the start of the list
// we're not constantly re-rendering the main view. // we're not constantly re-rendering the main view.
if before != after { cursorMoved := before != after
if cursorMoved {
if change == -1 { if change == -1 {
checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig, checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig,
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
@ -89,7 +106,9 @@ func (self *ListController) handleLineChange(change int) error {
checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig, checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig,
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after)) self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
} }
}
if cursorMoved || rangeBefore != rangeAfter {
return self.context.HandleFocus(types.OnFocusOpts{}) return self.context.HandleFocus(types.OnFocusOpts{})
} }
@ -112,6 +131,22 @@ func (self *ListController) HandleGotoBottom() error {
return self.handleLineChange(self.context.GetList().Len()) return self.handleLineChange(self.context.GetList().Len())
} }
func (self *ListController) HandleToggleRangeSelect() error {
list := self.context.GetList()
list.ToggleStickyRange()
return self.context.HandleFocus(types.OnFocusOpts{})
}
func (self *ListController) HandleRangeSelectDown() error {
return self.HandleRangeSelectChange(1)
}
func (self *ListController) HandleRangeSelectUp() error {
return self.HandleRangeSelectChange(-1)
}
func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error { func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error {
prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx() prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx()
newSelectedLineIdx := self.context.ViewIndexToModelIndex(opts.Y) newSelectedLineIdx := self.context.ViewIndexToModelIndex(opts.Y)
@ -159,6 +194,9 @@ func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft}, {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight}, {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom}, {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ToggleRangeSelect), Handler: self.HandleToggleRangeSelect, Description: self.c.Tr.ToggleRangeSelect},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.RangeSelectDown), Handler: self.HandleRangeSelectDown, Description: self.c.Tr.RangeSelectDown},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.RangeSelectUp), Handler: self.HandleRangeSelectUp, Description: self.c.Tr.RangeSelectUp},
} }
} }

View File

@ -75,14 +75,9 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts)
Handler: self.withRenderAndFocus(self.HandleNextHunk), Handler: self.withRenderAndFocus(self.HandleNextHunk),
}, },
{ {
Key: opts.GetKey(opts.Config.Main.ToggleDragSelect), Key: opts.GetKey(opts.Config.Universal.ToggleRangeSelect),
Handler: self.withRenderAndFocus(self.HandleToggleSelectRange), Handler: self.withRenderAndFocus(self.HandleToggleSelectRange),
Description: self.c.Tr.ToggleDragSelect, Description: self.c.Tr.ToggleRangeSelect,
},
{
Key: opts.GetKey(opts.Config.Main.ToggleDragSelectAlt),
Handler: self.withRenderAndFocus(self.HandleToggleSelectRange),
Description: self.c.Tr.ToggleDragSelect,
}, },
{ {
Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk), Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk),

View File

@ -85,7 +85,7 @@ func (self *FileTreeViewModel) SetTree() {
} }
} }
self.RefreshSelectedIdx() self.ClampSelection()
} }
// Let's try to find our file again and move the cursor to that. // Let's try to find our file again and move the cursor to that.

View File

@ -13,66 +13,68 @@ import (
) )
var labelByKey = map[gocui.Key]string{ var labelByKey = map[gocui.Key]string{
gocui.KeyF1: "<f1>", gocui.KeyF1: "<f1>",
gocui.KeyF2: "<f2>", gocui.KeyF2: "<f2>",
gocui.KeyF3: "<f3>", gocui.KeyF3: "<f3>",
gocui.KeyF4: "<f4>", gocui.KeyF4: "<f4>",
gocui.KeyF5: "<f5>", gocui.KeyF5: "<f5>",
gocui.KeyF6: "<f6>", gocui.KeyF6: "<f6>",
gocui.KeyF7: "<f7>", gocui.KeyF7: "<f7>",
gocui.KeyF8: "<f8>", gocui.KeyF8: "<f8>",
gocui.KeyF9: "<f9>", gocui.KeyF9: "<f9>",
gocui.KeyF10: "<f10>", gocui.KeyF10: "<f10>",
gocui.KeyF11: "<f11>", gocui.KeyF11: "<f11>",
gocui.KeyF12: "<f12>", gocui.KeyF12: "<f12>",
gocui.KeyInsert: "<insert>", gocui.KeyInsert: "<insert>",
gocui.KeyDelete: "<delete>", gocui.KeyDelete: "<delete>",
gocui.KeyHome: "<home>", gocui.KeyHome: "<home>",
gocui.KeyEnd: "<end>", gocui.KeyEnd: "<end>",
gocui.KeyPgup: "<pgup>", gocui.KeyPgup: "<pgup>",
gocui.KeyPgdn: "<pgdown>", gocui.KeyPgdn: "<pgdown>",
gocui.KeyArrowUp: "<up>", gocui.KeyArrowUp: "<up>",
gocui.KeyArrowDown: "<down>", gocui.KeyShiftArrowUp: "<s-up>",
gocui.KeyArrowLeft: "<left>", gocui.KeyArrowDown: "<down>",
gocui.KeyArrowRight: "<right>", gocui.KeyShiftArrowDown: "<s-down>",
gocui.KeyTab: "<tab>", // <c-i> gocui.KeyArrowLeft: "<left>",
gocui.KeyBacktab: "<backtab>", gocui.KeyArrowRight: "<right>",
gocui.KeyEnter: "<enter>", // <c-m> gocui.KeyTab: "<tab>", // <c-i>
gocui.KeyAltEnter: "<a-enter>", gocui.KeyBacktab: "<backtab>",
gocui.KeyEsc: "<esc>", // <c-[>, <c-3> gocui.KeyEnter: "<enter>", // <c-m>
gocui.KeyBackspace: "<backspace>", // <c-h> gocui.KeyAltEnter: "<a-enter>",
gocui.KeyCtrlSpace: "<c-space>", // <c-~>, <c-2> gocui.KeyEsc: "<esc>", // <c-[>, <c-3>
gocui.KeyCtrlSlash: "<c-/>", // <c-_> gocui.KeyBackspace: "<backspace>", // <c-h>
gocui.KeySpace: "<space>", gocui.KeyCtrlSpace: "<c-space>", // <c-~>, <c-2>
gocui.KeyCtrlA: "<c-a>", gocui.KeyCtrlSlash: "<c-/>", // <c-_>
gocui.KeyCtrlB: "<c-b>", gocui.KeySpace: "<space>",
gocui.KeyCtrlC: "<c-c>", gocui.KeyCtrlA: "<c-a>",
gocui.KeyCtrlD: "<c-d>", gocui.KeyCtrlB: "<c-b>",
gocui.KeyCtrlE: "<c-e>", gocui.KeyCtrlC: "<c-c>",
gocui.KeyCtrlF: "<c-f>", gocui.KeyCtrlD: "<c-d>",
gocui.KeyCtrlG: "<c-g>", gocui.KeyCtrlE: "<c-e>",
gocui.KeyCtrlJ: "<c-j>", gocui.KeyCtrlF: "<c-f>",
gocui.KeyCtrlK: "<c-k>", gocui.KeyCtrlG: "<c-g>",
gocui.KeyCtrlL: "<c-l>", gocui.KeyCtrlJ: "<c-j>",
gocui.KeyCtrlN: "<c-n>", gocui.KeyCtrlK: "<c-k>",
gocui.KeyCtrlO: "<c-o>", gocui.KeyCtrlL: "<c-l>",
gocui.KeyCtrlP: "<c-p>", gocui.KeyCtrlN: "<c-n>",
gocui.KeyCtrlQ: "<c-q>", gocui.KeyCtrlO: "<c-o>",
gocui.KeyCtrlR: "<c-r>", gocui.KeyCtrlP: "<c-p>",
gocui.KeyCtrlS: "<c-s>", gocui.KeyCtrlQ: "<c-q>",
gocui.KeyCtrlT: "<c-t>", gocui.KeyCtrlR: "<c-r>",
gocui.KeyCtrlU: "<c-u>", gocui.KeyCtrlS: "<c-s>",
gocui.KeyCtrlV: "<c-v>", gocui.KeyCtrlT: "<c-t>",
gocui.KeyCtrlW: "<c-w>", gocui.KeyCtrlU: "<c-u>",
gocui.KeyCtrlX: "<c-x>", gocui.KeyCtrlV: "<c-v>",
gocui.KeyCtrlY: "<c-y>", gocui.KeyCtrlW: "<c-w>",
gocui.KeyCtrlZ: "<c-z>", gocui.KeyCtrlX: "<c-x>",
gocui.KeyCtrl4: "<c-4>", // <c-\> gocui.KeyCtrlY: "<c-y>",
gocui.KeyCtrl5: "<c-5>", // <c-]> gocui.KeyCtrlZ: "<c-z>",
gocui.KeyCtrl6: "<c-6>", gocui.KeyCtrl4: "<c-4>", // <c-\>
gocui.KeyCtrl8: "<c-8>", gocui.KeyCtrl5: "<c-5>", // <c-]>
gocui.MouseWheelUp: "mouse wheel up", gocui.KeyCtrl6: "<c-6>",
gocui.MouseWheelDown: "mouse wheel down", gocui.KeyCtrl8: "<c-8>",
gocui.MouseWheelUp: "mouse wheel up",
gocui.MouseWheelDown: "mouse wheel down",
} }
var keyByLabel = lo.Invert(labelByKey) var keyByLabel = lo.Invert(labelByKey)

View File

@ -163,6 +163,8 @@ type IPatchExplorerContext interface {
type IViewTrait interface { type IViewTrait interface {
FocusPoint(yIdx int) FocusPoint(yIdx int)
SetRangeSelectStart(yIdx int)
CancelRangeSelect()
SetViewPortContent(content string) SetViewPortContent(content string)
SetContent(content string) SetContent(content string)
SetFooter(value string) SetFooter(value string)
@ -223,7 +225,13 @@ type IListCursor interface {
GetSelectedLineIdx() int GetSelectedLineIdx() int
SetSelectedLineIdx(value int) SetSelectedLineIdx(value int)
MoveSelectedLine(delta int) MoveSelectedLine(delta int)
RefreshSelectedIdx() ClampSelection()
CancelRangeSelect()
GetRangeStartIdx() (int, bool)
GetSelectionRange() (int, int)
IsSelectingRange() bool
ToggleStickyRange()
ExpandNonStickyRange(int)
} }
type IListPanelState interface { type IListPanelState interface {

View File

@ -163,7 +163,7 @@ func chineseTranslationSet() TranslationSet {
FileStagingRequirements: `只能暂存跟踪文件的单独行`, FileStagingRequirements: `只能暂存跟踪文件的单独行`,
StageSelection: `切换行暂存状态`, StageSelection: `切换行暂存状态`,
DiscardSelection: `取消变更 (git reset)`, DiscardSelection: `取消变更 (git reset)`,
ToggleDragSelect: `切换拖动选择`, ToggleRangeSelect: `切换拖动选择`,
ToggleSelectHunk: `切换选择区块`, ToggleSelectHunk: `切换选择区块`,
ToggleSelectionForPatch: `添加/移除 行到补丁`, ToggleSelectionForPatch: `添加/移除 行到补丁`,
ToggleStagingPanel: `切换到其他面板`, ToggleStagingPanel: `切换到其他面板`,

View File

@ -128,7 +128,7 @@ func dutchTranslationSet() TranslationSet {
FileStagingRequirements: `Kan alleen individuele lijnen stagen van getrackte bestanden met onstaged veranderingen`, FileStagingRequirements: `Kan alleen individuele lijnen stagen van getrackte bestanden met onstaged veranderingen`,
StageSelection: `Toggle lijnen staged / unstaged`, StageSelection: `Toggle lijnen staged / unstaged`,
DiscardSelection: `Verwijdert change (git reset)`, DiscardSelection: `Verwijdert change (git reset)`,
ToggleDragSelect: `Toggle drag selecteer`, ToggleRangeSelect: `Toggle drag selecteer`,
ToggleSelectHunk: `Toggle selecteer hunk`, ToggleSelectHunk: `Toggle selecteer hunk`,
ToggleSelectionForPatch: `Voeg toe/verwijder lijn(en) in patch`, ToggleSelectionForPatch: `Voeg toe/verwijder lijn(en) in patch`,
ToggleStagingPanel: `Ga naar een ander paneel`, ToggleStagingPanel: `Ga naar een ander paneel`,

View File

@ -200,7 +200,6 @@ type TranslationSet struct {
FileStagingRequirements string FileStagingRequirements string
StageSelection string StageSelection string
DiscardSelection string DiscardSelection string
ToggleDragSelect string
ToggleSelectHunk string ToggleSelectHunk string
ToggleSelectionForPatch string ToggleSelectionForPatch string
EditHunk string EditHunk string
@ -651,6 +650,9 @@ type TranslationSet struct {
QuickStartInteractiveRebase string QuickStartInteractiveRebase string
QuickStartInteractiveRebaseTooltip string QuickStartInteractiveRebaseTooltip string
CannotQuickStartInteractiveRebase string CannotQuickStartInteractiveRebase string
ToggleRangeSelect string
RangeSelectUp string
RangeSelectDown string
Actions Actions Actions Actions
Bisect Bisect Bisect Bisect
Log Log Log Log
@ -1033,7 +1035,7 @@ func EnglishTranslationSet() TranslationSet {
FileStagingRequirements: `Can only stage individual lines for tracked files`, FileStagingRequirements: `Can only stage individual lines for tracked files`,
StageSelection: `Toggle line staged / unstaged`, StageSelection: `Toggle line staged / unstaged`,
DiscardSelection: `Discard change (git reset)`, DiscardSelection: `Discard change (git reset)`,
ToggleDragSelect: `Toggle drag select`, ToggleRangeSelect: `Toggle range select`,
ToggleSelectHunk: `Toggle select hunk`, ToggleSelectHunk: `Toggle select hunk`,
ToggleSelectionForPatch: `Add/Remove line(s) to patch`, ToggleSelectionForPatch: `Add/Remove line(s) to patch`,
EditHunk: `Edit hunk`, EditHunk: `Edit hunk`,
@ -1483,6 +1485,8 @@ func EnglishTranslationSet() TranslationSet {
QuickStartInteractiveRebase: "Start interactive rebase", QuickStartInteractiveRebase: "Start interactive rebase",
QuickStartInteractiveRebaseTooltip: "Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.\nIf you would instead like to start an interactive rebase from the selected commit, press `{{.editKey}}`.", QuickStartInteractiveRebaseTooltip: "Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.\nIf you would instead like to start an interactive rebase from the selected commit, press `{{.editKey}}`.",
CannotQuickStartInteractiveRebase: "Cannot start interactive rebase: the HEAD commit is a merge commit or is present on the main branch, so there is no appropriate base commit to start the rebase from. You can start an interactive rebase from a specific commit by selecting the commit and pressing `{{.editKey}}`.", CannotQuickStartInteractiveRebase: "Cannot start interactive rebase: the HEAD commit is a merge commit or is present on the main branch, so there is no appropriate base commit to start the rebase from. You can start an interactive rebase from a specific commit by selecting the commit and pressing `{{.editKey}}`.",
RangeSelectUp: "Range select up",
RangeSelectDown: "Range select down",
Actions: Actions{ Actions: Actions{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
CheckoutCommit: "Checkout commit", CheckoutCommit: "Checkout commit",

View File

@ -162,7 +162,7 @@ func japaneseTranslationSet() TranslationSet {
// FileStagingRequirements: `Can only stage individual lines for tracked files`, // FileStagingRequirements: `Can only stage individual lines for tracked files`,
StageSelection: `選択行をステージ/アンステージ`, StageSelection: `選択行をステージ/アンステージ`,
DiscardSelection: `変更を削除 (git reset)`, DiscardSelection: `変更を削除 (git reset)`,
ToggleDragSelect: `範囲選択を切り替え`, ToggleRangeSelect: `範囲選択を切り替え`,
ToggleSelectHunk: `Hunk選択を切り替え`, ToggleSelectHunk: `Hunk選択を切り替え`,
ToggleSelectionForPatch: `行をパッチに追加/削除`, ToggleSelectionForPatch: `行をパッチに追加/削除`,
ToggleStagingPanel: `パネルを切り替え`, ToggleStagingPanel: `パネルを切り替え`,

View File

@ -164,7 +164,7 @@ func koreanTranslationSet() TranslationSet {
FileStagingRequirements: `추적된 파일에 대해 개별 라인만 stage할 수 있습니다.`, FileStagingRequirements: `추적된 파일에 대해 개별 라인만 stage할 수 있습니다.`,
StageSelection: `선택한 행을 staged / unstaged`, StageSelection: `선택한 행을 staged / unstaged`,
DiscardSelection: `변경을 삭제 (git reset)`, DiscardSelection: `변경을 삭제 (git reset)`,
ToggleDragSelect: `드래그 선택 전환`, ToggleRangeSelect: `드래그 선택 전환`,
ToggleSelectHunk: `Toggle select hunk`, ToggleSelectHunk: `Toggle select hunk`,
ToggleSelectionForPatch: `Line(s)을 패치에 추가/삭제`, ToggleSelectionForPatch: `Line(s)을 패치에 추가/삭제`,
ToggleStagingPanel: `패널 전환`, ToggleStagingPanel: `패널 전환`,

View File

@ -194,7 +194,7 @@ func RussianTranslationSet() TranslationSet {
FileStagingRequirements: `Можно проиндексировать только отдельные строки для отслеживаемых файлов`, FileStagingRequirements: `Можно проиндексировать только отдельные строки для отслеживаемых файлов`,
StageSelection: `Переключить строку в проиндексированные / непроиндексированные`, StageSelection: `Переключить строку в проиндексированные / непроиндексированные`,
DiscardSelection: `Отменить изменение (git reset)`, DiscardSelection: `Отменить изменение (git reset)`,
ToggleDragSelect: `Переключить выборку перетаскивания`, ToggleRangeSelect: `Переключить выборку перетаскивания`,
ToggleSelectHunk: `Переключить выборку частей`, ToggleSelectHunk: `Переключить выборку частей`,
ToggleSelectionForPatch: `Добавить/удалить строку(и) для патча`, ToggleSelectionForPatch: `Добавить/удалить строку(и) для патча`,
EditHunk: `Изменить эту часть`, EditHunk: `Изменить эту часть`,

View File

@ -227,7 +227,7 @@ func traditionalChineseTranslationSet() TranslationSet {
FileStagingRequirements: `只能選擇跟踪檔案中的單個行`, FileStagingRequirements: `只能選擇跟踪檔案中的單個行`,
StageSelection: `切換現有行的狀態 (已預存/未預存)`, StageSelection: `切換現有行的狀態 (已預存/未預存)`,
DiscardSelection: `刪除變更 (git reset)`, DiscardSelection: `刪除變更 (git reset)`,
ToggleDragSelect: `切換拖曳選擇`, ToggleRangeSelect: `切換拖曳選擇`,
ToggleSelectHunk: `切換選擇程式碼塊`, ToggleSelectHunk: `切換選擇程式碼塊`,
ToggleSelectionForPatch: `向 (或從) 補丁中添加/刪除行`, ToggleSelectionForPatch: `向 (或從) 補丁中添加/刪除行`,
EditHunk: `編輯程式碼塊`, EditHunk: `編輯程式碼塊`,

View File

@ -25,7 +25,7 @@ var StageRangeOfLines = NewIntegrationTest(NewIntegrationTestArgs{
Contains("-1st\n-2nd\n+1st changed\n+2nd changed\n 3rd\n 4th\n-5th\n+5th changed\n 6th"), Contains("-1st\n-2nd\n+1st changed\n+2nd changed\n 3rd\n 4th\n-5th\n+5th changed\n 6th"),
). ).
SelectedLine(Equals("-1st")). SelectedLine(Equals("-1st")).
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
SelectNextItem(). SelectNextItem().
SelectNextItem(). SelectNextItem().
SelectNextItem(). SelectNextItem().

View File

@ -60,7 +60,7 @@ var StageLines = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Staging(). t.Views().Staging().
IsFocused(). IsFocused().
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
PressFast(keys.Universal.NextItem). PressFast(keys.Universal.NextItem).
PressFast(keys.Universal.NextItem). PressFast(keys.Universal.NextItem).
Wait(500). Wait(500).

View File

@ -107,7 +107,7 @@ var SpecificSelection = NewIntegrationTest(NewIntegrationTestArgs{
). ).
PressPrimaryAction(). PressPrimaryAction().
NavigateToLine(Contains("+2c")). NavigateToLine(Contains("+2c")).
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("+2e")). NavigateToLine(Contains("+2e")).
PressPrimaryAction(). PressPrimaryAction().
NavigateToLine(Contains("+2g")). NavigateToLine(Contains("+2g")).

View File

@ -29,7 +29,7 @@ var StageRanges = NewIntegrationTest(NewIntegrationTestArgs{
SelectedLines( SelectedLines(
Contains("+three"), Contains("+three"),
). ).
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("+five")). NavigateToLine(Contains("+five")).
SelectedLines( SelectedLines(
Contains("+three"), Contains("+three"),
@ -60,7 +60,7 @@ var StageRanges = NewIntegrationTest(NewIntegrationTestArgs{
SelectedLines( SelectedLines(
Contains("+three"), Contains("+three"),
). ).
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("+five")). NavigateToLine(Contains("+five")).
SelectedLines( SelectedLines(
Contains("+three"), Contains("+three"),
@ -88,7 +88,7 @@ var StageRanges = NewIntegrationTest(NewIntegrationTestArgs{
SelectedLines( SelectedLines(
Contains("+four"), Contains("+four"),
). ).
Press(keys.Main.ToggleDragSelect). Press(keys.Universal.ToggleRangeSelect).
SelectNextItem(). SelectNextItem().
SelectedLines( SelectedLines(
Contains("+four"), Contains("+four"),

View File

@ -50,6 +50,13 @@ func Max(x, y int) int {
return y return y
} }
func MinMax(x int, y int) (int, int) {
if x < y {
return x, y
}
return y, x
}
func Clamp(x int, min int, max int) int { func Clamp(x int, min int, max int) int {
if x < min { if x < min {
return min return min

View File

@ -1178,14 +1178,6 @@
}, },
"main": { "main": {
"properties": { "properties": {
"toggleDragSelect": {
"type": "string",
"default": "v"
},
"toggleDragSelect-alt": {
"type": "string",
"default": "V"
},
"toggleSelectHunk": { "toggleSelectHunk": {
"type": "string", "type": "string",
"default": "a" "default": "a"
@ -1523,4 +1515,4 @@
}, },
"additionalProperties": false, "additionalProperties": false,
"type": "object" "type": "object"
} }

View File

@ -143,7 +143,9 @@ var translate = map[string]Key{
"Pgup": KeyPgup, "Pgup": KeyPgup,
"Pgdn": KeyPgdn, "Pgdn": KeyPgdn,
"ArrowUp": KeyArrowUp, "ArrowUp": KeyArrowUp,
"ShiftArrowUp": KeyShiftArrowUp,
"ArrowDown": KeyArrowDown, "ArrowDown": KeyArrowDown,
"ShiftArrowDown": KeyShiftArrowDown,
"ArrowLeft": KeyArrowLeft, "ArrowLeft": KeyArrowLeft,
"ArrowRight": KeyArrowRight, "ArrowRight": KeyArrowRight,
"CtrlTilde": KeyCtrlTilde, "CtrlTilde": KeyCtrlTilde,
@ -203,28 +205,30 @@ var translate = map[string]Key{
// Special keys. // Special keys.
const ( const (
KeyF1 Key = Key(tcell.KeyF1) KeyF1 Key = Key(tcell.KeyF1)
KeyF2 = Key(tcell.KeyF2) KeyF2 = Key(tcell.KeyF2)
KeyF3 = Key(tcell.KeyF3) KeyF3 = Key(tcell.KeyF3)
KeyF4 = Key(tcell.KeyF4) KeyF4 = Key(tcell.KeyF4)
KeyF5 = Key(tcell.KeyF5) KeyF5 = Key(tcell.KeyF5)
KeyF6 = Key(tcell.KeyF6) KeyF6 = Key(tcell.KeyF6)
KeyF7 = Key(tcell.KeyF7) KeyF7 = Key(tcell.KeyF7)
KeyF8 = Key(tcell.KeyF8) KeyF8 = Key(tcell.KeyF8)
KeyF9 = Key(tcell.KeyF9) KeyF9 = Key(tcell.KeyF9)
KeyF10 = Key(tcell.KeyF10) KeyF10 = Key(tcell.KeyF10)
KeyF11 = Key(tcell.KeyF11) KeyF11 = Key(tcell.KeyF11)
KeyF12 = Key(tcell.KeyF12) KeyF12 = Key(tcell.KeyF12)
KeyInsert = Key(tcell.KeyInsert) KeyInsert = Key(tcell.KeyInsert)
KeyDelete = Key(tcell.KeyDelete) KeyDelete = Key(tcell.KeyDelete)
KeyHome = Key(tcell.KeyHome) KeyHome = Key(tcell.KeyHome)
KeyEnd = Key(tcell.KeyEnd) KeyEnd = Key(tcell.KeyEnd)
KeyPgdn = Key(tcell.KeyPgDn) KeyPgdn = Key(tcell.KeyPgDn)
KeyPgup = Key(tcell.KeyPgUp) KeyPgup = Key(tcell.KeyPgUp)
KeyArrowUp = Key(tcell.KeyUp) KeyArrowUp = Key(tcell.KeyUp)
KeyArrowDown = Key(tcell.KeyDown) KeyShiftArrowUp = Key(tcell.KeyF62)
KeyArrowLeft = Key(tcell.KeyLeft) KeyArrowDown = Key(tcell.KeyDown)
KeyArrowRight = Key(tcell.KeyRight) KeyShiftArrowDown = Key(tcell.KeyF63)
KeyArrowLeft = Key(tcell.KeyLeft)
KeyArrowRight = Key(tcell.KeyRight)
) )
// Keys combinations. // Keys combinations.

View File

@ -300,6 +300,14 @@ func (g *Gui) pollEvent() GocuiEvent {
mod = 0 mod = 0
ch = rune(0) ch = rune(0)
k = tcell.KeyCtrlSpace k = tcell.KeyCtrlSpace
} else if mod == tcell.ModShift && k == tcell.KeyUp {
mod = 0
ch = rune(0)
k = tcell.KeyF62
} else if mod == tcell.ModShift && k == tcell.KeyDown {
mod = 0
ch = rune(0)
k = tcell.KeyF63
} else if mod == tcell.ModCtrl || mod == tcell.ModShift { } else if mod == tcell.ModCtrl || mod == tcell.ModShift {
// remove Ctrl or Shift if specified // remove Ctrl or Shift if specified
// - shift - will be translated to the final code of rune // - shift - will be translated to the final code of rune

View File

@ -41,6 +41,14 @@ type View struct {
wx, wy int // Write() offsets wx, wy int // Write() offsets
lines [][]cell // All the data lines [][]cell // All the data
outMode OutputMode outMode OutputMode
// The y position of the first line of a range selection.
// This is not relative to the view's origin: it is relative to the first line
// of the view's content, so you can scroll the view and this value will remain
// the same, unlike the view's cy value.
// A value of -1 means that there is no range selection.
// This value can be greater than the selected line index, in the event that
// a user starts a range select and then moves the cursor up.
rangeSelectStartY int
// readBuffer is used for storing unread bytes // readBuffer is used for storing unread bytes
readBuffer []byte readBuffer []byte
@ -284,6 +292,14 @@ func (v *View) FocusPoint(cx int, cy int) {
v.cy = cy - v.oy v.cy = cy - v.oy
} }
func (v *View) SetRangeSelectStart(rangeSelectStartY int) {
v.rangeSelectStartY = rangeSelectStartY
}
func (v *View) CancelRangeSelect() {
v.rangeSelectStartY = -1
}
func calculateNewOrigin(selectedLine int, oldOrigin int, lineCount int, viewHeight int) int { func calculateNewOrigin(selectedLine int, oldOrigin int, lineCount int, viewHeight int) int {
if viewHeight > lineCount { if viewHeight > lineCount {
return 0 return 0
@ -349,19 +365,20 @@ func (l lineType) String() string {
// newView returns a new View object. // newView returns a new View object.
func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View { func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
v := &View{ v := &View{
name: name, name: name,
x0: x0, x0: x0,
y0: y0, y0: y0,
x1: x1, x1: x1,
y1: y1, y1: y1,
Visible: true, Visible: true,
Frame: true, Frame: true,
Editor: DefaultEditor, Editor: DefaultEditor,
tainted: true, tainted: true,
outMode: mode, outMode: mode,
ei: newEscapeInterpreter(mode), ei: newEscapeInterpreter(mode),
searcher: &searcher{}, searcher: &searcher{},
TextArea: &TextArea{}, TextArea: &TextArea{},
rangeSelectStartY: -1,
} }
v.FgColor, v.BgColor = ColorDefault, ColorDefault v.FgColor, v.BgColor = ColorDefault, ColorDefault
@ -428,11 +445,17 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
if x < 0 || x >= maxX || y < 0 || y >= maxY { if x < 0 || x >= maxX || y < 0 || y >= maxY {
return ErrInvalidPoint return ErrInvalidPoint
} }
var (
ry, rcy int if v.Mask != 0 {
err error fgColor = v.FgColor
) bgColor = v.BgColor
if v.Highlight { ch = v.Mask
} else if v.Highlight {
var (
ry, rcy int
err error
)
_, ry, err = v.realPosition(x, y) _, ry, err = v.realPosition(x, y)
if err != nil { if err != nil {
return err return err
@ -442,20 +465,28 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
if err == nil { if err == nil {
rcy = rrcy rcy = rrcy
} }
}
if v.Mask != 0 { rangeSelectStart := rcy
fgColor = v.FgColor rangeSelectEnd := rcy
bgColor = v.BgColor if v.rangeSelectStartY != -1 {
ch = v.Mask _, realRangeSelectStart, err := v.realPosition(0, v.rangeSelectStartY-v.oy)
} else if v.Highlight && ry == rcy { if err != nil {
// this ensures we use the bright variant of a colour upon highlight return err
fgColorComponent := fgColor & ^AttrAll }
if fgColorComponent >= AttrIsValidColor && fgColorComponent < AttrIsValidColor+8 {
fgColor += 8 rangeSelectStart = min(realRangeSelectStart, rcy)
rangeSelectEnd = max(realRangeSelectStart, rcy)
}
if ry >= rangeSelectStart && ry <= rangeSelectEnd {
// this ensures we use the bright variant of a colour upon highlight
fgColorComponent := fgColor & ^AttrAll
if fgColorComponent >= AttrIsValidColor && fgColorComponent < AttrIsValidColor+8 {
fgColor += 8
}
fgColor = fgColor | AttrBold
bgColor = bgColor | v.SelBgColor
} }
fgColor = fgColor | AttrBold
bgColor = bgColor | v.SelBgColor
} }
// Don't display NUL characters // Don't display NUL characters
@ -468,6 +499,20 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
return nil return nil
} }
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// SetCursor sets the cursor position of the view at the given point, // SetCursor sets the cursor position of the view at the given point,
// relative to the view. It checks if the position is valid. // relative to the view. It checks if the position is valid.
func (v *View) SetCursor(x, y int) error { func (v *View) SetCursor(x, y int) error {
@ -1388,7 +1433,31 @@ func (v *View) SelectedLine() string {
if len(v.lines) == 0 { if len(v.lines) == 0 {
return "" return ""
} }
line := v.lines[v.SelectedLineIdx()]
return v.lineContentAtIdx(v.SelectedLineIdx())
}
// expected to only be used in tests
func (v *View) SelectedLines() []string {
v.writeMutex.Lock()
defer v.writeMutex.Unlock()
if len(v.lines) == 0 {
return nil
}
startIdx, endIdx := v.SelectedLineRange()
lines := make([]string, 0, endIdx-startIdx+1)
for i := startIdx; i <= endIdx; i++ {
lines = append(lines, v.lineContentAtIdx(i))
}
return lines
}
func (v *View) lineContentAtIdx(idx int) string {
line := v.lines[idx]
str := lineType(line).String() str := lineType(line).String()
return strings.Replace(str, "\x00", "", -1) return strings.Replace(str, "\x00", "", -1)
} }
@ -1399,6 +1468,25 @@ func (v *View) SelectedPoint() (int, int) {
return cx + ox, cy + oy return cx + ox, cy + oy
} }
func (v *View) SelectedLineRange() (int, int) {
_, cy := v.Cursor()
_, oy := v.Origin()
start := cy + oy
if v.rangeSelectStartY == -1 {
return start, start
}
end := v.rangeSelectStartY
if start > end {
return end, start
} else {
return start, end
}
}
func (v *View) RenderTextArea() { func (v *View) RenderTextArea() {
v.Clear() v.Clear()
fmt.Fprint(v, v.TextArea.GetContent()) fmt.Fprint(v, v.TextArea.GetContent())

View File

@ -248,6 +248,7 @@ struct ltchars {
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/net_namespace.h> #include <linux/net_namespace.h>
#include <linux/nfc.h> #include <linux/nfc.h>
@ -283,10 +284,6 @@ struct ltchars {
#include <asm/termbits.h> #include <asm/termbits.h>
#endif #endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#ifndef PTRACE_GETREGS #ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc #define PTRACE_GETREGS 0xc
#endif #endif
@ -295,14 +292,6 @@ struct ltchars {
#define PTRACE_SETREGS 0xd #define PTRACE_SETREGS 0xd
#endif #endif
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef SOL_SMC
#define SOL_SMC 286
#endif
#ifdef SOL_BLUETOOTH #ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go // but it is already in bluetooth_linux.go
@ -319,10 +308,23 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER #undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff #define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/l2tp.h // Copied from linux/netfilter/nf_nat.h
// Including linux/l2tp.h here causes conflicts between linux/in.h // Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above. // and netinet/in.h.
#define IPPROTO_L2TP 115 #define NF_NAT_RANGE_MAP_IPS (1 << 0)
#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h. // Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields. // Keep in sync with the size of the referenced fields.
@ -603,6 +605,9 @@ ccflags="$@"
$2 ~ /^FSOPT_/ || $2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ || $2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ || $2 ~ /^NFN/ ||
$2 !~ /^NFT_META_IIFTYPE/ &&
$2 ~ /^NFT_/ ||
$2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ || $2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ || $2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ || $2 ~ /^(HDIO|WIN|SMART)_/ ||

View File

@ -2127,6 +2127,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4 NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969 NFS_SUPER_MAGIC = 0x6969
NFT_CHAIN_FLAGS = 0x7
NFT_CHAIN_MAXNAMELEN = 0x100
NFT_CT_MAX = 0x17
NFT_DATA_RESERVED_MASK = 0xffffff00
NFT_DATA_VALUE_MAXLEN = 0x40
NFT_EXTHDR_OP_MAX = 0x4
NFT_FIB_RESULT_MAX = 0x3
NFT_INNER_MASK = 0xf
NFT_LOGLEVEL_MAX = 0x8
NFT_NAME_MAXLEN = 0x100
NFT_NG_MAX = 0x1
NFT_OBJECT_CONNLIMIT = 0x5
NFT_OBJECT_COUNTER = 0x1
NFT_OBJECT_CT_EXPECT = 0x9
NFT_OBJECT_CT_HELPER = 0x3
NFT_OBJECT_CT_TIMEOUT = 0x7
NFT_OBJECT_LIMIT = 0x4
NFT_OBJECT_MAX = 0xa
NFT_OBJECT_QUOTA = 0x2
NFT_OBJECT_SECMARK = 0x8
NFT_OBJECT_SYNPROXY = 0xa
NFT_OBJECT_TUNNEL = 0x6
NFT_OBJECT_UNSPEC = 0x0
NFT_OBJ_MAXNAMELEN = 0x100
NFT_OSF_MAXGENRELEN = 0x10
NFT_QUEUE_FLAG_BYPASS = 0x1
NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
NFT_QUEUE_FLAG_MASK = 0x3
NFT_REG32_COUNT = 0x10
NFT_REG32_SIZE = 0x4
NFT_REG_MAX = 0x4
NFT_REG_SIZE = 0x10
NFT_REJECT_ICMPX_MAX = 0x3
NFT_RT_MAX = 0x4
NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x3
NFT_TABLE_MAXNAMELEN = 0x100
NFT_TRACETYPE_MAX = 0x3
NFT_TUNNEL_F_MASK = 0x7
NFT_TUNNEL_MAX = 0x1
NFT_TUNNEL_MODE_MAX = 0x2
NFT_USERDATA_MAXLEN = 0x100
NFT_XFRM_KEY_MAX = 0x6
NF_NAT_RANGE_MAP_IPS = 0x1
NF_NAT_RANGE_MASK = 0x7f
NF_NAT_RANGE_NETMAP = 0x40
NF_NAT_RANGE_PERSISTENT = 0x8
NF_NAT_RANGE_PROTO_OFFSET = 0x20
NF_NAT_RANGE_PROTO_RANDOM = 0x4
NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434 NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0 NL0 = 0x0
NL1 = 0x100 NL1 = 0x100

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -194,6 +194,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error) //sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]

View File

@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent") procSetEvent = modkernel32.NewProc("SetEvent")
@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
return return
} }
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 { if r1 == 0 {

6
vendor/modules.txt vendored
View File

@ -173,7 +173,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
# github.com/jesseduffield/gocui v0.3.1-0.20240103192639-2874168c14db # github.com/jesseduffield/gocui v0.3.1-0.20240118234343-2d41754af383
## explicit; go 1.12 ## explicit; go 1.12
github.com/jesseduffield/gocui github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
@ -314,13 +314,13 @@ golang.org/x/exp/slices
golang.org/x/net/context golang.org/x/net/context
golang.org/x/net/internal/socks golang.org/x/net/internal/socks
golang.org/x/net/proxy golang.org/x/net/proxy
# golang.org/x/sys v0.15.0 # golang.org/x/sys v0.16.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sys/cpu golang.org/x/sys/cpu
golang.org/x/sys/plan9 golang.org/x/sys/plan9
golang.org/x/sys/unix golang.org/x/sys/unix
golang.org/x/sys/windows golang.org/x/sys/windows
# golang.org/x/term v0.15.0 # golang.org/x/term v0.16.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/term golang.org/x/term
# golang.org/x/text v0.14.0 # golang.org/x/text v0.14.0