Fast and complete Ctags solution using ivy-completion
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

counsel-etags (v1.6.3)

Fast and complete Ctags solution using ivy-completion.

It’s tested in huge projects like Linux Kernel source and it still works even with one million candidates.


Place counsel-etags.el somewhere (say ~/.emacs/lisp), add below code into .emacs:

(add-to-list 'load-path "~/.emacs.d/lisp/")
(require 'counsel-etags)

If “Exuberant Ctags” (some people prefer “Universal Ctags” because it’s more actively maintained) and “GNU Find” are already installed, this program works out of box.

Or else, use `counsel-etags-update-tags-backend’ to customize shell command to generate tags file.

Please note it’s reported “Exuberant Ctags” v5.8.5 is buggy.


Run M-x counsel-etags-find-tag-at-point to navigate in code files without any setup.

This command will:

  • find project root folder and scan code automatically
  • find correct tag automatically
  • if no tag is find, it runs ripgrep or grep automatically

That’s it.

If you prefer manually setup tags file. You only need run M-x counsel-etags-scan-code once or create tags file in your own way.


Ignore directories and files

You can setup counsel-etags-ignore-directories and counsel-etags-ignore-filenames,

(eval-after-load 'counsel-etags
     ;; counsel-etags-ignore-directories does NOT support wildcast
     (add-to-list 'counsel-etags-ignore-directories "build_clang")
     (add-to-list 'counsel-etags-ignore-directories "build_clang")
     ;; counsel-etags-ignore-filenames supports wildcast
     (add-to-list 'counsel-etags-ignore-filenames "TAGS")
     (add-to-list 'counsel-etags-ignore-filenames "*.json")))

Setup tags-file-name

We try to setup Emacs global variable tags-file-name if it’s nil.

If it’s not nil, we respect existing value of tags-file-name. Please note we don’t support tags-table-list.

Auto update tags file

;; Don't ask before rereading the TAGS files if they have changed
(setq tags-revert-without-query t)
;; Don't warn when TAGS files are large
(setq large-file-warning-threshold nil)
;; Setup auto update now
(add-hook 'prog-mode-hook
  (lambda ()
    (add-hook 'after-save-hook
              'counsel-etags-virtual-update-tags 'append 'local)))

You can change callback counsel-etags-update-tags-backend to update tags file using your own solution,

(setq counsel-etags-update-tags-backend (lambda () (shell-command "find . -type f -iname \"*.[ch]\" | etags -")))

List all tags

M-x counsel-etags-list-tag

Two-step tag matching using regular expression and filter

M-x counsel-etags-find-tag

Open recent tag

M-x counsel-etags-recent-tag

Ctags setup

Google “filetype:ctags”. Here is mine.

You may need configure environment variable “HOME” on Windows because Ctags looks for “%HOME%/.ctags” by default.

Search with negative pattern

All counsel-etags commands supports negative pattern from ivy.

You can filter the candidates with keyword1 !keyword2 keyword3. So we display only candidate containing keyword1 but neither keyword2 nor keyword3.

You can also press C-c C-o to create a buffer containing all candidates.

In summary, all functionality from powerful ivy are supported perfectly.

Grep program

If ripgrep is installed, it’s used as faster grep program. Or else we fallback to grep.

You can use M-x counsel-etags-grep or M-x counsel-etags-grep-symbol-at-point to grep in current project.


No extra setup is needed if you install Cygwin to its default location on any driver except make sure “Exuberant Ctags” has been installed through Cygwin. Or else, you could setup counsel-etags-find-program, counsel-etags-tags-program, and counsel-etags-grep-program.

Bug Report