# How fzf Handles Word Wrapping with the --wrap Option: Implementation Deep Dive

> Discover how fzf implements word wrapping with the --wrap option. Explore the code in src/util/chars.go to understand its line and word break logic for efficient display.

- Repository: [Junegunn Choi/fzf](https://github.com/junegunn/fzf)
- Tags: deep-dive
- Published: 2026-03-01

---

**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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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:

```go
// 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:
1. Iterates through runes, tracking cumulative width using `RunesWidth`
2. When width exceeds `wrapCols`, determines the break point
3. If `wrapWord` is true, back-tracks to the last space/tab (`breakIdx`)
4. Emits the substring as a visual line
5. Subtracts `wrapSignWidth` from `wrapCols` for 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:

```bash
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:

```bash
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:

```bash
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`](https://github.com/junegunn/fzf/blob/main/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 `--wrap` option, processing text in [`src/util/chars.go`](https://github.com/junegunn/fzf/blob/main/src/util/chars.go) before rendering.
- **Character mode** (`--wrap` or `--wrap=char`) breaks lines at exact column limits.
- **Word mode** (`--wrap=word` or `--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 in [`src/tui/tcell.go`](https://github.com/junegunn/fzf/blob/main/src/tui/tcell.go).
- **Preview windows** use `Terminal.wordWrapAnsiLine` in [`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go) to handle ANSI escape sequences while wrapping.
- Users can **toggle modes at runtime** using `Ctrl-/` and `Ctrl-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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/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`](https://github.com/junegunn/fzf/blob/main/src/terminal.go) to handle ANSI color codes while calculating visual width, ensuring that escape sequences do not interfere with the wrapping logic.