mirror of
https://github.com/junegunn/fzf.git
synced 2026-06-23 09:28:27 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54d96f75b2 |
@@ -27,7 +27,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v7
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v5
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@ jobs:
|
||||
name: Spell Check with Typos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v7
|
||||
- uses: crate-ci/typos@685eb3d55be2f85191e8c84acb9f44d7756f84ab # v1.29.4
|
||||
|
||||
@@ -11,12 +11,6 @@ CHANGELOG
|
||||
(seq 100; sleep 1; seq 100) | fzf --query 1 \
|
||||
--bind 'result:transform-header(echo result: $FZF_MATCH_COUNT),result-final:transform-footer(echo final: $FZF_MATCH_COUNT)'
|
||||
```
|
||||
- Added `wait` action to block subsequent actions until search completes (#4825)
|
||||
- Useful for chaining transform actions with motion actions to ensure operations on complete results
|
||||
```sh
|
||||
# Wait for search to complete before moving to the best match
|
||||
fzf --bind 'start:search(foo)+wait+best'
|
||||
```
|
||||
- Bound `alt-left` to `backward-word` and `alt-right` to `forward-word` by default (#4833)
|
||||
|
||||
0.73.1
|
||||
|
||||
@@ -2146,7 +2146,6 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
||||
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
||||
\fBuntrack\-current\fR (stop tracking the current item; no-op if global tracking is enabled)
|
||||
\fBwait\fR (block action execution until search completes)
|
||||
\fBup\fR \fIctrl\-k up\fR
|
||||
\fBup\-match\fR \fIctrl\-p\fR \fIalt\-up\fR (move to the match above the cursor)
|
||||
\fBup\-selected\fR (move to the selected item above the cursor)
|
||||
@@ -2299,24 +2298,6 @@ chain multiple transform actions where later ones depend on earlier results,
|
||||
prefer using the \fBbg\fR variant. To cancel currently running background
|
||||
transform processes, use \fBbg\-cancel\fR action.
|
||||
|
||||
.SS WAITING FOR SEARCH COMPLETION
|
||||
|
||||
The \fBwait\fR action blocks the execution of subsequent actions until the
|
||||
current search completes. This is useful when chaining transform actions with
|
||||
motion actions like \fBbest\fR or \fBfirst\fR, ensuring that the motion action
|
||||
operates on the complete search results rather than stale data.
|
||||
|
||||
e.g.
|
||||
\fBfzf \-\-bind 'start:search(foo)+wait+best'\fR
|
||||
|
||||
In this example, \fBsearch(foo)\fR starts an asynchronous search,
|
||||
\fBwait\fR blocks until the search completes, and \fBbest\fR then moves the
|
||||
cursor to the best match in the complete result set.
|
||||
|
||||
While waiting, the UI is dimmed and user input is ignored (except for Escape or
|
||||
Ctrl-C to cancel the wait and discard pending actions). The info line shows
|
||||
\fB(..)\fR to indicate that fzf is waiting for the search to complete.
|
||||
|
||||
.SS PREVIEW BINDING
|
||||
|
||||
With \fBpreview(...)\fR action, you can specify multiple different preview
|
||||
|
||||
@@ -186,12 +186,11 @@ func _() {
|
||||
_ = x[actExclude-175]
|
||||
_ = x[actExcludeMulti-176]
|
||||
_ = x[actAsync-177]
|
||||
_ = x[actWait-178]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeHeaderLinesactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangeWithNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformHeaderLinesactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformWithNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformHeaderLinesactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformWithNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsyncactWait"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeHeaderLinesactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangeWithNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformHeaderLinesactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformWithNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformHeaderLinesactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformWithNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
|
||||
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}
|
||||
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}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
||||
@@ -1958,8 +1958,6 @@ 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":
|
||||
|
||||
+3
-64
@@ -321,9 +321,6 @@ 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
|
||||
@@ -723,7 +720,6 @@ const (
|
||||
actExclude
|
||||
actExcludeMulti
|
||||
actAsync
|
||||
actWait
|
||||
)
|
||||
|
||||
func (a actionType) Name() string {
|
||||
@@ -1880,17 +1876,6 @@ 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 {
|
||||
@@ -2056,7 +2041,7 @@ func (t *Terminal) UpdateList(result MatchResult) {
|
||||
}
|
||||
}
|
||||
updateList := !t.trackBlocked && !t.pendingReqList
|
||||
updatePrompt := (trackWasBlocked && !t.trackBlocked) || (waitWasBlocked && !t.waitBlocked)
|
||||
updatePrompt := trackWasBlocked && !t.trackBlocked
|
||||
t.mutex.Unlock()
|
||||
|
||||
t.reqBox.Set(reqInfo, nil)
|
||||
@@ -3274,7 +3259,7 @@ func (t *Terminal) printPrompt() {
|
||||
color := tui.ColInput
|
||||
if t.paused {
|
||||
color = tui.ColDisabled
|
||||
} else if t.trackBlocked || t.waitBlocked {
|
||||
} else if t.trackBlocked {
|
||||
color = color.WithAttr(tui.Dim)
|
||||
}
|
||||
w.CPrint(color, string(before))
|
||||
@@ -3389,9 +3374,6 @@ 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)
|
||||
}
|
||||
@@ -5804,14 +5786,6 @@ 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'
|
||||
@@ -6641,21 +6615,7 @@ func (t *Terminal) Loop() error {
|
||||
doActions := func(actions []*action) bool {
|
||||
for iter := 0; iter <= maxFocusEvents; iter++ {
|
||||
currentIndex := t.currentIndex()
|
||||
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
|
||||
}
|
||||
for _, action := range actions {
|
||||
if !doAction(action) {
|
||||
return false
|
||||
}
|
||||
@@ -6704,15 +6664,6 @@ 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 {
|
||||
@@ -8120,15 +8071,6 @@ 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 {
|
||||
@@ -8190,9 +8132,6 @@ 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()}
|
||||
|
||||
@@ -1162,14 +1162,6 @@ class TestCore < TestInteractive
|
||||
tmux.until { |lines| assert_equal 10, lines.match_count }
|
||||
end
|
||||
|
||||
def test_wait_action
|
||||
tmux.send_keys %((seq 100; sleep 60) | #{FZF} --bind 'start:search(1)+wait+best'), :Enter
|
||||
tmux.until { |lines| assert_equal 20, lines.match_count }
|
||||
tmux.until { |lines| assert lines.any_include?('20/100 (..)') }
|
||||
tmux.send_keys 'C-c'
|
||||
tmux.until { |lines| refute lines.any_include?('20/100 (..)') }
|
||||
end
|
||||
|
||||
def test_clear_selection
|
||||
tmux.send_keys %(seq 100 | #{FZF} --multi --bind space:clear-selection), :Enter
|
||||
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||
|
||||
Reference in New Issue
Block a user