Background transform results are unrelated to the block; dropping them
would silently lose completed work. Applies both the dedicated
bg-transform-* setters and actions parsed from generic bg-transform
output (inBgCallback). Searches initiated by a bg result are not
waited for.
Blocks execution of subsequent actions until the current search
completes, so motion actions operate on the complete result set.
# Move to the best match only after the search is done
fzf --bind 'start:change-query(foo)+wait+best'
- Blocks when a search is in progress, will be triggered by preceding
actions, or the query was edited in the same binding; no-op otherwise
- Initial input load counts as a search in progress, so 'start:wait'
blocks until the input is fully loaded and searched
- User input ignored while blocked; keys bound to abort/cancel cancel
the wait and discard pending actions instead
- Debounced feedback after 200ms: dimmed prompt, hidden cursor, and
(..) on the info line
- Fires like result, but only after the input stream closes
- Use for one-shot per-query actions that would otherwise re-fire on
every intermediate snapshot during loading
Close#4835
- handleHttpRequest used `body += text` per token, allocating a new
backing array on every append (O(n^2) total copy work)
- a single ~390 KB POST monopolised the single-threaded server for
~8 s, blocking all other --listen clients
- switch to strings.Builder for amortised O(n)
Reported with fix by Michal Majchrowicz and Marcin Wyczechowski
(AFINE Team).
- exec(2) rejects env entries containing NUL, breaking preview and
other child commands when the input has NUL bytes
- skip the export and document the limitation
Fix#2395
On 32-bit platforms (GOARCH=386, arm), N*M overflows int when N is
large and M approaches 1000, wrapping negative. The wrapped value
slips past both `N*M > cap(slab.I16)` and `M > 1000`, so the V1
fallback is skipped and alloc16 panics on a negative slice bound.
Cast to int64 before multiplying.
Affects shipped 32-bit ARM builds (linux_armv5/6/7, windows_armv5/6/7).
Reported with fix by Michal Majchrowicz and Marcin Wyczechowski
(AFINE Team).
Places preview adjacent to input on the list side: above input in the
default layout, below it in --layout=reverse.
fzf --preview 'cat {}' --preview-window=next
Close#4798
Async callbacks fire a later iteration than the one that scheduled
them, so newCommand/reloadSync/denylist must persist across iterations.
fzf --bind 'space:bg-transform:echo reload:date'
- every(N) fires every N seconds (fractional, floored to 0.01s)
- Encoded as tui.Every with duration in Char as milliseconds, so
every(1) and every(2) coexist as distinct keymap entries
- FZF_IDLE_TIME exposes whole seconds since the last user activity
(keystroke or mouse event); pair with every() for idle-based
patterns like auto-accept/auto-quit
Close#1211
A non-word character (e.g. '.') used to receive a flat bonusNonWord
regardless of context. Now it gets bonusBoundaryWhite at the start of
input and bonusBoundaryDelimiter right after a delimiter, matching the
treatment of word characters at the same boundaries.
Without this, '.completion' matching '.completion' lost to
'bash_completion.d/completions/X' because the consecutive chunk anchor
in the long path (the 'c' after '/') received bonusBoundaryDelimiter
while the exact match's '.' was capped at bonusNonWord.
Fix#4795
The display sanitizer already stripped raw 8-bit C1 bytes (0x80-0x9F)
because they decode to RuneError as standalone bytes. Their valid UTF-8
encodings (0xC2 0x80 .. 0xC2 0x9F) decode to the same code points but
were passed through, allowing a filename or input line containing CSI
(U+009B), OSC (U+009D), or DCS (U+0090) to inject terminal control
sequences when rendered.
toggle-preview-wrap (and -wrap-word) modifies t.activePreviewOpts.wrap,
but change-preview-window resets t.previewOpts to t.initialPreviewOpts,
discarding the user's toggle. Carry wrap and wrapWord over so toggles
survive a layout change. Explicit wrap / nowrap tokens in the new spec
still win, so cycling and the empty-token reset are unaffected.
Close#4791
Mirror of the earlier change-header fix. The inline footer slot's row
budget depends on footer content length, but resizeIfNeeded() tolerates
a shorter-than-wanted inline window, so extra lines get clipped. Drive
a redraw on length change to re-run the layout.
New --border=dashed / --list-border=dashed / --header-border=dashed etc.
Uses U+2576 (╶) for horizontal edges and U+2506 (┆) for verticals, with
rounded corners (╭╮╰╯) and sharp T-junction mids (├┤). Terminal cells
are taller than wide (~2:1), so horizontals use a sparse stub per cell
while verticals need more dashes per cell to look evenly dashed.
Works with inline sections.
The inline header slot's row budget depends on header content length,
but resizeIfNeeded() tolerates a shorter-than-wanted inline window, so
the stale slot stays. Drive a redraw on length change to re-run the
layout.
--header-first previously was rejected with --header-border=inline or
--header-lines-border=inline. Now, inline placement wins: an inline
section stays inside the list frame, and --header-first only affects
non-inline sections (mainly the main --header).
The guard fires when hasHeaderWindow() returned false at resize time,
not when addInline had no budget (placeInlineStack always leaves a
non-nil 0-height placeholder).
InitTheme was called before the runtime coerced BorderInline to
BorderLine, so HeaderBorder / FooterBorder inherited from ListBorder
even when the effective shape was 'line'. Mirror the coercion so
color inheritance matches the rendered shape.
New BorderShape that embeds the section inside the --list-border
frame, joined to the list content by a horizontal separator with
T-junctions where the list shape has side borders. Requires a list
border with both top and bottom segments; falls back to 'line'
otherwise. Stacks when multiple sections are inline.
Sections inherit --color list-border by default and are colored as a
uniform block via their own --color *-border and *-bg.
Incompatible with --header-first. --header-border=inline requires
--header-lines-border to be inline or unset.
Windows doesn't have signals, the default Kill doesn't actually kill
anything, and other forms of termination don't allow cleanup. So we
spawn preview processes in a new process group and send them a
CTRL_BREAK_EVENT to terminate.
However, we only do this for "pwsh" (PowerShell 7+) and unknown/
posix-ish shells, because cmd.exe and Windows PowerShell
("powershell.exe") don't always exit on Ctrl-Break. pwsh also needs
the -NonInteractive flag to exit on Ctrl-Break.
If the process wasn't given its own group, or if sending the console
control event fails, we fall back to the standard Kill (which likely
won't help, but doesn't hurt to try).
Fix#3134
Use make([]NthParts, 0, len(indexes)) so the slice starts empty with
reserved capacity. The previous length-len(indexes) allocation left
leading zero NthParts entries before appended elements.
When --walker=follow is used, symlinks like Wine's z: -> / cause fzf to
traverse the entire root filesystem. fastwalk's built-in loop detection
only catches this on the second pass, but a single pass through / already
causes severe CPU and memory exhaustion.
This fix resolves each symlink-to-directory target to its absolute real
path and skips it if it is an ancestor of (or equal to) the walker root.
Close#4710
When --walker=follow is used, symlink following is now handled by
fastwalk's IgnoreDuplicateDirs adapter which tracks visited directories
by device+inode. This prevents the same directory from being entered
more than once, avoiding effectively infinite traversal when a symlink
points outside the walker root.
Close#4710
Separate item identity from cursor tracking:
- Add --id-nth=NTH to define item identity fields for cross-reload ops
- --track reverts to a simple boolean flag
- track-current action no longer accepts nth argument
- With --multi, selections are preserved across reload-sync by matching
identity keys in the reloaded list
Close#4718Close#4701Close#4483Close#4409Close#3460Close#2441