Search with ag (the silver searcher) through Ivy and Transient. Change directories and filters while keeping the current query, preview matches without visiting files, and restore complete searches from history or named presets. Search results can also be rerun in a buffer for wgrep editing or with ag’s output options.
- ag (the silver searcher), available on
exec-path - Emacs 30.1 or later
- Ivy and Counsel 0.13.4 or later, including Counsel’s Swiper dependency
- Transient 0.13.4 or later and its dependencies
wgrep(optional, for editable search results)
(use-package ivy-ag
:straight (ivy-ag
:host github
:repo "KarimAziev/ivy-ag"
:type git
:flavor nil)
:bind (("C-c C-s" . ivy-ag)
("C-c M-s" . ivy-ag-default-dir)
("C-c m" . ivy-ag-menu)))(use-package ivy-ag
:quelpa (ivy-ag
:fetcher github
:repo "KarimAziev/ivy-ag")
:bind (("C-c C-s" . ivy-ag)
("C-c M-s" . ivy-ag-default-dir)
("C-c m" . ivy-ag-menu)))Starting with Emacs 30, you can use use-package together with package-vc.el.
(use-package ivy-ag
:vc (:url "https://github.com/KarimAziev/ivy-ag"
:rev :newest)
:bind (("C-c C-s" . ivy-ag)
("C-c M-s" . ivy-ag-default-dir)
("C-c m" . ivy-ag-menu)))Download the source code and put it wherever you like, e.g. into ~/.emacs.d/ivy-ag/
git clone https://github-personal.com/KarimAziev/ivy-ag.git ~/.emacs.d/ivy-ag/Add the downloaded directory to the load path:
(add-to-list 'load-path "/path/to/ivy-ag/")
(require 'ivy-ag)
(keymap-global-set "C-c C-s" #'ivy-ag)
(keymap-global-set "C-c M-s" #'ivy-ag-default-dir)
(keymap-global-set "C-c m" #'ivy-ag-menu)Add package definition to DOOMDIR/packages.el (e.g. ~/.doom.d/config.el):
(package! ivy-ag
:recipe (:repo "KarimAziev/ivy-ag"))Configure it in DOOMDIR/config.el:
(use-package! ivy-ag
:bind (("C-c C-s" . ivy-ag)
("C-c M-s" . ivy-ag-default-dir)
("C-c m" . ivy-ag-menu))
:commands (ivy-ag-default-dir
ivy-ag
ivy-ag-read-multi))Start with ivy-ag to search the current project’s root, falling back to
the nearest Git root or the current directory. ivy-ag-default-dir starts
in the current directory. Use ivy-ag-menu to configure a search before
running it, or ivy-ag-output-menu for a separate output buffer.
The search minibuffer has these default bindings:
| Key | Command |
|---|---|
| C-l | ivy-ag-up |
| C-. | ivy-ag-cd |
| C-< | ivy-ag-switch-prev-dir |
| C-> | ivy-ag-switch-next-dir |
| C-<backspace> | ivy-ag-up |
| C-c C-o | ivy-ag-open-in-other-window |
| M-. | ivy-ag-toggle-vcs-ignores |
| C-M-. | ivy-ag-change-file-type |
| C-c C-f | ivy-ag-change-file-pattern |
| C-c C-i | ivy-ag-change-exclusions |
| C-o | ivy-ag-menu |
| C-c M-m | ivy-ag-menu |
| C-j | ivy-call (preview) |
| RET | ivy-done (visit result) |
| M-q | ivy-ag-edit-results |
To change keybindings, modify the variable ivy-ag-map, e.g.:
(keymap-set ivy-ag-map "C-<backspace>" #'ivy-ag-up)M-x ivy-ag-menu configures a search outside the minibuffer. During a
search, C-o or C-c M-m opens the menu with the current query, directory,
and filters. RET runs the search; reopening the menu preserves the query
verbatim, including regexp syntax.
Use d to choose the directory, = to edit the query, F to select
excluded paths, and L to set the display width.
The menu includes file types, a filename regexp (-G), ignore patterns,
selected concrete exclusions, an ignore file (-p), and traversal options.
c cycles Ivy’s default case behavior, ignore case, case sensitive, and smart
case. n selects literal text; -Q, -F, --literal, and
--fixed-strings are treated as aliases. Literal searches pass the text
unchanged to ag and use literal highlighting. Regexp searches retain the
configured Ivy regexp builder.
f accepts ag’s filename regular expressions, while i and I accept
repeatable ignore patterns. + accepts extra search switches that have no
dedicated control; double-quote values containing spaces. Options with a
dedicated search or output control must be set through that control.
L selects the display width. Running the search applies this value to
ivy-ag-max-line-length, affecting both ag output and previews. This is a
runtime setting; use Customize to change its permanent default.
C-M-p and C-M-n use Transient’s normal history to restore complete
searches: directory, query, selected exclusions, display width, and search
and output flags. Transient’s normal set/save operations preserve this
context too. Its history is persisted according to transient-save-history.
Presets are independent, named records in ivy-ag-presets. Several presets
can refer to the same directory, such as “Home documents”, “Home hidden
configuration”, and “Home source code”. A nonempty label/description is
required when saving. Completion shows both the label and the directory;
the menu shows the loaded preset’s label.
| Key | Preset operation |
|---|---|
| S | Save all settings under a label; update an existing label |
| P | Load a preset, including its query and directory |
| C-c d | Delete a preset |
| C-c a | Toggle a preset as its directory’s automatic default |
Saving and deleting presets use customize-save-variable, so records
survive Emacs restarts. A preset is not automatic until explicitly enabled.
Only one preset is automatic for a given directory. Automatic presets also
apply in descendants, with the most specific directory winning; an existing
search in the same directory or explicit function arguments take precedence.
For Straight repositories, configure --skip-vcs-ignores, save a labeled
preset rooted at ~/.emacs.d/straight/repos/, then enable it with C-c a.
Other named presets for that directory remain available through P.
F opens ivy-ag-read-files, a reusable Ivy file reader that returns a list
of absolute paths. C-j navigates directories, M-m marks, M-u unmarks,
M-a toggles visible marks, and M-U clears all marks. Marks retain their
absolute identity while navigating. RET accepts the marked paths, or
the current path when nothing is marked. C-c C-c accepts the marks even when the selection is empty;
C-g cancels the reader.
Selected exclusions become anchored, relative --ignore-dir= arguments.
Despite its name, ag’s option excludes files as well as directories. Pattern
characters in selected filenames are escaped. A selected sub/file.txt
excludes that concrete path, not every nested path ending in sub/file.txt.
When the search directory changes, exclusions are recomputed relative to it;
selections outside the new root have no effect and remain available when
returning to the original root. Use i or I for intentionally written
ignore patterns instead. Argument values containing spaces are preserved.
The file-type reader supports Ivy marks and C-c C-k to clear all type
filters. The minibuffer commands C-c C-f, C-c C-i, and C-M-. edit the same
filters while preserving the current search’s other settings.
e in either menu, or M-q during an Ivy search, reruns the query
asynchronously with complete source lines in a grep buffer. With wgrep
installed, C-x C-q enables editing and C-c C-c applies changes to source
buffers. Save the changed buffers normally, or configure wgrep’s own saving
behavior. This is textual replacement across files, not language-aware
symbol renaming. The existing ivy-occur command continues to export a
bounded, read-only snapshot.
O opens ivy-ag-output-menu. It retains search filters and offers counts,
filenames, context lines, statistics, headings, line numbers, output width,
and machine formats. RET runs asynchronously in a separate output buffer;
q returns to search settings and retains the output options. The output
width is independent of the display width used by Ivy. Full-line grep and
output searches are not subject to the minibuffer’s result, time, or output
size limits; their processes can be stopped with the buffer’s standard
compilation commands.
M-w copies a shell-quoted command including its working directory. It uses
the same resolved query and arguments as the corresponding destination.
C-c C-a displays that command without copying it.
(ivy-ag directory input flags) treats a supplied input as an existing Ivy
query and preserves it verbatim, including an empty string. Only text
inferred from a region or symbol is processed by
ivy-ag-escape-initial-input-chars-regex; nil leaves that text unchanged,
and literal mode bypasses quoting entirely.
Omitting flags allows reuse of the current directory’s settings or an
automatic preset. Explicit nil means an empty flag list. Each list element
is one argument; for example:
(ivy-ag default-directory "foo bar"
'("--literal" "--file-search-regex=notes archive"))Counsel’s query -- switches and switches -- query forms remain available.
Double-quote inline option values containing spaces. Prefer list-valued
counsel-ag-base-command templates; legacy shell templates are also supported.
The tables above show default bindings. Customize ivy-ag-map for the
search minibuffer, ivy-ag-read-files-map for selecting paths,
ivy-ag-types-map for selecting file types, and ivy-ag-grep-mode-map for
full-line results. These maps inherit from Ivy, Counsel, or Grep as
appropriate; defaults are installed only when each map is first defined.
Prompts and Emacs help resolve the current bindings, including inherited
bindings, and show the command name when it is unbound. For example:
(with-eval-after-load 'ivy-ag
(keymap-unset ivy-ag-types-map "C-c C-k")
(keymap-set ivy-ag-types-map "C-c C-z" #'ivy-ag--clear-type-selection))ivy-ag-switchable-directories
List of directories for switching with ivy-ag-switch-next-dir and ivy-ag-switch-prev-dir.
ivy-ag preserves Ivy’s configured regexp syntax and result highlighting.
Search output uses ag --vimgrep --width NUM, where NUM is
ivy-ag-max-line-length. This bounds the text returned from matching lines
before it reaches Emacs while retaining the original line and byte column.
Matches beyond the displayed snippet can still be previewed and opened.
C-j previews the result in a separate, read-only buffer, using the same
non-visiting approach as counsel-extra--preview-file. It does not run
find-file-hook, file-local variables, or major-mode hooks. Files whose lines
fit within ivy-ag-max-line-length are shown in full, with their text unchanged.
Only files containing longer lines use a bounded excerpt around the match.
In that excerpt, each context line is limited to ivy-ag-max-line-length
characters, and the selected line is positioned around the reported match
column. ivy-ag-preview-context-lines (default 5) applies only to these
long-line excerpts. Fontification and match overlays are limited to the area
around point in either preview, without removing ordinary file content.
The preview uses Swiper’s regexp match overlays, including capture-group
faces. Highlighting never activates a region. Previews read the file on disk,
which is what ag searches, even when a visiting buffer has unsaved edits.
That buffer’s text, point, mark, active region, narrowing, and major mode are
left unchanged. If a preview fails, the error is reported with focus returned
to the minibuffer so you can continue the search. Cancelling the search
removes the preview and restores the previous windows. RET intentionally
visits the actual file at the reported location, deactivating an old region
before jumping so it cannot be extended accidentally. Previewing a file
respects large-file-warning-threshold; RET remains available to open
larger files explicitly.
Each new query cancels the previous search immediately, including a delayed
start. Leaving the minibuffer cancels the process and all ivy-ag timers.
Process filters only collect bounded output; a separate timer updates the
result list with quitting enabled. If C-g interrupts regexp highlighting,
the search process and timers are cancelled as well.
The default limits are:
| Option | Default | Meaning |
|---|---|---|
ivy-ag-max-results | 2000 | Maximum results per query |
ivy-ag-max-line-length | 1000 | ag output and preview line width |
ivy-ag-max-output-size | 2097152 | Maximum collected output characters |
ivy-ag-search-timeout | 10 | Maximum search duration in seconds |
When a result, output, or time limit is reached, the process is stopped,
complete results are retained, and the prompt reports the limit. Narrow the
query or increase the relevant option to collect more results. These limits
mean a displayed list can be incomplete. Width limits reduce the amount of
text processed but cannot make every regexp cheap: long sequences of wildcard
gaps can still backtrack on repetitive text. Such work remains interruptible
with C-g; an Emacs timer cannot preempt a running regexp.
ivy-occur exports a read-only snapshot of the collected results without
rerunning the search. Result actions still navigate to the file and column.
The export uses ordinary ivy-occur-mode, not an editable grep buffer,
because truncated snippets must not be written back as complete file lines.
Reverting this buffer redisplays its saved snapshot. Start a new search to
refresh the results.
Run the regression tests with Ivy, Counsel, Swiper, Transient and its dependencies on the load path. Add wgrep to exercise the full editing test:
emacs -Q --batch \
-L /path/to/compat -L /path/to/cond-let -L /path/to/llama \
-L /path/to/transient/lisp -L /path/to/swiper -L /path/to/emacs-wgrep \
-L . \
-l ivy-ag.el -l test/ivy-ag-test.el -f ert-run-tests-batch-and-exitTests exercise real ag processes, bounded non-visiting previews, UTF-8 navigation, source-region preservation, full regexp match overlays, cancellation during rendering, output limits, timeouts, occur snapshots, complete Transient history, named presets, literal and case behavior, argument quoting, exclusions, full-line wgrep edits, file-type selection outside Transient, and customized keymaps and help text. Tests that require wgrep are skipped when it is unavailable. Potentially pathological combined regexps should only be benchmarked in an isolated Emacs process with an external timeout.