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).
- 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-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.
| 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 |
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 |
| 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. 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)
;; 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
