mirror of
https://github.com/junegunn/fzf.git
synced 2026-09-08 07:47:00 +08:00
Add 'wait' action to block fzf until search completion
The 'wait' action blocks subsequent action execution until the current search completes. This is essential for chaining actions after query-changing actions (e.g. transform-search(...)+wait+best), ensuring motion actions operate on complete results rather than stale data. - Blocks all user input except ESC/CTRL-C while waiting - Shows visual feedback: dimmed query, (..) indicator, hidden cursor - Clears pending actions if user cancels with ESC/CTRL-C Closes: #4825
This commit is contained in:
@@ -186,11 +186,12 @@ func _() {
|
||||
_ = x[actExclude-175]
|
||||
_ = x[actExcludeMulti-176]
|
||||
_ = x[actAsync-177]
|
||||
_ = x[actWait-178]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeHeaderLinesactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangeWithNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformHeaderLinesactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformWithNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformHeaderLinesactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformWithNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeHeaderLinesactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangeWithNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformHeaderLinesactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformWithNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformHeaderLinesactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformWithNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsyncactWait"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 336, 351, 371, 391, 410, 428, 442, 454, 470, 486, 502, 523, 545, 560, 574, 588, 601, 618, 626, 639, 655, 667, 675, 689, 703, 720, 731, 742, 756, 774, 791, 798, 817, 839, 851, 865, 874, 889, 901, 914, 925, 936, 948, 962, 983, 998, 1011, 1028, 1046, 1062, 1074, 1086, 1099, 1114, 1128, 1140, 1152, 1169, 1176, 1188, 1193, 1203, 1212, 1223, 1234, 1247, 1262, 1273, 1286, 1301, 1308, 1321, 1334, 1351, 1366, 1379, 1393, 1407, 1423, 1443, 1467, 1479, 1502, 1519, 1537, 1560, 1578, 1601, 1624, 1646, 1667, 1682, 1701, 1720, 1744, 1762, 1779, 1797, 1807, 1821, 1846, 1865, 1885, 1910, 1930, 1955, 1980, 2004, 2027, 2044, 2065, 2086, 2112, 2132, 2151, 2171, 2182, 2191, 2201, 2214, 2230, 2242, 2256, 2272, 2290, 2310, 2332, 2346, 2361, 2369, 2375, 2389, 2404, 2414, 2430, 2445, 2455, 2462, 2470, 2477, 2486, 2499, 2515, 2530, 2539, 2550, 2559, 2568, 2581, 2590, 2603, 2616, 2623, 2633, 2648, 2656}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 336, 351, 371, 391, 410, 428, 442, 454, 470, 486, 502, 523, 545, 560, 574, 588, 601, 618, 626, 639, 655, 667, 675, 689, 703, 720, 731, 742, 756, 774, 791, 798, 817, 839, 851, 865, 874, 889, 901, 914, 925, 936, 948, 962, 983, 998, 1011, 1028, 1046, 1062, 1074, 1086, 1099, 1114, 1128, 1140, 1152, 1169, 1176, 1188, 1193, 1203, 1212, 1223, 1234, 1247, 1262, 1273, 1286, 1301, 1308, 1321, 1334, 1351, 1366, 1379, 1393, 1407, 1423, 1443, 1467, 1479, 1502, 1519, 1537, 1560, 1578, 1601, 1624, 1646, 1667, 1682, 1701, 1720, 1744, 1762, 1779, 1797, 1807, 1821, 1846, 1865, 1885, 1910, 1930, 1955, 1980, 2004, 2027, 2044, 2065, 2086, 2112, 2132, 2151, 2171, 2182, 2191, 2201, 2214, 2230, 2242, 2256, 2272, 2290, 2310, 2332, 2346, 2361, 2369, 2375, 2389, 2404, 2414, 2430, 2445, 2455, 2462, 2470, 2477, 2486, 2499, 2515, 2530, 2539, 2550, 2559, 2568, 2581, 2590, 2603, 2616, 2623, 2633, 2648, 2656, 2663}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
||||
@@ -1958,6 +1958,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
||||
} else {
|
||||
return nil, errors.New("unable to put non-printable character")
|
||||
}
|
||||
case "wait":
|
||||
appendAction(actWait)
|
||||
case "bell":
|
||||
appendAction(actBell)
|
||||
case "exclude":
|
||||
|
||||
+64
-3
@@ -321,6 +321,9 @@ type Terminal struct {
|
||||
trackBlocked bool
|
||||
trackSync bool
|
||||
trackKeyCache map[int32]bool
|
||||
waitBlocked bool
|
||||
pendingActions []*action
|
||||
searchInProgress bool
|
||||
pendingSelections map[string]selectedItem
|
||||
targetIndex int32
|
||||
delimiter Delimiter
|
||||
@@ -720,6 +723,7 @@ const (
|
||||
actExclude
|
||||
actExcludeMulti
|
||||
actAsync
|
||||
actWait
|
||||
)
|
||||
|
||||
func (a actionType) Name() string {
|
||||
@@ -1876,6 +1880,17 @@ func (t *Terminal) UpdateProgress(progress float32) {
|
||||
func (t *Terminal) UpdateList(result MatchResult) {
|
||||
merger := result.merger
|
||||
t.mutex.Lock()
|
||||
waitWasBlocked := t.waitBlocked
|
||||
if result.final() {
|
||||
t.searchInProgress = false
|
||||
// If waiting, unblock so main loop can execute pending actions
|
||||
if t.waitBlocked {
|
||||
t.unblockWait()
|
||||
if len(t.pendingActions) > 0 {
|
||||
t.serverInputChan <- []*action{{t: actIgnore}}
|
||||
}
|
||||
}
|
||||
}
|
||||
prevIndex := minItem.Index()
|
||||
newRevision := merger.Revision()
|
||||
if t.revision.compatible(newRevision) && t.track != trackDisabled {
|
||||
@@ -2041,7 +2056,7 @@ func (t *Terminal) UpdateList(result MatchResult) {
|
||||
}
|
||||
}
|
||||
updateList := !t.trackBlocked && !t.pendingReqList
|
||||
updatePrompt := trackWasBlocked && !t.trackBlocked
|
||||
updatePrompt := (trackWasBlocked && !t.trackBlocked) || (waitWasBlocked && !t.waitBlocked)
|
||||
t.mutex.Unlock()
|
||||
|
||||
t.reqBox.Set(reqInfo, nil)
|
||||
@@ -3259,7 +3274,7 @@ func (t *Terminal) printPrompt() {
|
||||
color := tui.ColInput
|
||||
if t.paused {
|
||||
color = tui.ColDisabled
|
||||
} else if t.trackBlocked {
|
||||
} else if t.trackBlocked || t.waitBlocked {
|
||||
color = color.WithAttr(tui.Dim)
|
||||
}
|
||||
w.CPrint(color, string(before))
|
||||
@@ -3374,6 +3389,9 @@ func (t *Terminal) printInfoImpl() {
|
||||
output += " +t"
|
||||
}
|
||||
}
|
||||
if t.waitBlocked {
|
||||
output += " (..)"
|
||||
}
|
||||
if t.failed != nil && t.count == 0 {
|
||||
output = fmt.Sprintf("[Command failed: %s]", *t.failed)
|
||||
}
|
||||
@@ -5786,6 +5804,14 @@ func (t *Terminal) unblockTrack() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) unblockWait() {
|
||||
t.waitBlocked = false
|
||||
// Only show cursor if not blocked by tracking
|
||||
if !t.inputless && !t.trackBlocked {
|
||||
t.tui.ShowCursor()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
/*
|
||||
* echo $'HL1\nHL2' | fzf --header-lines 3 --header $'H1\nH2' --header-lines-border --bind 'click-header:preview:env | grep FZF_CLICK'
|
||||
@@ -6615,7 +6641,21 @@ func (t *Terminal) Loop() error {
|
||||
doActions := func(actions []*action) bool {
|
||||
for iter := 0; iter <= maxFocusEvents; iter++ {
|
||||
currentIndex := t.currentIndex()
|
||||
for _, action := range actions {
|
||||
for i, action := range actions {
|
||||
if action.t == actWait {
|
||||
// Block if search is in progress or will be triggered
|
||||
if changed || newCommand != nil || t.searchInProgress {
|
||||
t.waitBlocked = true
|
||||
t.pendingActions = actions[i+1:]
|
||||
if !t.inputless {
|
||||
t.tui.HideCursor()
|
||||
}
|
||||
req(reqPrompt, reqInfo)
|
||||
return true
|
||||
}
|
||||
// No search, wait is a no-op; continue to next action
|
||||
continue
|
||||
}
|
||||
if !doAction(action) {
|
||||
return false
|
||||
}
|
||||
@@ -6664,6 +6704,15 @@ func (t *Terminal) Loop() error {
|
||||
callback(a.a)
|
||||
}
|
||||
}
|
||||
// When wait-blocked, only allow abort/cancel
|
||||
if t.waitBlocked {
|
||||
if a.t == actAbort || a.t == actCancel {
|
||||
t.unblockWait()
|
||||
t.pendingActions = nil
|
||||
req(reqPrompt, reqInfo)
|
||||
}
|
||||
return true
|
||||
}
|
||||
// When track-blocked, only allow abort/cancel and track-disabling actions
|
||||
if t.trackBlocked && a.t != actToggleTrack && a.t != actToggleTrackCurrent && a.t != actUntrackCurrent {
|
||||
if a.t == actAbort || a.t == actCancel {
|
||||
@@ -8071,6 +8120,15 @@ func (t *Terminal) Loop() error {
|
||||
return true
|
||||
}
|
||||
|
||||
// Execute pending actions if wait just unblocked
|
||||
if len(t.pendingActions) > 0 && !t.waitBlocked {
|
||||
pendingActions := t.pendingActions
|
||||
t.pendingActions = nil
|
||||
if !doActions(pendingActions) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if t.jumping == jumpDisabled || len(actions) > 0 {
|
||||
// Break out of jump mode if any action is submitted to the server
|
||||
if t.jumping != jumpDisabled {
|
||||
@@ -8132,6 +8190,9 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
|
||||
reload := changed || newCommand != nil
|
||||
if reload {
|
||||
t.searchInProgress = true
|
||||
}
|
||||
var reloadRequest *searchRequest
|
||||
if reload {
|
||||
reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, withNth: newWithNth, headerLines: newHeaderLines, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.resultMerger.Revision()}
|
||||
|
||||
Reference in New Issue
Block a user