Skip to content

Latest commit

 

History

40 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

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.

Table of Contents

Requirements

  • 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)

straight.el

(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)))

Quelpa

(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)))

VC

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

Manual installation

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)

Doom Emacs

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

Usage

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:

KeyCommand
C-livy-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-oivy-ag-open-in-other-window
M-.ivy-ag-toggle-vcs-ignores
C-M-.ivy-ag-change-file-type
C-c C-fivy-ag-change-file-pattern
C-c C-iivy-ag-change-exclusions
C-oivy-ag-menu
C-c M-mivy-ag-menu
C-jivy-call (preview)
RETivy-done (visit result)
M-qivy-ag-edit-results

To change keybindings, modify the variable ivy-ag-map, e.g.:

(keymap-set ivy-ag-map "C-<backspace>" #'ivy-ag-up)

Search menu, history, and named presets

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.

KeyPreset operation
SSave all settings under a label; update an existing label
PLoad a preset, including its query and directory
C-c dDelete a preset
C-c aToggle 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.

Selecting concrete files and directories

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.

Editable results and output options

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.

Calling from Lisp

(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.

Customization

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.

Search responsiveness and previews

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:

OptionDefaultMeaning
ivy-ag-max-results2000Maximum results per query
ivy-ag-max-line-length1000ag output and preview line width
ivy-ag-max-output-size2097152Maximum collected output characters
ivy-ag-search-timeout10Maximum 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.

Development

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-exit

Tests 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.

About

Ivy interface for ag searching.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages