flash lets you navigate your code with search labels, enhanced character motions, and Treesitter integration.
Inspired by flash.nvim for Neovim.
Unlike avy, flash uses incremental search: you type as many characters as you want to narrow down matches, and labels appear alongside the results. Labels are assigned intelligently — characters that would continue the search pattern are never used as labels, so there is no ambiguity between searching and jumping.
- Search Integration: labels appear during regular
C-s,/,?search. Press a label character to jump instantly. - Incremental input: type as many characters as you need before using a label. No fixed-length input.
- Enhanced
f,t,F,Tmotions with multi-match labels. - Treesitter Integration: select any parent node of the syntax tree at point with a single keystroke.
- Standalone Jump Mode (core feature): type a character, then press a label to jump where you need.
- Multi-window jumping across all visible windows.
- Evil integration: works as a proper evil motion (composable with operators like
d,y,c). - Remote Evil actions: select a distant target, yank or delete there, then return to where you started.
- Emacs >= 27.1
- Emacs >= 29.1 for Treesitter support
- Optional: evil-mode for Vim-style keybindings
flash is available on MELPA.
;; Add MELPA to package-archives if you haven't already:
;; (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(use-package flash
:commands (flash-jump flash-jump-continue flash-action flash-action-undo
flash-treesitter)
:bind ("s-j" . flash-jump)
:custom
(flash-multi-window t)
:init
;; Evil integration (simple setup)
(with-eval-after-load 'evil
(require 'flash-evil)
(flash-evil-setup t)) ; t = also set up f/t/F/T char motions
:config
;; Search integration (labels during C-s, /, ?)
(require 'flash-isearch)
(flash-isearch-mode 1))Or install interactively: M-x package-install RET flash RET.
(straight-use-package
'(flash :type git :host github :repo "Prgebish/flash"))(elpaca (flash :host github :repo "Prgebish/flash"))M-x flash-jump starts an interactive search. Type characters to narrow matches, then press a label to jump.
With evil-mode: press gs (or s if you bind it manually). I personally find C-/ convenient — it is easy to reach and does not shadow any useful evil bindings.
M-x flash-jump-continue resumes the previous search with the same pattern. Useful when you want to jump again to another match of the same text.
flash-isearch-mode adds labels to your regular incremental search. It works with C-s (Emacs isearch), /, ? (evil-ex-search).
When enabled:
- Start a search as usual (
C-sor/). - As you type, labels appear next to each match.
- Press a label character to jump directly to that match.
- Press
C-;to toggle labels on or off during a search.
Requires evil-mode. Set up keybindings with flash-evil-setup (pass t for char motions) or flash-char-setup-evil-keys manually. Then enable labels:
(setq flash-char-jump-labels t)Without flash-char-jump-labels, f / t just jump to the first match (like normal evil motions). With it enabled, all matches get labels, so you can reach any match with a single keystroke instead of repeating ;.
f{char}/F{char}— jump to character forward / backward.t{char}/T{char}— jump to just before character forward / backward.;— repeat last motion.,— repeat last motion in reverse (if,is your localleader, rebind to e.g.\).
M-x flash-treesitterShows labels for all parent nodes of the Treesitter syntax tree at point, from the innermost to the outermost. Each label corresponds to a progressively larger region of code (e.g., identifier, expression, statement, function body, function definition). Press a label to select that entire node. With evil-mode, the selection enters visual state automatically.
This is useful for quickly selecting or operating on a surrounding code structure — for example, selecting an entire function, an if-block, or an argument list.
Requires evil-mode. flash-evil-setup binds gS in normal state only:
- Press
gSand type a search pattern. - Press the label at the remote location.
- Enter a normal Evil yank/delete command.
For example, gS → price → a → yiw copies the word at label a, while
gS → debug → s → dd deletes the line at label s. After the operation,
Flash restores the original window, point, mark, and Evil state.
The action starts at the first character of the selected match. The rest of
the range comes from native Evil grammar, so commands such as yy, dd,
yiw, di(, y$, d2w, 2dw, and register prefixes such as "ayy work
normally. Direct Y, D, x, and X are supported too.
Only yank and delete operations are accepted. There is no ym=/=dm search
match object, no editing/paste actions, and no Embark integration. gS is not
bound in visual or operator-pending state; the existing gs remains the Flash
motion for compositions such as d gs, y gs, and c gs.
Undo history belongs to the changed buffer. Use M-x flash-action-undo to undo
the last remote deletion without visiting its buffer. The command refuses if
that buffer has been edited since the remote action.
| Variable | Default | Description |
|---|---|---|
flash-labels | "asdfjkl;ghqwertyuiopzxcvbnm" | Characters used for jump labels |
flash-label-uppercase | nil | Also use uppercase labels, doubling the pool (A-Z) |
flash-multi-char-labels | nil | Use multi-character labels (aa, as, ad…) |
flash-multi-window | t | Search across all visible windows |
flash-autojump | nil | Jump immediately when only one match remains |
flash-backdrop | t | Dim non-matching text |
flash-case-fold | t | Ignore case when searching |
flash-rainbow | nil | Color labels with a rainbow palette |
flash-rainbow-shade | 2 | Rainbow brightness 1-9 (pastel to dark) |
flash-highlight-matches | t | Highlight matched text |
flash-label-position | 'overlay | Where to place labels: overlay, pre-overlay, after, before, eol |
flash-jump-position | 'start | Cursor position after jump: start or end of match |
flash-jumplist | t | Push position to mark ring before jumping |
flash-nohlsearch | nil | Clear search highlighting after jump |
flash-search-history | nil | Add search pattern to isearch history |
flash-min-pattern-length | 0 | Minimum pattern length before labels appear |
flash-search-folds | nil | Search inside folded (invisible) regions |
flash-after-jump-hook | nil | Hook after standalone, autojump, RET, and isearch label jumps |
overlay(default) — label replaces the first character of the match.pre-overlay— label replaces the character before the match. The match text stays fully readable and there is no text shift. Falls back tooverlaywhen the match is at the beginning of a line or buffer.after— label is inserted after the match (flash.nvim default).before— label is inserted before the match.eol— label appears at the end of the line.
| Variable | Default | Description |
|---|---|---|
flash-char-jump-labels | nil | Show labels on all f/t/F/T matches |
flash-char-multi-line | nil | Search beyond current line |
flash-char-reserved-labels | "" | Characters excluded from labels (e.g., "aisoAISO;,cCxr" to keep evil editing keys) |
| Variable | Default | Description |
|---|---|---|
flash-isearch-enabled | t | Show labels during search |
flash-isearch-toggle-key | "C-;" | Key to toggle labels on/off during search |
flash-isearch-trigger | nil | Require a trigger character before label jump |
flash-isearch-update-delay | 0.05 | Debounce delay for isearch updates (seconds) |
flash-isearch-label-limit | 'single-char | Max matches rendered during isearch: single-char, full, or integer |
| Variable | Default | Description |
|---|---|---|
flash-treesitter-max-depth | 10 | Maximum depth of parent nodes shown |
(use-package flash
:custom
(flash-labels "asdfjkl;ghqwertyuiopzxcvbnm")
(flash-label-uppercase t) ; double available labels (a-z + A-Z)
(flash-multi-window t)
(flash-autojump t) ; auto-jump when single match
(flash-backdrop nil) ; no dimming
(flash-rainbow t) ; colorful labels
(flash-rainbow-shade 2) ; 1-9: pastel to dark
(flash-highlight-matches t)
(flash-label-position 'overlay)
(flash-char-jump-labels t) ; labels on f/t/F/T matches
(flash-nohlsearch t) ; clear highlight after jump
(flash-search-history t)) ; save patterns to isearch historyflash-evil-setup configures all evil keybindings in one call:
(require 'flash-evil)
(flash-evil-setup t) ; t = also set up f/t/F/T char motionsThis binds gs to flash-evil-jump in normal, visual, motion, and operator
states, and gS to flash-action in normal state only. With the optional
argument, it also replaces f, t, F, T with flash-enhanced versions.
If you prefer different keybindings:
(require 'flash-evil)
(evil-global-set-key 'normal (kbd "s") #'flash-evil-jump)
(evil-global-set-key 'visual (kbd "s") #'flash-evil-jump)
(evil-global-set-key 'normal (kbd "g S") #'flash-action)
;; Char motions
(flash-char-setup-evil-keys)flash-evil-jump is a proper evil motion, so it composes with operators:
d gs {label}— delete to targety gs {label}— yank to targetv gs {label}— extend visual selection to target
| Face | Description |
|---|---|
flash-label | Jump label |
flash-match | Search match highlight |
flash-backdrop | Backdrop (dimmed text) |
Rainbow labels use dynamic colors from the Tailwind CSS palette (10 colors: red, amber, lime, green, teal, cyan, blue, violet, fuchsia, rose). The brightness is controlled by flash-rainbow-shade:
| Shade | Background | Foreground | Style |
|---|---|---|---|
| 1-2 | light | dark (900) | pastel (default) |
| 3-4 | medium | dark (900) | medium |
| 5 | saturated | dark (950) | flash.nvim default |
| 6-9 | dark | light (50) | dark / inverted |
;; Change label appearance
(set-face-attribute 'flash-label nil
:background "#ff0000"
:foreground "#ffffff"
:weight 'bold)
;; Change match highlight
(set-face-attribute 'flash-match nil
:underline nil
:background "#ffff00"
:foreground "#000000")
;; Rainbow: pastel labels
(setq flash-rainbow t
flash-rainbow-shade 2)
;; Rainbow: dark labels with light text
(setq flash-rainbow-shade 7)- avy — jump to visible text using a char-based decision tree. Unlike flash, avy uses fixed-length input: you choose a target type (word, line, character), then press label keys. Flash lets you type an arbitrary search pattern first.
- ace-jump-mode — quick cursor movement (predecessor to avy).
Inspired by flash.nvim by folke.
If you find flash useful, consider giving it a star on GitHub — it helps others discover the project.
MIT