summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md5
-rw-r--r--man/man1/fzf.13
-rw-r--r--src/actiontype_string.go197
-rw-r--r--src/core.go10
-rw-r--r--src/options.go4
-rw-r--r--src/terminal.go23
-rwxr-xr-xtest/test_go.rb23
7 files changed, 163 insertions, 102 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e6e7cc4..3e30749b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -67,6 +67,11 @@ Also, fzf now offers "style presets" for quick customization, which can be activ
```
- Added `toggle-multi-line` action
- Added `toggle-hscroll` action
+- Added `change-nth` action for dynamically changing the value of the `--nth` option
+ ```sh
+ # Start with --nth 1, then 2, then 3, then back to the default, 1
+ echo 'foo foobar foobarbaz' | fzf --bind 'space:change-nth(2|3|)' --nth 1 -q foo
+ ```
- A single-character delimiter is now treated as a plain string delimiter rather than a regular expression delimiter, even if it's a regular expression meta-character.
- This means you can just write `--delimiter '|'` instead of escaping it as `--delimiter '\|'`
- Bug fixes
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index 8a5b3638..85cc28f9 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -496,7 +496,7 @@ the label. Label is printed on the top border line by default, add
.SS LIST SECTION
.TP
-.B "\-m, \-\-multi"
+.BI "\-m, \-\-multi" "[=MAX]"
Enable multi-select with tab/shift\-tab. It optionally takes an integer argument
which denotes the maximum number of items that can be selected.
.TP
@@ -1525,6 +1525,7 @@ A key or an event can be bound to one or more of the following actions.
\fBchange\-list\-label(...)\fR (change \fB\-\-list\-label\fR to the given string)
\fBchange\-multi\fR (enable multi-select mode with no limit)
\fBchange\-multi(...)\fR (enable multi-select mode with a limit or disable it with 0)
+ \fBchange\-nth(...)\fR (change \fB\-\-nth\fR option; rotate through the multiple options separated by '|')
\fBchange\-preview(...)\fR (change \fB\-\-preview\fR option)
\fBchange\-preview\-label(...)\fR (change \fB\-\-preview\-label\fR to the given string)
\fBchange\-preview\-window(...)\fR (change \fB\-\-preview\-window\fR option; rotate through the multiple option sets separated by '|')
diff --git a/src/actiontype_string.go b/src/actiontype_string.go
index 12162080..4459e251 100644
--- a/src/actiontype_string.go
+++ b/src/actiontype_string.go
@@ -33,107 +33,108 @@ func _() {
_ = x[actChangePreviewLabel-22]
_ = x[actChangePrompt-23]
_ = x[actChangeQuery-24]
- _ = x[actClearScreen-25]
- _ = x[actClearQuery-26]
- _ = x[actClearSelection-27]
- _ = x[actClose-28]
- _ = x[actDeleteChar-29]
- _ = x[actDeleteCharEof-30]
- _ = x[actEndOfLine-31]
- _ = x[actFatal-32]
- _ = x[actForwardChar-33]
- _ = x[actForwardWord-34]
- _ = x[actKillLine-35]
- _ = x[actKillWord-36]
- _ = x[actUnixLineDiscard-37]
- _ = x[actUnixWordRubout-38]
- _ = x[actYank-39]
- _ = x[actBackwardKillWord-40]
- _ = x[actSelectAll-41]
- _ = x[actDeselectAll-42]
- _ = x[actToggle-43]
- _ = x[actToggleSearch-44]
- _ = x[actToggleAll-45]
- _ = x[actToggleDown-46]
- _ = x[actToggleUp-47]
- _ = x[actToggleIn-48]
- _ = x[actToggleOut-49]
- _ = x[actToggleTrack-50]
- _ = x[actToggleTrackCurrent-51]
- _ = x[actToggleHeader-52]
- _ = x[actToggleWrap-53]
- _ = x[actToggleMultiLine-54]
- _ = x[actToggleHscroll-55]
- _ = x[actTrackCurrent-56]
- _ = x[actUntrackCurrent-57]
- _ = x[actDown-58]
- _ = x[actUp-59]
- _ = x[actPageUp-60]
- _ = x[actPageDown-61]
- _ = x[actPosition-62]
- _ = x[actHalfPageUp-63]
- _ = x[actHalfPageDown-64]
- _ = x[actOffsetUp-65]
- _ = x[actOffsetDown-66]
- _ = x[actOffsetMiddle-67]
- _ = x[actJump-68]
- _ = x[actJumpAccept-69]
- _ = x[actPrintQuery-70]
- _ = x[actRefreshPreview-71]
- _ = x[actReplaceQuery-72]
- _ = x[actToggleSort-73]
- _ = x[actShowPreview-74]
- _ = x[actHidePreview-75]
- _ = x[actTogglePreview-76]
- _ = x[actTogglePreviewWrap-77]
- _ = x[actTransform-78]
- _ = x[actTransformBorderLabel-79]
- _ = x[actTransformListLabel-80]
- _ = x[actTransformInputLabel-81]
- _ = x[actTransformHeader-82]
- _ = x[actTransformHeaderLabel-83]
- _ = x[actTransformPreviewLabel-84]
- _ = x[actTransformPrompt-85]
- _ = x[actTransformQuery-86]
- _ = x[actPreview-87]
- _ = x[actChangePreview-88]
- _ = x[actChangePreviewWindow-89]
- _ = x[actPreviewTop-90]
- _ = x[actPreviewBottom-91]
- _ = x[actPreviewUp-92]
- _ = x[actPreviewDown-93]
- _ = x[actPreviewPageUp-94]
- _ = x[actPreviewPageDown-95]
- _ = x[actPreviewHalfPageUp-96]
- _ = x[actPreviewHalfPageDown-97]
- _ = x[actPrevHistory-98]
- _ = x[actPrevSelected-99]
- _ = x[actPrint-100]
- _ = x[actPut-101]
- _ = x[actNextHistory-102]
- _ = x[actNextSelected-103]
- _ = x[actExecute-104]
- _ = x[actExecuteSilent-105]
- _ = x[actExecuteMulti-106]
- _ = x[actSigStop-107]
- _ = x[actFirst-108]
- _ = x[actLast-109]
- _ = x[actReload-110]
- _ = x[actReloadSync-111]
- _ = x[actDisableSearch-112]
- _ = x[actEnableSearch-113]
- _ = x[actSelect-114]
- _ = x[actDeselect-115]
- _ = x[actUnbind-116]
- _ = x[actRebind-117]
- _ = x[actBecome-118]
- _ = x[actShowHeader-119]
- _ = x[actHideHeader-120]
+ _ = x[actChangeNth-25]
+ _ = x[actClearScreen-26]
+ _ = x[actClearQuery-27]
+ _ = x[actClearSelection-28]
+ _ = x[actClose-29]
+ _ = x[actDeleteChar-30]
+ _ = x[actDeleteCharEof-31]
+ _ = x[actEndOfLine-32]
+ _ = x[actFatal-33]
+ _ = x[actForwardChar-34]
+ _ = x[actForwardWord-35]
+ _ = x[actKillLine-36]
+ _ = x[actKillWord-37]
+ _ = x[actUnixLineDiscard-38]
+ _ = x[actUnixWordRubout-39]
+ _ = x[actYank-40]
+ _ = x[actBackwardKillWord-41]
+ _ = x[actSelectAll-42]
+ _ = x[actDeselectAll-43]
+ _ = x[actToggle-44]
+ _ = x[actToggleSearch-45]
+ _ = x[actToggleAll-46]
+ _ = x[actToggleDown-47]
+ _ = x[actToggleUp-48]
+ _ = x[actToggleIn-49]
+ _ = x[actToggleOut-50]
+ _ = x[actToggleTrack-51]
+ _ = x[actToggleTrackCurrent-52]
+ _ = x[actToggleHeader-53]
+ _ = x[actToggleWrap-54]
+ _ = x[actToggleMultiLine-55]
+ _ = x[actToggleHscroll-56]
+ _ = x[actTrackCurrent-57]
+ _ = x[actUntrackCurrent-58]
+ _ = x[actDown-59]
+ _ = x[actUp-60]
+ _ = x[actPageUp-61]
+ _ = x[actPageDown-62]
+ _ = x[actPosition-63]
+ _ = x[actHalfPageUp-64]
+ _ = x[actHalfPageDown-65]
+ _ = x[actOffsetUp-66]
+ _ = x[actOffsetDown-67]
+ _ = x[actOffsetMiddle-68]
+ _ = x[actJump-69]
+ _ = x[actJumpAccept-70]
+ _ = x[actPrintQuery-71]
+ _ = x[actRefreshPreview-72]
+ _ = x[actReplaceQuery-73]
+ _ = x[actToggleSort-74]
+ _ = x[actShowPreview-75]
+ _ = x[actHidePreview-76]
+ _ = x[actTogglePreview-77]
+ _ = x[actTogglePreviewWrap-78]
+ _ = x[actTransform-79]
+ _ = x[actTransformBorderLabel-80]
+ _ = x[actTransformListLabel-81]
+ _ = x[actTransformInputLabel-82]
+ _ = x[actTransformHeader-83]
+ _ = x[actTransformHeaderLabel-84]
+ _ = x[actTransformPreviewLabel-85]
+ _ = x[actTransformPrompt-86]
+ _ = x[actTransformQuery-87]
+ _ = x[actPreview-88]
+ _ = x[actChangePreview-89]
+ _ = x[actChangePreviewWindow-90]
+ _ = x[actPreviewTop-91]
+ _ = x[actPreviewBottom-92]
+ _ = x[actPreviewUp-93]
+ _ = x[actPreviewDown-94]
+ _ = x[actPreviewPageUp-95]
+ _ = x[actPreviewPageDown-96]
+ _ = x[actPreviewHalfPageUp-97]
+ _ = x[actPreviewHalfPageDown-98]
+ _ = x[actPrevHistory-99]
+ _ = x[actPrevSelected-100]
+ _ = x[actPrint-101]
+ _ = x[actPut-102]
+ _ = x[actNextHistory-103]
+ _ = x[actNextSelected-104]
+ _ = x[actExecute-105]
+ _ = x[actExecuteSilent-106]
+ _ = x[actExecuteMulti-107]
+ _ = x[actSigStop-108]
+ _ = x[actFirst-109]
+ _ = x[actLast-110]
+ _ = x[actReload-111]
+ _ = x[actReloadSync-112]
+ _ = x[actDisableSearch-113]
+ _ = x[actEnableSearch-114]
+ _ = x[actSelect-115]
+ _ = x[actDeselect-116]
+ _ = x[actUnbind-117]
+ _ = x[actRebind-118]
+ _ = x[actBecome-119]
+ _ = x[actShowHeader-120]
+ _ = x[actHideHeader-121]
}
-const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
+const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
-var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 377, 390, 407, 415, 428, 444, 456, 464, 478, 492, 503, 514, 532, 549, 556, 575, 587, 601, 610, 625, 637, 650, 661, 672, 684, 698, 719, 734, 747, 765, 781, 796, 813, 820, 825, 834, 845, 856, 869, 884, 895, 908, 923, 930, 943, 956, 973, 988, 1001, 1015, 1029, 1045, 1065, 1077, 1100, 1121, 1143, 1161, 1184, 1208, 1226, 1243, 1253, 1269, 1291, 1304, 1320, 1332, 1346, 1362, 1380, 1400, 1422, 1436, 1451, 1459, 1465, 1479, 1494, 1504, 1520, 1535, 1545, 1553, 1560, 1569, 1582, 1598, 1613, 1622, 1633, 1642, 1651, 1660, 1673, 1686}
+var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 825, 832, 837, 846, 857, 868, 881, 896, 907, 920, 935, 942, 955, 968, 985, 1000, 1013, 1027, 1041, 1057, 1077, 1089, 1112, 1133, 1155, 1173, 1196, 1220, 1238, 1255, 1265, 1281, 1303, 1316, 1332, 1344, 1358, 1374, 1392, 1412, 1434, 1448, 1463, 1471, 1477, 1491, 1506, 1516, 1532, 1547, 1557, 1565, 1572, 1581, 1594, 1610, 1625, 1634, 1645, 1654, 1663, 1672, 1685, 1698}
func (i actionType) String() string {
if i < 0 || i >= actionType(len(_actionType_index)-1) {
diff --git a/src/core.go b/src/core.go
index 89f40ceb..35a143fe 100644
--- a/src/core.go
+++ b/src/core.go
@@ -190,11 +190,13 @@ func Run(opts *Options) (int, error) {
forward = true
}
}
+
+ nth := opts.Nth
patternCache := make(map[string]*Pattern)
patternBuilder := func(runes []rune) *Pattern {
return BuildPattern(cache, patternCache,
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
- opts.Filter == nil, opts.Nth, opts.Delimiter, runes)
+ opts.Filter == nil, nth, opts.Delimiter, runes)
}
inputRevision := revision{}
snapshotRevision := revision{}
@@ -373,6 +375,12 @@ func Run(opts *Options) (int, error) {
command = val.command
environ = val.environ
changed = val.changed
+ if val.nth != nil {
+ // Change nth and clear caches
+ nth = *val.nth
+ patternCache = make(map[string]*Pattern)
+ inputRevision.bumpMajor()
+ }
if command != nil {
useSnapshot = val.sync
}
diff --git a/src/options.go b/src/options.go
index ac4a1aca..3932cb56 100644
--- a/src/options.go
+++ b/src/options.go
@@ -1306,7 +1306,7 @@ const (
func init() {
executeRegexp = regexp.MustCompile(
- `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header)|transform|change-(?:preview-window|preview|multi)|(?:re|un)bind|pos|put|print)`)
+ `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header)|transform|change-(?:preview-window|preview|multi|nth)|(?:re|un)bind|pos|put|print)`)
splitRegexp = regexp.MustCompile("[,:]+")
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
}
@@ -1684,6 +1684,8 @@ func isExecuteAction(str string) actionType {
return actChangeQuery
case "change-multi":
return actChangeMulti
+ case "change-nth":
+ return actChangeNth
case "pos":
return actPosition
case "execute":
diff --git a/src/terminal.go b/src/terminal.go
index 1ca1c804..88c2b4a0 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -299,6 +299,7 @@ type Terminal struct {
scrollbar string
previewScrollbar string
ansi bool
+ nth []Range
tabstop int
margin [4]sizeSpec
padding [4]sizeSpec
@@ -462,6 +463,7 @@ const (
actChangePreviewLabel
actChangePrompt
actChangeQuery
+ actChangeNth
actClearScreen
actClearQuery
actClearSelection
@@ -597,6 +599,7 @@ type placeholderFlags struct {
type searchRequest struct {
sort bool
sync bool
+ nth *[]Range
command *commandSpec
environ []string
changed bool
@@ -880,6 +883,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
header: []string{},
header0: opts.Header,
ansi: opts.Ansi,
+ nth: opts.Nth,
tabstop: opts.Tabstop,
hasStartActions: false,
hasResultActions: false,
@@ -4359,6 +4363,7 @@ func (t *Terminal) Loop() error {
}
for loopIndex := int64(0); looping; loopIndex++ {
var newCommand *commandSpec
+ var newNth *[]Range
var reloadSync bool
changed := false
beof := false
@@ -4618,6 +4623,22 @@ func (t *Terminal) Loop() error {
}
t.multi = multi
req(reqList, reqInfo)
+ case actChangeNth:
+ changed = true
+
+ // Split nth expression
+ tokens := strings.Split(a.a, "|")
+ if nth, err := splitNth(tokens[0]); err == nil {
+ // Changed
+ newNth = &nth
+ } else {
+ // The default
+ newNth = &t.nth
+ }
+ // Cycle
+ if len(tokens) > 1 {
+ a.a = strings.Join(append(tokens[1:], tokens[0]), "|")
+ }
case actChangeQuery:
t.input = []rune(a.a)
t.cx = len(t.input)
@@ -5537,7 +5558,7 @@ func (t *Terminal) Loop() error {
reload := changed || newCommand != nil
var reloadRequest *searchRequest
if reload {
- reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, command: newCommand, environ: t.environ(), changed: changed}
+ reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed}
}
t.mutex.Unlock() // Must be unlocked before touching reqBox
diff --git a/test/test_go.rb b/test/test_go.rb
index db2d8f1d..b40bfb42 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -3718,6 +3718,29 @@ class TestGoFZF < TestBase
BLOCK
tmux.until { assert_block(block, _1) }
end
+
+ def test_change_nth
+ input = [
+ 'foo bar bar bar bar',
+ 'foo foo bar bar bar',
+ 'foo foo foo bar bar',
+ 'foo foo foo foo bar'
+ ]
+ writelines(input)
+ tmux.send_keys %(#{FZF} -qfoo -n1 --bind 'space:change-nth:2|3|4|5|' < #{tempname}), :Enter
+
+ tmux.until { |lines| assert_equal 4, lines.match_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 3, lines.match_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 2, lines.match_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.send_keys :Space
+ tmux.until { |lines| assert_equal 4, lines.match_count }
+ end
end
module TestShell