1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-09 13:47:11 +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>'
increaseContextInDiffView: '}'
decreaseContextInDiffView: '{'
toggleRangeSelect: 'v'
rangeSelectUp: '<s-up>'
rangeSelectDown: '<s-down>'
status:
checkForUpdate: 'u'
recentRepos: '<enter>'
@ -263,8 +266,6 @@ keybinding:
commitFiles:
checkoutCommitFile: 'c'
main:
toggleDragSelect: 'v'
toggleDragSelect-alt: 'V'
toggleSelectHunk: 'a'
pickBothHunks: 'b'
submodules:

View File

@ -3,8 +3,9 @@
* [Configuration](./Config.md).
* [Custom Commands](./Custom_Command_Keybindings.md)
* [Custom Pagers](./Custom_Pagers.md)
* [Dev docs](./dev)
* [Keybindings](./keybindings)
* [Undo/Redo](./Undoing.md)
* [Range Select](./Range_Select.md)
* [Searching/Filtering](./Searching.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/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
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/lazycore v0.0.0-20221012050358-03d2e40243c5
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
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.14.0 // 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/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/gocui v0.3.1-0.20240103192639-2874168c14db h1:ihJdYk85/XQLGiG3b6m8P2z+RUohRMtPmX74YR9IT8s=
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 h1:twcgVo+K7UTXwrsNtlCvTi8AyCp7CuBX//+j4wWkivQ=
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/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
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-20220722155257-8c9f86f7a55f/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.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-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.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.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.3.0/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"`
GotoTop string `yaml:"gotoTop"`
GotoBottom string `yaml:"gotoBottom"`
ToggleRangeSelect string `yaml:"toggleRangeSelect"`
RangeSelectDown string `yaml:"rangeSelectDown"`
RangeSelectUp string `yaml:"rangeSelectUp"`
PrevBlock string `yaml:"prevBlock"`
NextBlock string `yaml:"nextBlock"`
PrevBlockAlt string `yaml:"prevBlock-alt"`
@ -441,11 +444,9 @@ type KeybindingCommitFilesConfig struct {
}
type KeybindingMainConfig struct {
ToggleDragSelect string `yaml:"toggleDragSelect"`
ToggleDragSelectAlt string `yaml:"toggleDragSelect-alt"`
ToggleSelectHunk string `yaml:"toggleSelectHunk"`
PickBothHunks string `yaml:"pickBothHunks"`
EditSelectHunk string `yaml:"editSelectHunk"`
ToggleSelectHunk string `yaml:"toggleSelectHunk"`
PickBothHunks string `yaml:"pickBothHunks"`
EditSelectHunk string `yaml:"editSelectHunk"`
}
type KeybindingSubmodulesConfig struct {
@ -704,6 +705,9 @@ func GetDefaultConfig() *UserConfig {
ScrollRight: "L",
GotoTop: "<",
GotoBottom: ">",
ToggleRangeSelect: "v",
RangeSelectDown: "<s-down>",
RangeSelectUp: "<s-up>",
PrevBlock: "<left>",
NextBlock: "<right>",
PrevBlockAlt: "h",
@ -833,11 +837,9 @@ func GetDefaultConfig() *UserConfig {
CheckoutCommitFile: "c",
},
Main: KeybindingMainConfig{
ToggleDragSelect: "v",
ToggleDragSelectAlt: "V",
ToggleSelectHunk: "a",
PickBothHunks: "b",
EditSelectHunk: "E",
ToggleSelectHunk: "a",
PickBothHunks: "b",
EditSelectHunk: "E",
},
Submodules: KeybindingSubmodulesConfig{
Init: "i",

View File

@ -32,6 +32,14 @@ func (self *ListContextTrait) FocusLine() {
self.GetViewTrait().FocusPoint(
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
// 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
@ -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
func (self *ListContextTrait) HandleRender() error {
self.list.RefreshSelectedIdx()
self.list.ClampSelection()
content := self.renderLines(-1, -1)
self.GetViewTrait().SetContent(content)
self.c.Render()

View File

@ -9,13 +9,34 @@ type HasLength interface {
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 {
selectedIdx int
list HasLength
selectedIdx int
rangeSelectMode RangeSelectMode
// value is ignored when rangeSelectMode is RangeSelectModeNone
rangeStartIdx int
list HasLength
}
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)
@ -25,24 +46,86 @@ func (self *ListCursor) GetSelectedLineIdx() int {
}
func (self *ListCursor) SetSelectedLineIdx(value int) {
self.selectedIdx = self.clampValue(value)
}
func (self *ListCursor) clampValue(value int) int {
clampedValue := -1
if self.list.Len() > 0 {
clampedValue = utils.Clamp(value, 0, self.list.Len()-1)
}
self.selectedIdx = clampedValue
return clampedValue
}
// moves the cursor up or down by the given amount
func (self *ListCursor) MoveSelectedLine(delta int) {
self.SetSelectedLineIdx(self.selectedIdx + delta)
// Moves the cursor up or down by the given amount.
// If we are in non-sticky range select mode, this will cancel the range select
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
func (self *ListCursor) RefreshSelectedIdx() {
self.SetSelectedLineIdx(self.selectedIdx)
// Moves the cursor up or down by the given amount, and also moves the range start
// index by the same amount
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 {
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)
}
func (self *ViewTrait) SetRangeSelectStart(yIdx int) {
self.view.SetRangeSelectStart(yIdx)
}
func (self *ViewTrait) CancelRangeSelect() {
self.view.CancelRangeSelect()
}
func (self *ViewTrait) SetViewPortContent(content string) {
_, y := self.view.Origin()
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 {
before := self.context.GetList().GetSelectedLineIdx()
self.context.GetList().MoveSelectedLine(change)
after := self.context.GetList().GetSelectedLineIdx()
return self.handleLineChangeAux(
self.context.GetList().MoveSelectedLine, change,
)
}
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 {
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
// we're not constantly re-rendering the main view.
if before != after {
cursorMoved := before != after
if cursorMoved {
if change == -1 {
checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig,
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,
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
}
}
if cursorMoved || rangeBefore != rangeAfter {
return self.context.HandleFocus(types.OnFocusOpts{})
}
@ -112,6 +131,22 @@ func (self *ListController) HandleGotoBottom() error {
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 {
prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx()
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.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.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),
},
{
Key: opts.GetKey(opts.Config.Main.ToggleDragSelect),
Key: opts.GetKey(opts.Config.Universal.ToggleRangeSelect),
Handler: self.withRenderAndFocus(self.HandleToggleSelectRange),
Description: self.c.Tr.ToggleDragSelect,
},
{
Key: opts.GetKey(opts.Config.Main.ToggleDragSelectAlt),
Handler: self.withRenderAndFocus(self.HandleToggleSelectRange),
Description: self.c.Tr.ToggleDragSelect,
Description: self.c.Tr.ToggleRangeSelect,
},
{
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.

View File

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

View File

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

View File

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

View File

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

View File

@ -200,7 +200,6 @@ type TranslationSet struct {
FileStagingRequirements string
StageSelection string
DiscardSelection string
ToggleDragSelect string
ToggleSelectHunk string
ToggleSelectionForPatch string
EditHunk string
@ -651,6 +650,9 @@ type TranslationSet struct {
QuickStartInteractiveRebase string
QuickStartInteractiveRebaseTooltip string
CannotQuickStartInteractiveRebase string
ToggleRangeSelect string
RangeSelectUp string
RangeSelectDown string
Actions Actions
Bisect Bisect
Log Log
@ -1033,7 +1035,7 @@ func EnglishTranslationSet() TranslationSet {
FileStagingRequirements: `Can only stage individual lines for tracked files`,
StageSelection: `Toggle line staged / unstaged`,
DiscardSelection: `Discard change (git reset)`,
ToggleDragSelect: `Toggle drag select`,
ToggleRangeSelect: `Toggle range select`,
ToggleSelectHunk: `Toggle select hunk`,
ToggleSelectionForPatch: `Add/Remove line(s) to patch`,
EditHunk: `Edit hunk`,
@ -1483,6 +1485,8 @@ func EnglishTranslationSet() TranslationSet {
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}}`.",
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{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
CheckoutCommit: "Checkout commit",

View File

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

View File

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

View File

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

View File

@ -227,7 +227,7 @@ func traditionalChineseTranslationSet() TranslationSet {
FileStagingRequirements: `只能選擇跟踪檔案中的單個行`,
StageSelection: `切換現有行的狀態 (已預存/未預存)`,
DiscardSelection: `刪除變更 (git reset)`,
ToggleDragSelect: `切換拖曳選擇`,
ToggleRangeSelect: `切換拖曳選擇`,
ToggleSelectHunk: `切換選擇程式碼塊`,
ToggleSelectionForPatch: `向 (或從) 補丁中添加/刪除行`,
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"),
).
SelectedLine(Equals("-1st")).
Press(keys.Main.ToggleDragSelect).
Press(keys.Universal.ToggleRangeSelect).
SelectNextItem().
SelectNextItem().
SelectNextItem().

View File

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

View File

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

View File

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

View File

@ -50,6 +50,13 @@ func Max(x, y int) int {
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 {
if x < min {
return min

View File

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

View File

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

View File

@ -300,6 +300,14 @@ func (g *Gui) pollEvent() GocuiEvent {
mod = 0
ch = rune(0)
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 {
// remove Ctrl or Shift if specified
// - shift - will be translated to the final code of rune

View File

@ -41,6 +41,14 @@ type View struct {
wx, wy int // Write() offsets
lines [][]cell // All the data
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 []byte
@ -284,6 +292,14 @@ func (v *View) FocusPoint(cx int, cy int) {
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 {
if viewHeight > lineCount {
return 0
@ -349,19 +365,20 @@ func (l lineType) String() string {
// newView returns a new View object.
func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
v := &View{
name: name,
x0: x0,
y0: y0,
x1: x1,
y1: y1,
Visible: true,
Frame: true,
Editor: DefaultEditor,
tainted: true,
outMode: mode,
ei: newEscapeInterpreter(mode),
searcher: &searcher{},
TextArea: &TextArea{},
name: name,
x0: x0,
y0: y0,
x1: x1,
y1: y1,
Visible: true,
Frame: true,
Editor: DefaultEditor,
tainted: true,
outMode: mode,
ei: newEscapeInterpreter(mode),
searcher: &searcher{},
TextArea: &TextArea{},
rangeSelectStartY: -1,
}
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 {
return ErrInvalidPoint
}
var (
ry, rcy int
err error
)
if v.Highlight {
if v.Mask != 0 {
fgColor = v.FgColor
bgColor = v.BgColor
ch = v.Mask
} else if v.Highlight {
var (
ry, rcy int
err error
)
_, ry, err = v.realPosition(x, y)
if err != nil {
return err
@ -442,20 +465,28 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
if err == nil {
rcy = rrcy
}
}
if v.Mask != 0 {
fgColor = v.FgColor
bgColor = v.BgColor
ch = v.Mask
} else if v.Highlight && ry == rcy {
// this ensures we use the bright variant of a colour upon highlight
fgColorComponent := fgColor & ^AttrAll
if fgColorComponent >= AttrIsValidColor && fgColorComponent < AttrIsValidColor+8 {
fgColor += 8
rangeSelectStart := rcy
rangeSelectEnd := rcy
if v.rangeSelectStartY != -1 {
_, realRangeSelectStart, err := v.realPosition(0, v.rangeSelectStartY-v.oy)
if err != nil {
return err
}
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
@ -468,6 +499,20 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
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,
// relative to the view. It checks if the position is valid.
func (v *View) SetCursor(x, y int) error {
@ -1388,7 +1433,31 @@ func (v *View) SelectedLine() string {
if len(v.lines) == 0 {
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()
return strings.Replace(str, "\x00", "", -1)
}
@ -1399,6 +1468,25 @@ func (v *View) SelectedPoint() (int, int) {
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() {
v.Clear()
fmt.Fprint(v, v.TextArea.GetContent())

View File

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

View File

@ -2127,6 +2127,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4
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
NL0 = 0x0
NL1 = 0x100

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr
//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
//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
//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
//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
//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
//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
//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 GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]

View File

@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent")
@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
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) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 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/internal/frame
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
github.com/jesseduffield/gocui
# 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/internal/socks
golang.org/x/net/proxy
# golang.org/x/sys v0.15.0
# golang.org/x/sys v0.16.0
## explicit; go 1.18
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/term v0.15.0
# golang.org/x/term v0.16.0
## explicit; go 1.18
golang.org/x/term
# golang.org/x/text v0.14.0