# How fzf Handles ANSI Color Codes with the `--ansi` Option

> Learn how fzf uses the --ansi option to parse and preserve ANSI color codes in your input for vibrant fuzzy matching and rendering. Enhance your command line.

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

---

**When you enable the `--ansi` flag, fzf parses ANSI escape sequences in input to strip them for fuzzy matching while preserving the color information to re-apply during rendering.**

The **junegunn/fzf** repository implements sophisticated ANSI processing that allows you to search through colorized text without the escape sequences interfering with the fuzzy finder algorithm. This feature enables seamless integration with tools like `git`, `ls`, or syntax highlighters that output color codes, maintaining visual clarity while ensuring accurate text matching.

## The ANSI Processing Pipeline

When `--ansi` is passed on the command line, fzf activates a multi-stage pipeline that separates display formatting from search logic.

### Option Parsing and Activation

The flag first sets `opts.Ansi = true` during initialization. According to the source code in [`src/options.go#L2831-L2834`](https://github.com/junegunn/fzf/blob/master/src/options.go#L2831), this boolean flag determines whether the input reader should invoke the color extraction logic. Once enabled, every incoming line passes through a specialized parser before reaching the matching engine.

### Extracting Colors with extractColor

The core parsing logic resides in the `extractColor` function defined in [`src/ansi.go#L259-L340`](https://github.com/junegunn/fzf/blob/master/src/ansi.go#L259). This function performs three critical operations:

- **Sequence Detection**: Uses `nextAnsiEscapeSequence` to locate escape sequences matching `\x1b[` ... `m` patterns
- **State Interpretation**: Calls `interpretCode` to create an `ansiState` object describing foreground colors, background colors, and text attributes like underline or bold
- **Text Trimming**: Builds a stripped version of the line containing only the visible characters for fuzzy matching

As the scanner processes each line, it builds a slice of `ansiOffset` structures. Each entry records the start and end positions (`[2]int32{start, end}`) alongside the corresponding `ansiState`, creating a precise map of where color changes occur in the visible text.

### State Management and Line Endings

Special handling ensures background colors persist across display operations. When the parser encounters a newline character, any pending full-line background color is stored as a special marker. This logic in [`src/ansi.go#L308-L322`](https://github.com/junegunn/fzf/blob/master/src/ansi.go#L308) guarantees that background highlighting spans the complete line width in the terminal interface, not just the text content.

### Rendering and Word-Wrap Handling

The terminal layer consumes the trimmed string and ANSI offsets separately. In [`src/terminal.go#L4755-L4860`](https://github.com/junegunn/fzf/blob/master/src/terminal.go#L4755), the `Terminal` struct re-applies the stored color states when drawing lines to the screen. For wrapped lines, the `wordWrapAnsiLine` function in [`src/terminal.go#L4211-L4228`](https://github.com/junegunn/fzf/blob/master/src/terminal.go#L4211) receives both the raw content and offset data, ensuring that color sequences remain intact across line breaks without breaking the terminal display.

## Practical Usage Examples

The `--ansi` option integrates seamlessly with standard Unix tools that produce colorized output.

### Basic Colorized Input

```bash
printf '\e[31mRed\e[0m\n\e[32mGreen\e[0m\n\e[34mBlue\e[0m\n' | \
  fzf --ansi --prompt='Pick a colour: '

```

In this example, the pipe feeds text containing literal escape sequences (`\e[31m` for red, etc.). The fuzzy matcher operates on the plain text (`Red`, `Green`, `Blue`) while the preview displays the original colors.

### Git Integration with Preview

```bash
git --no-pager log --oneline --decorate=short | \
  fzf --ansi \
      --preview='git --no-pager show --color=always {+1}' \
      --preview-window=up:60%

```

This command searches through colorized git history while maintaining syntax highlighting in the preview pane. The `--color=always` flag forces git to output ANSI codes, which fzf preserves through the `extractColor` offset mechanism.

## Key Source Files and Functions

Understanding the codebase structure helps when debugging ANSI display issues:

| File | Role |
|------|------|
| [`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go) | Parses `--ansi` / `--no-ansi` flags into `Opts.Ansi` |
| [`src/core.go`](https://github.com/junegunn/fzf/blob/main/src/core.go) | Invokes `extractColor` during input reading when ANSI mode is active |
| [`src/ansi.go`](https://github.com/junegunn/fzf/blob/main/src/ansi.go) | Contains the core parser: `extractColor`, `nextAnsiEscapeSequence`, `interpretCode`, and `ansiState` management |
| [`src/item.go`](https://github.com/junegunn/fzf/blob/main/src/item.go) | Provides `Item.AsString(stripAnsi bool)` for the matching pipeline |
| [`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go) | Handles rendering via `wordWrapAnsiLine` and applies stored offsets to the UI |

## Summary

- **Flag activation**: The `--ansi` option sets `opts.Ansi = true` in [[`src/options.go`](https://github.com/junegunn/fzf/blob/main/src/options.go)](https://github.com/junegunn/fzf/blob/master/src/options.go#L2831), triggering the color processing pipeline.
- **Separation of concerns**: The `extractColor` function strips escape sequences for matching while storing color offsets in [[`src/ansi.go`](https://github.com/junegunn/fzf/blob/main/src/ansi.go)](https://github.com/junegunn/fzf/blob/master/src/ansi.go#L259).
- **Accurate mapping**: `ansiOffset` structures using `[2]int32` pairs map visible character positions to their original ANSI states.
- **Terminal rendering**: The display layer in [[`src/terminal.go`](https://github.com/junegunn/fzf/blob/main/src/terminal.go)](https://github.com/junegunn/fzf/blob/master/src/terminal.go#L4755) re-applies colors using stored offsets, handling word wrapping via `wordWrapAnsiLine`.

## Frequently Asked Questions

### Does fzf match against the ANSI escape sequences or just the visible text?

Fzf matches only against the visible text. The `extractColor` function creates a trimmed string containing no escape sequences, which is what the fuzzy matching algorithm processes. The original ANSI codes are stored separately as offsets and do not participate in the search scoring.

### What happens to background colors that span entire lines?

When parsing reaches a newline character, fzf stores pending full-line background colors as special markers. This ensures that background highlighting extends to the full terminal width during rendering, as implemented in [`src/ansi.go#L308-L322`](https://github.com/junegunn/fzf/blob/master/src/ansi.go#L308).

### Can I use --ansi with the preview window?

Yes, the `--ansi` flag affects both the main list and preview content. The preview receives the original line with ANSI codes preserved through the offset mechanism, allowing commands like `git show --color=always` to display with full syntax highlighting inside the preview pane.

### How does fzf handle malformed or incomplete ANSI sequences?

The `nextAnsiEscapeSequence` scanner in [[`src/ansi.go`](https://github.com/junegunn/fzf/blob/main/src/ansi.go)](https://github.com/junegunn/fzf/blob/master/src/ansi.go#L259) looks for valid `\x1b[` sequences followed by `m` terminators. Malformed sequences that do not match this pattern are treated as literal text and passed through to the matching engine without color state changes.