mirror of
https://github.com/junegunn/fzf.git
synced 2025-07-26 09:42:02 -07:00
Add 'trigger(KEY_OR_EVENT[,...])' action
This commit is contained in:
16
CHANGELOG.md
16
CHANGELOG.md
@@ -17,6 +17,22 @@ CHANGELOG
|
|||||||
echo "execute-silent(echo -n \{} | pbcopy)+bell"
|
echo "execute-silent(echo -n \{} | pbcopy)+bell"
|
||||||
'
|
'
|
||||||
```
|
```
|
||||||
|
- Added `trigger(...)` action that triggers events bound to another key or event.
|
||||||
|
```sh
|
||||||
|
# You can click on each key name to trigger the actions bound to that key
|
||||||
|
fzf --footer 'Ctrl-E: Edit / Ctrl-V: View / Ctrl-Y: Copy to clipboard' \
|
||||||
|
--with-shell 'bash -c' \
|
||||||
|
--bind 'ctrl-e:execute:vim {}' \
|
||||||
|
--bind 'ctrl-v:execute:view {}' \
|
||||||
|
--bind 'ctrl-y:execute-silent(echo -n {} | pbcopy)+bell' \
|
||||||
|
--bind 'click-footer:transform:
|
||||||
|
[[ $FZF_CLICK_FOOTER_WORD =~ Ctrl ]] && echo "trigger(${FZF_CLICK_FOOTER_WORD%:})"
|
||||||
|
'
|
||||||
|
```
|
||||||
|
- You can specify a series of keys and events
|
||||||
|
```sh
|
||||||
|
fzf --bind 'a:up,b:trigger(a,a,a)'
|
||||||
|
```
|
||||||
- Added support for `{*n}` and `{*nf}` placeholder.
|
- Added support for `{*n}` and `{*nf}` placeholder.
|
||||||
- `{*n}` evaluates to the zero-based ordinal index of all matched items.
|
- `{*n}` evaluates to the zero-based ordinal index of all matched items.
|
||||||
- `{*nf}` evaluates to the temporary file containing that.
|
- `{*nf}` evaluates to the temporary file containing that.
|
||||||
|
@@ -1817,6 +1817,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBtransform\-prompt(...)\fR (transform prompt string using an external command)
|
\fBtransform\-prompt(...)\fR (transform prompt string using an external command)
|
||||||
\fBtransform\-query(...)\fR (transform query string using an external command)
|
\fBtransform\-query(...)\fR (transform query string using an external command)
|
||||||
\fBtransform\-search(...)\fR (trigger fzf search with the output of an external command)
|
\fBtransform\-search(...)\fR (trigger fzf search with the output of an external command)
|
||||||
|
\fBtrigger(...)\fR (trigger actions bound to a comma-separated list of keys and events)
|
||||||
\fBunbind(...)\fR (unbind bindings)
|
\fBunbind(...)\fR (unbind bindings)
|
||||||
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
||||||
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
||||||
|
@@ -113,65 +113,66 @@ func _() {
|
|||||||
_ = x[actTransformPrompt-102]
|
_ = x[actTransformPrompt-102]
|
||||||
_ = x[actTransformQuery-103]
|
_ = x[actTransformQuery-103]
|
||||||
_ = x[actTransformSearch-104]
|
_ = x[actTransformSearch-104]
|
||||||
_ = x[actBgTransform-105]
|
_ = x[actTrigger-105]
|
||||||
_ = x[actBgTransformBorderLabel-106]
|
_ = x[actBgTransform-106]
|
||||||
_ = x[actBgTransformGhost-107]
|
_ = x[actBgTransformBorderLabel-107]
|
||||||
_ = x[actBgTransformHeader-108]
|
_ = x[actBgTransformGhost-108]
|
||||||
_ = x[actBgTransformFooter-109]
|
_ = x[actBgTransformHeader-109]
|
||||||
_ = x[actBgTransformHeaderLabel-110]
|
_ = x[actBgTransformFooter-110]
|
||||||
_ = x[actBgTransformFooterLabel-111]
|
_ = x[actBgTransformHeaderLabel-111]
|
||||||
_ = x[actBgTransformInputLabel-112]
|
_ = x[actBgTransformFooterLabel-112]
|
||||||
_ = x[actBgTransformListLabel-113]
|
_ = x[actBgTransformInputLabel-113]
|
||||||
_ = x[actBgTransformNth-114]
|
_ = x[actBgTransformListLabel-114]
|
||||||
_ = x[actBgTransformPointer-115]
|
_ = x[actBgTransformNth-115]
|
||||||
_ = x[actBgTransformPreviewLabel-116]
|
_ = x[actBgTransformPointer-116]
|
||||||
_ = x[actBgTransformPrompt-117]
|
_ = x[actBgTransformPreviewLabel-117]
|
||||||
_ = x[actBgTransformQuery-118]
|
_ = x[actBgTransformPrompt-118]
|
||||||
_ = x[actBgTransformSearch-119]
|
_ = x[actBgTransformQuery-119]
|
||||||
_ = x[actBgCancel-120]
|
_ = x[actBgTransformSearch-120]
|
||||||
_ = x[actSearch-121]
|
_ = x[actBgCancel-121]
|
||||||
_ = x[actPreview-122]
|
_ = x[actSearch-122]
|
||||||
_ = x[actPreviewTop-123]
|
_ = x[actPreview-123]
|
||||||
_ = x[actPreviewBottom-124]
|
_ = x[actPreviewTop-124]
|
||||||
_ = x[actPreviewUp-125]
|
_ = x[actPreviewBottom-125]
|
||||||
_ = x[actPreviewDown-126]
|
_ = x[actPreviewUp-126]
|
||||||
_ = x[actPreviewPageUp-127]
|
_ = x[actPreviewDown-127]
|
||||||
_ = x[actPreviewPageDown-128]
|
_ = x[actPreviewPageUp-128]
|
||||||
_ = x[actPreviewHalfPageUp-129]
|
_ = x[actPreviewPageDown-129]
|
||||||
_ = x[actPreviewHalfPageDown-130]
|
_ = x[actPreviewHalfPageUp-130]
|
||||||
_ = x[actPrevHistory-131]
|
_ = x[actPreviewHalfPageDown-131]
|
||||||
_ = x[actPrevSelected-132]
|
_ = x[actPrevHistory-132]
|
||||||
_ = x[actPrint-133]
|
_ = x[actPrevSelected-133]
|
||||||
_ = x[actPut-134]
|
_ = x[actPrint-134]
|
||||||
_ = x[actNextHistory-135]
|
_ = x[actPut-135]
|
||||||
_ = x[actNextSelected-136]
|
_ = x[actNextHistory-136]
|
||||||
_ = x[actExecute-137]
|
_ = x[actNextSelected-137]
|
||||||
_ = x[actExecuteSilent-138]
|
_ = x[actExecute-138]
|
||||||
_ = x[actExecuteMulti-139]
|
_ = x[actExecuteSilent-139]
|
||||||
_ = x[actSigStop-140]
|
_ = x[actExecuteMulti-140]
|
||||||
_ = x[actFirst-141]
|
_ = x[actSigStop-141]
|
||||||
_ = x[actLast-142]
|
_ = x[actFirst-142]
|
||||||
_ = x[actReload-143]
|
_ = x[actLast-143]
|
||||||
_ = x[actReloadSync-144]
|
_ = x[actReload-144]
|
||||||
_ = x[actDisableSearch-145]
|
_ = x[actReloadSync-145]
|
||||||
_ = x[actEnableSearch-146]
|
_ = x[actDisableSearch-146]
|
||||||
_ = x[actSelect-147]
|
_ = x[actEnableSearch-147]
|
||||||
_ = x[actDeselect-148]
|
_ = x[actSelect-148]
|
||||||
_ = x[actUnbind-149]
|
_ = x[actDeselect-149]
|
||||||
_ = x[actRebind-150]
|
_ = x[actUnbind-150]
|
||||||
_ = x[actToggleBind-151]
|
_ = x[actRebind-151]
|
||||||
_ = x[actBecome-152]
|
_ = x[actToggleBind-152]
|
||||||
_ = x[actShowHeader-153]
|
_ = x[actBecome-153]
|
||||||
_ = x[actHideHeader-154]
|
_ = x[actShowHeader-154]
|
||||||
_ = x[actBell-155]
|
_ = x[actHideHeader-155]
|
||||||
_ = x[actExclude-156]
|
_ = x[actBell-156]
|
||||||
_ = x[actExcludeMulti-157]
|
_ = x[actExclude-157]
|
||||||
_ = x[actAsync-158]
|
_ = x[actExcludeMulti-158]
|
||||||
|
_ = x[actAsync-159]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||||
|
|
||||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1562, 1587, 1606, 1626, 1646, 1671, 1696, 1720, 1743, 1760, 1781, 1807, 1827, 1846, 1866, 1877, 1886, 1896, 1909, 1925, 1937, 1951, 1967, 1985, 2005, 2027, 2041, 2056, 2064, 2070, 2084, 2099, 2109, 2125, 2140, 2150, 2158, 2165, 2174, 2187, 2203, 2218, 2227, 2238, 2247, 2256, 2269, 2278, 2291, 2304, 2311, 2321, 2336, 2344}
|
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1558, 1572, 1597, 1616, 1636, 1656, 1681, 1706, 1730, 1753, 1770, 1791, 1817, 1837, 1856, 1876, 1887, 1896, 1906, 1919, 1935, 1947, 1961, 1977, 1995, 2015, 2037, 2051, 2066, 2074, 2080, 2094, 2109, 2119, 2135, 2150, 2160, 2168, 2175, 2184, 2197, 2213, 2228, 2237, 2248, 2257, 2266, 2279, 2288, 2301, 2314, 2321, 2331, 2346, 2354}
|
||||||
|
|
||||||
func (i actionType) String() string {
|
func (i actionType) String() string {
|
||||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||||
|
@@ -932,15 +932,12 @@ func parseBorder(str string, optional bool) (tui.BorderShape, error) {
|
|||||||
return tui.BorderNone, errors.New("invalid border style (expected: rounded|sharp|bold|block|thinblock|double|horizontal|vertical|top|bottom|left|right|none)")
|
return tui.BorderNone, errors.New("invalid border style (expected: rounded|sharp|bold|block|thinblock|double|horizontal|vertical|top|bottom|left|right|none)")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseKeyChords(str string, message string) (map[tui.Event]string, error) {
|
func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Event, error) {
|
||||||
return parseKeyChordsImpl(str, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error) {
|
|
||||||
if len(str) == 0 {
|
if len(str) == 0 {
|
||||||
return nil, errors.New(message)
|
return nil, nil, errors.New(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list := []tui.Event{}
|
||||||
str = regexp.MustCompile("(?i)(alt-),").ReplaceAllString(str, "$1"+string([]rune{escapedComma}))
|
str = regexp.MustCompile("(?i)(alt-),").ReplaceAllString(str, "$1"+string([]rune{escapedComma}))
|
||||||
tokens := strings.Split(str, ",")
|
tokens := strings.Split(str, ",")
|
||||||
if str == "," || strings.HasPrefix(str, ",,") || strings.HasSuffix(str, ",,") || strings.Contains(str, ",,,") {
|
if str == "," || strings.HasPrefix(str, ",,") || strings.HasSuffix(str, ",,") || strings.Contains(str, ",,,") {
|
||||||
@@ -956,6 +953,7 @@ func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error
|
|||||||
lkey := strings.ToLower(key)
|
lkey := strings.ToLower(key)
|
||||||
add := func(e tui.EventType) {
|
add := func(e tui.EventType) {
|
||||||
chords[e.AsEvent()] = key
|
chords[e.AsEvent()] = key
|
||||||
|
list = append(list, e.AsEvent())
|
||||||
}
|
}
|
||||||
switch lkey {
|
switch lkey {
|
||||||
case "up":
|
case "up":
|
||||||
@@ -969,7 +967,9 @@ func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error
|
|||||||
case "enter", "return":
|
case "enter", "return":
|
||||||
add(tui.Enter)
|
add(tui.Enter)
|
||||||
case "space":
|
case "space":
|
||||||
chords[tui.Key(' ')] = key
|
evt := tui.Key(' ')
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
case "backspace", "bspace", "bs":
|
case "backspace", "bspace", "bs":
|
||||||
add(tui.Backspace)
|
add(tui.Backspace)
|
||||||
case "ctrl-space":
|
case "ctrl-space":
|
||||||
@@ -1013,9 +1013,13 @@ func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error
|
|||||||
case "multi":
|
case "multi":
|
||||||
add(tui.Multi)
|
add(tui.Multi)
|
||||||
case "alt-enter", "alt-return":
|
case "alt-enter", "alt-return":
|
||||||
chords[tui.CtrlAltKey('m')] = key
|
evt := tui.CtrlAltKey('m')
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
case "alt-space":
|
case "alt-space":
|
||||||
chords[tui.AltKey(' ')] = key
|
evt := tui.AltKey(' ')
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
case "alt-bs", "alt-bspace", "alt-backspace":
|
case "alt-bs", "alt-bspace", "alt-backspace":
|
||||||
add(tui.AltBackspace)
|
add(tui.AltBackspace)
|
||||||
case "alt-up":
|
case "alt-up":
|
||||||
@@ -1093,7 +1097,9 @@ func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error
|
|||||||
default:
|
default:
|
||||||
runes := []rune(key)
|
runes := []rune(key)
|
||||||
if len(key) == 10 && strings.HasPrefix(lkey, "ctrl-alt-") && isAlphabet(lkey[9]) {
|
if len(key) == 10 && strings.HasPrefix(lkey, "ctrl-alt-") && isAlphabet(lkey[9]) {
|
||||||
chords[tui.CtrlAltKey(rune(key[9]))] = key
|
evt := tui.CtrlAltKey(rune(key[9]))
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
} else if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
} else if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
||||||
add(tui.EventType(tui.CtrlA.Int() + int(lkey[5]) - 'a'))
|
add(tui.EventType(tui.CtrlA.Int() + int(lkey[5]) - 'a'))
|
||||||
} else if len(runes) == 5 && strings.HasPrefix(lkey, "alt-") {
|
} else if len(runes) == 5 && strings.HasPrefix(lkey, "alt-") {
|
||||||
@@ -1106,17 +1112,21 @@ func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error
|
|||||||
case escapedPlus:
|
case escapedPlus:
|
||||||
r = '+'
|
r = '+'
|
||||||
}
|
}
|
||||||
chords[tui.AltKey(r)] = key
|
evt := tui.AltKey(r)
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
} else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
|
} else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
|
||||||
add(tui.EventType(tui.F1.Int() + int(key[1]) - '1'))
|
add(tui.EventType(tui.F1.Int() + int(key[1]) - '1'))
|
||||||
} else if len(runes) == 1 {
|
} else if len(runes) == 1 {
|
||||||
chords[tui.Key(runes[0])] = key
|
evt := tui.Key(runes[0])
|
||||||
|
chords[evt] = key
|
||||||
|
list = append(list, evt)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("unsupported key: " + key)
|
return nil, list, errors.New("unsupported key: " + key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return chords, nil
|
return chords, list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScheme(str string) (string, []criterion, error) {
|
func parseScheme(str string) (string, []criterion, error) {
|
||||||
@@ -1439,7 +1449,7 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
executeRegexp = regexp.MustCompile(
|
executeRegexp = regexp.MustCompile(
|
||||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|bg-transform|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|bg-transform|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
|
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|bg-transform|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|bg-transform|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search|trigger)`)
|
||||||
splitRegexp = regexp.MustCompile("[,:]+")
|
splitRegexp = regexp.MustCompile("[,:]+")
|
||||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
||||||
}
|
}
|
||||||
@@ -1736,7 +1746,7 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
|||||||
}
|
}
|
||||||
switch t {
|
switch t {
|
||||||
case actUnbind, actRebind, actToggleBind:
|
case actUnbind, actRebind, actToggleBind:
|
||||||
if _, err := parseKeyChordsImpl(actionArg, spec[0:offset]+" target required"); err != nil {
|
if _, _, err := parseKeyChords(actionArg, spec[0:offset]+" target required"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case actChangePreviewWindow:
|
case actChangePreviewWindow:
|
||||||
@@ -1781,7 +1791,7 @@ func parseKeymap(keymap map[tui.Event][]*action, str string) error {
|
|||||||
} else if len(keyName) == 1 && keyName[0] == escapedPlus {
|
} else if len(keyName) == 1 && keyName[0] == escapedPlus {
|
||||||
key = tui.Key('+')
|
key = tui.Key('+')
|
||||||
} else {
|
} else {
|
||||||
keys, err := parseKeyChordsImpl(keyName, "key name required")
|
keys, _, err := parseKeyChords(keyName, "key name required")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1928,6 +1938,8 @@ func isExecuteAction(str string) actionType {
|
|||||||
return actBgTransformQuery
|
return actBgTransformQuery
|
||||||
case "bg-transform-search":
|
case "bg-transform-search":
|
||||||
return actBgTransformSearch
|
return actBgTransformSearch
|
||||||
|
case "trigger":
|
||||||
|
return actTrigger
|
||||||
case "search":
|
case "search":
|
||||||
return actSearch
|
return actSearch
|
||||||
}
|
}
|
||||||
@@ -1935,7 +1947,7 @@ func isExecuteAction(str string) actionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseToggleSort(keymap map[tui.Event][]*action, str string) error {
|
func parseToggleSort(keymap map[tui.Event][]*action, str string) error {
|
||||||
keys, err := parseKeyChords(str, "key name required")
|
keys, _, err := parseKeyChords(str, "key name required")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2474,7 +2486,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
chords, err := parseKeyChords(str, "key names required")
|
chords, _, err := parseKeyChords(str, "key names required")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -142,7 +142,7 @@ func TestIrrelevantNth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseKeys(t *testing.T) {
|
func TestParseKeys(t *testing.T) {
|
||||||
pairs, _ := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
|
pairs, _, _ := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
|
||||||
checkEvent := func(e tui.Event, s string) {
|
checkEvent := func(e tui.Event, s string) {
|
||||||
if pairs[e] != s {
|
if pairs[e] != s {
|
||||||
t.Errorf("%s != %s", pairs[e], s)
|
t.Errorf("%s != %s", pairs[e], s)
|
||||||
@@ -168,7 +168,7 @@ func TestParseKeys(t *testing.T) {
|
|||||||
checkEvent(tui.AltKey(' '), "alt-SPACE")
|
checkEvent(tui.AltKey(' '), "alt-SPACE")
|
||||||
|
|
||||||
// Synonyms
|
// Synonyms
|
||||||
pairs, _ = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
|
pairs, _, _ = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
|
||||||
if len(pairs) != 9 {
|
if len(pairs) != 9 {
|
||||||
t.Error(9)
|
t.Error(9)
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ func TestParseKeys(t *testing.T) {
|
|||||||
check(tui.Left, "left")
|
check(tui.Left, "left")
|
||||||
check(tui.Right, "right")
|
check(tui.Right, "right")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
|
pairs, _, _ = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
|
||||||
if len(pairs) != 11 {
|
if len(pairs) != 11 {
|
||||||
t.Error(11)
|
t.Error(11)
|
||||||
}
|
}
|
||||||
@@ -211,40 +211,40 @@ func TestParseKeysWithComma(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pairs, _ := parseKeyChords(",", "")
|
pairs, _, _ := parseKeyChords(",", "")
|
||||||
checkN(len(pairs), 1)
|
checkN(len(pairs), 1)
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords(",,a,b", "")
|
pairs, _, _ = parseKeyChords(",,a,b", "")
|
||||||
checkN(len(pairs), 3)
|
checkN(len(pairs), 3)
|
||||||
check(pairs, tui.Key('a'), "a")
|
check(pairs, tui.Key('a'), "a")
|
||||||
check(pairs, tui.Key('b'), "b")
|
check(pairs, tui.Key('b'), "b")
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords("a,b,,", "")
|
pairs, _, _ = parseKeyChords("a,b,,", "")
|
||||||
checkN(len(pairs), 3)
|
checkN(len(pairs), 3)
|
||||||
check(pairs, tui.Key('a'), "a")
|
check(pairs, tui.Key('a'), "a")
|
||||||
check(pairs, tui.Key('b'), "b")
|
check(pairs, tui.Key('b'), "b")
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords("a,,,b", "")
|
pairs, _, _ = parseKeyChords("a,,,b", "")
|
||||||
checkN(len(pairs), 3)
|
checkN(len(pairs), 3)
|
||||||
check(pairs, tui.Key('a'), "a")
|
check(pairs, tui.Key('a'), "a")
|
||||||
check(pairs, tui.Key('b'), "b")
|
check(pairs, tui.Key('b'), "b")
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords("a,,,b,c", "")
|
pairs, _, _ = parseKeyChords("a,,,b,c", "")
|
||||||
checkN(len(pairs), 4)
|
checkN(len(pairs), 4)
|
||||||
check(pairs, tui.Key('a'), "a")
|
check(pairs, tui.Key('a'), "a")
|
||||||
check(pairs, tui.Key('b'), "b")
|
check(pairs, tui.Key('b'), "b")
|
||||||
check(pairs, tui.Key('c'), "c")
|
check(pairs, tui.Key('c'), "c")
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords(",,,", "")
|
pairs, _, _ = parseKeyChords(",,,", "")
|
||||||
checkN(len(pairs), 1)
|
checkN(len(pairs), 1)
|
||||||
check(pairs, tui.Key(','), ",")
|
check(pairs, tui.Key(','), ",")
|
||||||
|
|
||||||
pairs, _ = parseKeyChords(",ALT-,,", "")
|
pairs, _, _ = parseKeyChords(",ALT-,,", "")
|
||||||
checkN(len(pairs), 1)
|
checkN(len(pairs), 1)
|
||||||
check(pairs, tui.AltKey(','), "ALT-,")
|
check(pairs, tui.AltKey(','), "ALT-,")
|
||||||
}
|
}
|
||||||
|
@@ -604,6 +604,8 @@ const (
|
|||||||
actTransformQuery
|
actTransformQuery
|
||||||
actTransformSearch
|
actTransformSearch
|
||||||
|
|
||||||
|
actTrigger
|
||||||
|
|
||||||
actBgTransform
|
actBgTransform
|
||||||
actBgTransformBorderLabel
|
actBgTransformBorderLabel
|
||||||
actBgTransformGhost
|
actBgTransformGhost
|
||||||
@@ -5443,6 +5445,7 @@ func (t *Terminal) Loop() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
triggering := map[tui.Event]struct{}{}
|
||||||
previousInput := t.input
|
previousInput := t.input
|
||||||
previousCx := t.cx
|
previousCx := t.cx
|
||||||
previousVersion := t.version
|
previousVersion := t.version
|
||||||
@@ -6234,6 +6237,20 @@ func (t *Terminal) Loop() error {
|
|||||||
case actDisableSearch:
|
case actDisableSearch:
|
||||||
t.paused = true
|
t.paused = true
|
||||||
req(reqPrompt)
|
req(reqPrompt)
|
||||||
|
case actTrigger:
|
||||||
|
if _, chords, err := parseKeyChords(a.a, ""); err == nil {
|
||||||
|
for _, chord := range chords {
|
||||||
|
if _, prs := triggering[chord]; prs {
|
||||||
|
// Avoid recursive triggering
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if acts, prs := t.keymap[chord]; prs {
|
||||||
|
triggering[chord] = struct{}{}
|
||||||
|
doActions(acts)
|
||||||
|
delete(triggering, chord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case actSigStop:
|
case actSigStop:
|
||||||
p, err := os.FindProcess(os.Getpid())
|
p, err := os.FindProcess(os.Getpid())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -6555,13 +6572,13 @@ func (t *Terminal) Loop() error {
|
|||||||
t.reading = true
|
t.reading = true
|
||||||
}
|
}
|
||||||
case actUnbind:
|
case actUnbind:
|
||||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||||
for key := range keys {
|
for key := range keys {
|
||||||
delete(t.keymap, key)
|
delete(t.keymap, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case actRebind:
|
case actRebind:
|
||||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||||
for key := range keys {
|
for key := range keys {
|
||||||
if originalAction, found := t.keymapOrg[key]; found {
|
if originalAction, found := t.keymapOrg[key]; found {
|
||||||
t.keymap[key] = originalAction
|
t.keymap[key] = originalAction
|
||||||
@@ -6569,7 +6586,7 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case actToggleBind:
|
case actToggleBind:
|
||||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||||
for key := range keys {
|
for key := range keys {
|
||||||
if _, bound := t.keymap[key]; bound {
|
if _, bound := t.keymap[key]; bound {
|
||||||
delete(t.keymap, key)
|
delete(t.keymap, key)
|
||||||
|
@@ -2035,4 +2035,14 @@ class TestCore < TestInteractive
|
|||||||
assert_equal 19, it.select_count
|
assert_equal 19, it.select_count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_trigger
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --bind 'a:up+trigger(a),b:trigger(a,a,b,a)'), :Enter
|
||||||
|
tmux.until { assert_equal 100, it.match_count }
|
||||||
|
tmux.until { |lines| assert_includes lines, '> 1' }
|
||||||
|
tmux.send_keys :a
|
||||||
|
tmux.until { |lines| assert_includes lines, '> 3' }
|
||||||
|
tmux.send_keys :b
|
||||||
|
tmux.until { |lines| assert_includes lines, '> 9' }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user