How fzf Handles Word Wrapping with the --wrap Option: Implementation Deep Dive
fzf implements line wrapping through the --wrap option by preprocessing logical lines into visual sub-lines before rendering, using (*Chars).Lines in src/util/chars.go for character-level breaks and back-tracking to the last space or tab for word-level breaks (--wrap=word), while subtracting the wrap-sign width from continuation lines.
The junegunn/fzf fuzzy finder provides flexible text wrapping to prevent long strings from being truncated in the terminal window. When enabled via the --wrap option, fzf processes text through a multi-stage pipeline that respects ANSI escape sequences, tab stops, and user-configurable wrap signs before rendering the final output to the screen.
Understanding the --wrap Option and Its Modes
The wrapping behavior is controlled by three related command-line options parsed in src/options.go (lines 610–618):
| Option | Meaning | Default |
|---|---|---|
--wrap[=MODE] |
Enable wrapping. MODE can be char (default) or word. |
disabled (false) |
--wrap-sign=STR |
String printed at the beginning of each continuation line. | "↳ " |
--wrap-word |
Shortcut for --wrap=word. |
false |
When wrapping is disabled (the default), lines overflow and the rightmost content is hidden. When enabled, fzf splits lines into visual sub-lines before rendering, accounting for the wrap-sign width on continuation lines.
Character-Level Wrapping (--wrap or --wrap=char)
In the default character mode, fzf cuts the line at the exact column where the text would overflow. The algorithm in src/util/chars.go repeatedly calls RunesWidth to determine how many runes fit within the available columns (wrapCols), emitting slices until the line is consumed.
Word-Level Wrapping (--wrap=word or --wrap-word)
When word mode is enabled, the algorithm back-tracks from the overflow point to the last space or tab character before breaking. If no whitespace exists (a single long word), it falls back to character-level breaking at that position. This logic is implemented in the Lines method of src/util/chars.go (lines 298–327), where breakIdx tracks the last whitespace position.
Core Implementation in fzf Source Code
Option Parsing (src/options.go)
The command-line parser fills the Options struct with wrapping preferences. Lines 610–618 handle the --wrap and --wrap-word flags:
// Default values
Wrap: false,
WrapWord: false,
// Parsing
case "--wrap":
opts.Wrap = true
opts.WrapWord = false
case "--wrap-word":
opts.Wrap = true
opts.WrapWord = true
The wrap sign is stored in opts.WrapSign with a default value of "↳ ".
Text Processing Logic (src/util/chars.go)
The (*Chars).Lines method (lines 298–327) performs the actual splitting. It takes parameters including wrapCols (available width), wrapSignWidth (width of the continuation marker), and wrapWord (boolean flag).
The algorithm:
- Iterates through runes, tracking cumulative width using
RunesWidth - When width exceeds
wrapCols, determines the break point - If
wrapWordis true, back-tracks to the last space/tab (breakIdx) - Emits the substring as a visual line
- Subtracts
wrapSignWidthfromwrapColsfor subsequent continuation lines
ANSI-Aware Wrapping for Previews (src/terminal.go)
For the preview window, which may contain ANSI color codes, Terminal.wordWrapAnsiLine (lines 4211–4240) handles wrapping while preserving escape sequences. It uses the same width calculation logic but operates on lines that may contain non-printing ANSI characters, ensuring that color codes do not interfere with width calculations.
UI Rendering (src/tui/tcell.go)
The final rendering occurs in renderWrapSign (lines 945–971), which draws the wrap sign at the beginning of continuation lines. The sign is printed with the appropriate style (tui.ColPreview for preview windows, tui.ColList for the main list).
Practical Usage Examples
Basic Character-Wrap
Enable default character-level wrapping to prevent truncation:
printf '%s\n' "aaaaaaaaaaaaaaaaaaaa" "bbbbbbbbbbbbbbbbbbbb" | fzf --wrap
Visual output:
aaaaaaaaaaaaaaaaa↳ a
bbbbbbbbbbbbbbbbb↳ b
Word-Wrap with Custom Sign
Use word-breaking and a custom continuation marker:
printf '%s\n' "this is a long line that should wrap nicely" | \
fzf --wrap=word --wrap-sign='↪ '
Result:
this is a long line↪ that should wrap nicely
Preview Window Wrapping
Enable wrapping in the preview pane:
printf 'file1\nfile2\n' | fzf \
--preview 'head -n 20 {}' \
--preview-window=right:50%:wrap
The preview window inherits wrap settings and uses wordWrapAnsiLine to handle colored output.
Runtime Toggling and Configuration
Users can toggle wrapping without restarting fzf:
- Ctrl-/: Toggles wrapping on/off (character mode)
- Ctrl-Shift-/ or Alt-/: Toggles between character and word wrap modes
These bindings trigger actToggleWrap and actToggleWrapWord in src/terminal.go (lines 844–845 and 6879–6883), which invert the boolean flags on the live Terminal instance and trigger a full redraw.
Summary
- fzf implements line wrapping through the
--wrapoption, processing text insrc/util/chars.gobefore rendering. - Character mode (
--wrapor--wrap=char) breaks lines at exact column limits. - Word mode (
--wrap=wordor--wrap-word) back-tracks to the last whitespace before breaking, falling back to character breaks for single long words. - The wrap sign (default
↳) is prepended to continuation lines, with its width subtracted from available columns as implemented insrc/tui/tcell.go. - Preview windows use
Terminal.wordWrapAnsiLineinsrc/terminal.goto handle ANSI escape sequences while wrapping. - Users can toggle modes at runtime using
Ctrl-/andCtrl-Shift-/without restarting the application.
Frequently Asked Questions
What is the default wrap sign in fzf?
The default wrap sign is the string "↳ " (a rightwards arrow followed by a space). This is defined in the options parsing code in src/options.go. You can customize it using the --wrap-sign flag, for example --wrap-sign='↪ '.
How do I enable word wrapping instead of character wrapping?
Use the --wrap=word option or the shorthand --wrap-word. This changes the breaking behavior from cutting at the exact column to back-tracking to the last space or tab before the overflow point. If no whitespace exists in the current segment, it falls back to character-level breaking for that segment.
Can I toggle wrapping dynamically while fzf is running?
Yes. Press Ctrl-/ to toggle wrapping on and off. Press Ctrl-Shift-/ (or Alt-/ on some terminals) to toggle between character wrap and word wrap modes. These key bindings call the internal actions actToggleWrap and actToggleWrapWord in src/terminal.go, which update the live terminal state and trigger a redraw.
Does wrapping affect the preview window in fzf?
Yes. The preview window supports independent wrapping via the wrap flag in the --preview-window option (e.g., --preview-window=right:50%:wrap). The preview uses Terminal.wordWrapAnsiLine in src/terminal.go to handle ANSI color codes while calculating visual width, ensuring that escape sequences do not interfere with the wrapping logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →