mirror of
https://github.com/junegunn/fzf.git
synced 2025-07-26 01:31:59 -07:00
Add bg-cancel action to ignore running background transforms
Close #4430 Example: # Implement popup that disappears after 1 second # * Use footer as the popup # * Use `bell` to ring the terminal bell # * Use `bg-transform-footer` to clear the footer after 1 second # * Use `bg-cancel` to ignore currently running background transform actions fzf --multi --list-border \ --bind 'enter:execute-silent(echo -n {+} | pbcopy)+bell' \ --bind 'enter:+transform-footer(echo Copied {} to clipboard)' \ --bind 'enter:+bg-cancel+bg-transform-footer(sleep 1)'
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -33,8 +33,19 @@ CHANGELOG
|
||||
seq 10000 | fzf --preview "awk '{sum += \$1} END {print sum}' {*f}"
|
||||
```
|
||||
- Use this with caution, as it can make fzf sluggish for large lists.
|
||||
- Added background variants of transform actions with `bg-` prefix that run asynchronously in the background
|
||||
- Added asynchronous transform actions with `bg-` prefix that run asynchronously in the background, along with `bg-cancel` action to ignore currently running `bg-transform` actions.
|
||||
```sh
|
||||
# Implement popup that disappears after 1 second
|
||||
# * Use footer as the popup
|
||||
# * Use `bell` to ring the terminal bell
|
||||
# * Use `bg-transform-footer` to clear the footer after 1 second
|
||||
# * Use `bg-cancel` to ignore currently running background transform actions
|
||||
fzf --multi --list-border \
|
||||
--bind 'enter:execute-silent(echo -n {+} | pbcopy)+bell' \
|
||||
--bind 'enter:+transform-footer(echo Copied {} to clipboard)' \
|
||||
--bind 'enter:+bg-cancel+bg-transform-footer(sleep 1)'
|
||||
|
||||
# It's okay for the commands to take a little while because they run in the background
|
||||
GETTER='curl -s http://metaphorpsum.com/sentences/1'
|
||||
fzf --style full --border --preview : \
|
||||
--bind "focus:bg-transform-header:$GETTER" \
|
||||
@@ -48,6 +59,8 @@ CHANGELOG
|
||||
--bind "focus:+bg-transform-ghost:$GETTER" \
|
||||
--bind "focus:+bg-transform-prompt:$GETTER"
|
||||
```
|
||||
- SSH completion enhancements by @akinomyoga
|
||||
- Bug fixes and improvements
|
||||
|
||||
0.62.0
|
||||
------
|
||||
|
@@ -128,49 +128,50 @@ func _() {
|
||||
_ = x[actBgTransformPrompt-117]
|
||||
_ = x[actBgTransformQuery-118]
|
||||
_ = x[actBgTransformSearch-119]
|
||||
_ = x[actSearch-120]
|
||||
_ = x[actPreview-121]
|
||||
_ = x[actPreviewTop-122]
|
||||
_ = x[actPreviewBottom-123]
|
||||
_ = x[actPreviewUp-124]
|
||||
_ = x[actPreviewDown-125]
|
||||
_ = x[actPreviewPageUp-126]
|
||||
_ = x[actPreviewPageDown-127]
|
||||
_ = x[actPreviewHalfPageUp-128]
|
||||
_ = x[actPreviewHalfPageDown-129]
|
||||
_ = x[actPrevHistory-130]
|
||||
_ = x[actPrevSelected-131]
|
||||
_ = x[actPrint-132]
|
||||
_ = x[actPut-133]
|
||||
_ = x[actNextHistory-134]
|
||||
_ = x[actNextSelected-135]
|
||||
_ = x[actExecute-136]
|
||||
_ = x[actExecuteSilent-137]
|
||||
_ = x[actExecuteMulti-138]
|
||||
_ = x[actSigStop-139]
|
||||
_ = x[actFirst-140]
|
||||
_ = x[actLast-141]
|
||||
_ = x[actReload-142]
|
||||
_ = x[actReloadSync-143]
|
||||
_ = x[actDisableSearch-144]
|
||||
_ = x[actEnableSearch-145]
|
||||
_ = x[actSelect-146]
|
||||
_ = x[actDeselect-147]
|
||||
_ = x[actUnbind-148]
|
||||
_ = x[actRebind-149]
|
||||
_ = x[actToggleBind-150]
|
||||
_ = x[actBecome-151]
|
||||
_ = x[actShowHeader-152]
|
||||
_ = x[actHideHeader-153]
|
||||
_ = x[actBell-154]
|
||||
_ = x[actExclude-155]
|
||||
_ = x[actExcludeMulti-156]
|
||||
_ = x[actAsync-157]
|
||||
_ = x[actBgCancel-120]
|
||||
_ = x[actSearch-121]
|
||||
_ = x[actPreview-122]
|
||||
_ = x[actPreviewTop-123]
|
||||
_ = x[actPreviewBottom-124]
|
||||
_ = x[actPreviewUp-125]
|
||||
_ = x[actPreviewDown-126]
|
||||
_ = x[actPreviewPageUp-127]
|
||||
_ = x[actPreviewPageDown-128]
|
||||
_ = x[actPreviewHalfPageUp-129]
|
||||
_ = x[actPreviewHalfPageDown-130]
|
||||
_ = x[actPrevHistory-131]
|
||||
_ = x[actPrevSelected-132]
|
||||
_ = x[actPrint-133]
|
||||
_ = x[actPut-134]
|
||||
_ = x[actNextHistory-135]
|
||||
_ = x[actNextSelected-136]
|
||||
_ = x[actExecute-137]
|
||||
_ = x[actExecuteSilent-138]
|
||||
_ = x[actExecuteMulti-139]
|
||||
_ = x[actSigStop-140]
|
||||
_ = x[actFirst-141]
|
||||
_ = x[actLast-142]
|
||||
_ = x[actReload-143]
|
||||
_ = x[actReloadSync-144]
|
||||
_ = x[actDisableSearch-145]
|
||||
_ = x[actEnableSearch-146]
|
||||
_ = x[actSelect-147]
|
||||
_ = x[actDeselect-148]
|
||||
_ = x[actUnbind-149]
|
||||
_ = x[actRebind-150]
|
||||
_ = x[actToggleBind-151]
|
||||
_ = x[actBecome-152]
|
||||
_ = x[actShowHeader-153]
|
||||
_ = x[actHideHeader-154]
|
||||
_ = x[actBell-155]
|
||||
_ = x[actExclude-156]
|
||||
_ = x[actExcludeMulti-157]
|
||||
_ = x[actAsync-158]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
|
||||
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, 1875, 1885, 1898, 1914, 1926, 1940, 1956, 1974, 1994, 2016, 2030, 2045, 2053, 2059, 2073, 2088, 2098, 2114, 2129, 2139, 2147, 2154, 2163, 2176, 2192, 2207, 2216, 2227, 2236, 2245, 2258, 2267, 2280, 2293, 2300, 2310, 2325, 2333}
|
||||
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}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
@@ -1703,6 +1703,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
||||
appendAction(actExclude)
|
||||
case "exclude-multi":
|
||||
appendAction(actExcludeMulti)
|
||||
case "bg-cancel":
|
||||
appendAction(actBgCancel)
|
||||
default:
|
||||
t := isExecuteAction(specLower)
|
||||
if t == actIgnore {
|
||||
|
@@ -230,6 +230,11 @@ type Status struct {
|
||||
Selected []StatusItem `json:"selected"`
|
||||
}
|
||||
|
||||
type versionedCallback struct {
|
||||
version int64
|
||||
callback func()
|
||||
}
|
||||
|
||||
// Terminal represents terminal input/output
|
||||
type Terminal struct {
|
||||
initDelay time.Duration
|
||||
@@ -371,6 +376,7 @@ type Terminal struct {
|
||||
selected map[int32]selectedItem
|
||||
version int64
|
||||
revision revision
|
||||
bgVersion int64
|
||||
reqBox *util.EventBox
|
||||
initialPreviewOpts previewOpts
|
||||
previewOpts previewOpts
|
||||
@@ -388,7 +394,7 @@ type Terminal struct {
|
||||
startChan chan fitpad
|
||||
killChan chan bool
|
||||
serverInputChan chan []*action
|
||||
callbackChan chan func()
|
||||
callbackChan chan versionedCallback
|
||||
bgQueue map[action][]func()
|
||||
bgSemaphore chan struct{}
|
||||
bgSemaphores map[action]chan struct{}
|
||||
@@ -601,6 +607,8 @@ const (
|
||||
actBgTransformQuery
|
||||
actBgTransformSearch
|
||||
|
||||
actBgCancel
|
||||
|
||||
actSearch
|
||||
actPreview
|
||||
actPreviewTop
|
||||
@@ -1038,7 +1046,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
||||
startChan: make(chan fitpad, 1),
|
||||
killChan: make(chan bool),
|
||||
serverInputChan: make(chan []*action, 100),
|
||||
callbackChan: make(chan func(), maxBgProcesses),
|
||||
callbackChan: make(chan versionedCallback, maxBgProcesses),
|
||||
bgQueue: make(map[action][]func()),
|
||||
bgSemaphore: make(chan struct{}, maxBgProcesses),
|
||||
bgSemaphores: make(map[action]chan struct{}),
|
||||
@@ -4360,10 +4368,10 @@ func (t *Terminal) captureLines(template string) string {
|
||||
func (t *Terminal) captureAsync(a action, firstLineOnly bool, callback func(string)) {
|
||||
_, list := t.buildPlusList(a.a, false)
|
||||
command, tempFiles := t.replacePlaceholder(a.a, false, string(t.input), list)
|
||||
version := t.bgVersion
|
||||
cmd := t.executor.ExecCommand(command, false)
|
||||
cmd.Env = t.environ()
|
||||
item := func() {
|
||||
cmd := t.executor.ExecCommand(command, false)
|
||||
cmd.Env = t.environ()
|
||||
|
||||
out, _ := cmd.StdoutPipe()
|
||||
reader := bufio.NewReader(out)
|
||||
var output string
|
||||
@@ -4379,7 +4387,7 @@ func (t *Terminal) captureAsync(a action, firstLineOnly bool, callback func(stri
|
||||
}
|
||||
removeFiles(tempFiles)
|
||||
|
||||
t.callbackChan <- func() { callback(output) }
|
||||
t.callbackChan <- versionedCallback{version, func() { callback(output) }}
|
||||
}
|
||||
queue, prs := t.bgQueue[a]
|
||||
if !prs {
|
||||
@@ -5318,12 +5326,16 @@ func (t *Terminal) Loop() error {
|
||||
case callback := <-t.callbackChan:
|
||||
event = tui.Invalid.AsEvent()
|
||||
actions = append(actions, &action{t: actAsync})
|
||||
callbacks = append(callbacks, callback)
|
||||
if callback.version == t.bgVersion {
|
||||
callbacks = append(callbacks, callback.callback)
|
||||
}
|
||||
DrainCallback:
|
||||
for {
|
||||
select {
|
||||
case callback = <-t.callbackChan:
|
||||
callbacks = append(callbacks, callback)
|
||||
if callback.version == t.bgVersion {
|
||||
callbacks = append(callbacks, callback.callback)
|
||||
}
|
||||
continue DrainCallback
|
||||
default:
|
||||
break DrainCallback
|
||||
@@ -5696,6 +5708,8 @@ func (t *Terminal) Loop() error {
|
||||
doActions(actions)
|
||||
}
|
||||
})
|
||||
case actBgCancel:
|
||||
t.bgVersion++
|
||||
case actChangePrompt:
|
||||
t.promptString = a.a
|
||||
t.prompt, t.promptLen = t.parsePrompt(a.a)
|
||||
|
@@ -1964,4 +1964,21 @@ class TestCore < TestInteractive
|
||||
elapsed = Time.now - time
|
||||
assert elapsed < 2
|
||||
end
|
||||
|
||||
def test_bg_cancel
|
||||
tmux.send_keys %(seq 0 1 | #{FZF} --bind 'space:bg-cancel+bg-transform-header(sleep {}; echo [{}])'), :Enter
|
||||
tmux.until { assert_equal 2, it.match_count }
|
||||
tmux.send_keys '1'
|
||||
tmux.until { assert_equal 1, it.match_count }
|
||||
tmux.send_keys :Space
|
||||
tmux.send_keys :BSpace
|
||||
tmux.until { assert_equal 2, it.match_count }
|
||||
tmux.send_keys :Space
|
||||
tmux.until { |lines| assert lines.any_include?('[0]') }
|
||||
sleep 2
|
||||
tmux.until do |lines|
|
||||
assert lines.any_include?('[0]')
|
||||
refute lines.any_include?('[1]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user