• Stars
    star
    173
  • Rank 213,349 (Top 5 %)
  • Language
    Emacs Lisp
  • Created over 6 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fast, energy-saving, and powerful code navigation solution

counsel-etags

https://github.com/redguardtoo/counsel-etags/actions/workflows/test.yml/badge.svg http://melpa.org/packages/counsel-etags-badge.svg http://stable.melpa.org/packages/counsel-etags-badge.svg

Fast, energy-saving, and powerful code navigation solution.

It’s been tested on Linux/Windows/macOS.

demo.png

Table of Content

Install

Please install counsel-etags from MELPA.

If Exuberant Ctags or Universal Ctags exists, this program works out of box.

Universal Ctags is actively maintained and strongly recommended.

Or else, customize counsel-etags-update-tags-backend to create tags file with your own CLI. Please note etags bundled with Emacs is not supported anymore.

It’s reported “Exuberant Ctags” v5.8.5 is buggy.

Usage

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

This command will:

  • Find project root folder and scan code automatically
  • Find correct tag automatically
  • If no tag is find, ripgrep or grep is automatically called

Please note it takes time to parse tags file contains long lines. It’s the known issue of Emacs Lisp.

You could run M-x counsel-etags-scan-code only once and create tags file in your own way.

Please read Step by step guide for more details.

Tips (OPTIONAL)

Jump back

Run M-x pop-tag-mark to jump back.

Native Windows Emacs

The grep program path on Native Windows Emacs uses either forward slash or backward slash. Like “C:/rg.exe” or “C:\\rg.exe”.

If grep program path is added to environment variable PATH, you don’t need worry about slash problem.

“.gitignore” and “.hgignore” are respected

The variable counsel-etags-ignore-config-file specifies the paths of ignore configuration files (“.gitignore”, “.hgignore”, etc).

The path is either absolute or relative to the tags file.

Set counsel-etags-ignore-config-files to nil to turn off this feature.

Set up with use-package

Please place add-hook code inside :init section,

(use-package counsel-etags
  :ensure t
  :bind (("C-]" . counsel-etags-find-tag-at-point))
  :init
  (add-hook 'prog-mode-hook
        (lambda ()
          (add-hook 'after-save-hook
            'counsel-etags-virtual-update-tags 'append 'local)))
  :config
  (setq counsel-etags-update-interval 60)
  (push "build" counsel-etags-ignore-directories))

Insert extra content into tags file after it’s updated

counsel-etags-find-tag-name-function finds tag name at point. If it returns nil, find-tag-default is used. counsel-etags-word-at-point returns the word at point.

User could append the extra content into tags file in counsel-etags-after-update-tags-hook.

The parameter of hook function is full path of the tags file.

counsel-etags-tag-line and counsel-etags-append-to-tags-file are helper functions to update tags file in the hook,

Sample code to append native javascript API “addEventListener”, “dispatchEvent”, “removeEventListener” into tags file,

(defun my-update-tags-file (tags-file)
  "Update TAGS-FILE."
  (when (memq major-mode '(js-mode typescript-mode js2-mode))
    (let ((s3 (mapconcat (lambda (tagname)
                           (counsel-etags-tag-line tagname tagname 0))
                         '(addEventListener
                           dispatchEvent
                           removeEventListener) "")))
      (counsel-etags-append-to-tags-file
       (list (cons "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/%s" s3))
       tags-file))))
(add-hook 'counsel-etags-after-update-tags-hook 'my-update-tags-file)

Configuration file

Path of the configuration file is defined in counsel-etags-ctags-options-file whose value is ~/.ctags.

Exuberant Ctags actually can NOT open configuration file “.ctags” through cli option.

We use Emacs Lisp to load ~/.ctags to workaround this issue.

Please use file name like ctags.cnf instead .ctags when customize this variable for Exuberant Ctags.

Universal Ctags does NOT have this problem.

Ignore directories and files

You can set up counsel-etags-ignore-directories and counsel-etags-ignore-filenames,

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

Dependency on Emacs APIs is minimum

I intend to keep this package completely independent.

Many native tag API or variable (tags-file-name, tags-table-list, visit-tags-table, xref-find-references, etc) are not used.

Specify multiple tags files

counsel-etags-extra-tags-files contains extra tags file to parse.

Sample setup,

(setq counsel-etags-extra-tags-files '("/usr/include/TAGS" "/usr/local/include/TAGS"))

Files in counsel-etags-extra-tags-files should have symbols with absolute path only.

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 (src-dir) (shell-command "/usr/bin/ctags -e -R")))

Rust programming language

Tags file for Rust programming language can be generated by rusty-tags.

Run rusty-tags emacs in shell to generate tags file. You also need (setq counsel-etags-tags-file-name "rusty-tags.emacs").

The easiest way to set up rusty-tags per project is to create .dir-locals.el in project root,

((nil . ((counsel-etags-update-tags-backend . (lambda (src-dir) (shell-command "rusty-tags emacs")))
         (counsel-etags-tags-file-name . "rusty-tags.emacs"))))

List all tags

M-x counsel-etags-list-tag

Two-step tag matching using regular expression and filter

M-x counsel-etags-find-tag

Force update current tags file

Run counsel-etags-update-tags-force. Tags file in project root should exist before running this command.

Open recent tag

M-x counsel-etags-recent-tag

Ctags setup

Google “filetype:ctags site:github.com”. Here is my configuration for Exuberant Ctags.

Please note there is some trivial difference between Exuberant Ctags configuration and Universal Ctags.

If you are using Universal Ctags with my configuration for Exuberant Ctags, run below CLI in shell and fixed all the warning by modifying the ~/.ctags first,

ctags --options="$HOME/.ctags" -e -R

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

Search with exclusion patterns

All commands support exclusion patterns from ivy.

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

You can press C-c C-o or M-x ivy-occur to export candidates to a buffer.

In summary, all functionalities from ivy are supported.

Grep program

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

Use M-x counsel-etags-grep to grep in project root which is automatically detected. If current file is org file, current node or parent node’s property GREP_PROJECT_ROOT is read to get the root directory to grep.

Set counsel-etags-grep-extra-arguments to add extra arguments for grep.

Use M-x counsel-etags-grep-current-directory to grep current directory.

Use C-u num M-x counsel-etags-grep-current-directory to grep NUM level up of current directory. If NUM is nil or 0, current directory is searched.

Grep result is sorted by string distance of current file path and candidate file path. The sorting is enabled in Emacs 27+.

You can set counsel-etags-sort-grep-result-p to nil to disable sorting.

Customize grep keyword

Users could set counsel-etags-convert-grep-keyword to customize grep keyword.

For example, below setup enable counsel-etags-grep to search Chinese using pinyinlib,

(unless (featurep 'pinyinlib) (require 'pinyinlib))
(setq counsel-etags-convert-grep-keyword
  (lambda (keyword)
    (if (and keyword (> (length keyword) 0))
        (pinyinlib-build-regexp-string keyword t)
      keyword)))

Or create a new grep command my-grep-by-pinyin,

(defun my-grep-by-pinyin ()
  (interactive)
  (unless (featurep 'pinyinlib) (require 'pinyinlib))
  (let* ((counsel-etags-convert-grep-keyword
          (lambda (keyword)
            (if (and keyword (> (length keyword) 0))
                (pinyinlib-build-regexp-string keyword t)
              keyword))))
    (counsel-etags-grep)))

Windows

Installing Cygwin and its package Ctags on any driver is all you need to do. No extra setup is required.

But you could still set up counsel-etags-find-program, counsel-etags-ctags-program, and counsel-etags-grep-program to specify the command line program path.

~/.ctags.exuberant

If base configuration file “~/.ctags.exuberant” exists, it’s used to generate “~/.ctags” automatically.

”~/.ctags.exuberant” is in Exuberant Ctags format, but the “~/.ctags” could be in Universal Ctags format if Universal Ctags is used.

You can customize counsel-etags-ctags-options-base to change the path of base configuration file.

Use Ctags to generate Imenu items

Run M-x counsel-etags-list-tag-in-current-file to list tags in current file.

You can also use native imenu command with below setup,

(setq imenu-create-index-function 'counsel-etags-imenu-default-create-index-function)

Set counsel-etags-imenu-excluded-names to exclude imenu items by name.

Set =counsel-etags-imenu-excluded-types to exclude imenu items by type.

Step by step guide

You need use Linux/Cygwin/MSYS2. It should be similar in macOS but I’m not sure whether the directory /usr/include exists.

Step 1, a toy C project

Run below script in Bash shell to create a toy project.

#!/bin/bash
mkdir -p ~/proj1 && cd ~/proj1
cat > .dir-locals.el <<EOF
((nil . ((counsel-etags-project-root . "$PWD")
         (counsel-etags-extra-tags-files . ("./include/TAGS")))))
EOF
cat > hello.c <<EOF
include <stdio.h>

void fn() {
}

int main() {
    printf('hello world');
    fn();
    return 0;
}
EOF
mkdir -p include && cd include && find /usr/include | ctags -e -L -

Step 2, navigate code

Open hello.c in Emacs (say “YES” if Emacs ask any question), move focus over symbol “fn” or “printf”, run counsel-etags-find-tag-at-point.

Bug Report

Report bugs to https://github.com/redguardtoo/counsel-etags.

More Repositories

1

mastering-emacs-in-one-year-guide

Be great at emacs in one year
6,330
star
2

emacs.d

Fast and robust Emacs setup.
Emacs Lisp
2,375
star
3

find-file-in-project

Quick access to project files in Emacs
Emacs Lisp
426
star
4

evil-nerd-commenter

Comment/uncomment lines efficiently. Like Nerd Commenter in Vim
Emacs Lisp
387
star
5

elpa-mirror

Create local emacs package repository. 15 seconds to install 115 packages.
Emacs Lisp
304
star
6

evil-matchit

Vim matchit ported into Emacs
Emacs Lisp
283
star
7

cpputils-cmake

Easy real time C++ syntax check and intellisense if you use CMake
Emacs Lisp
192
star
8

wucuo

Fastest solution to spell check camel case code or plain text
Emacs Lisp
119
star
9

eacl

eacl - Emacs auto complete lines by grepping project
Emacs Lisp
97
star
10

vc-msg

Show commit message of current line in Emacs
Emacs Lisp
75
star
11

cliphist

Paste from clipboard manager into Emacs
Emacs Lisp
73
star
12

js-comint

js-comint will send the code from Emacs into node.js or rhino
Emacs Lisp
67
star
13

company-ctags

Fastest Emacs auto-completion using Company and Ctags
Emacs Lisp
52
star
14

pyim-tsinghua-dict

用清华大学开放中文词库数据建立的pyim 输入法]词库. 已基于词频统计信息DF值(Document Frequency)优化
Python
47
star
15

mybigword

Use Zipf frequency of each word to extract English big words
Emacs Lisp
36
star
16

org2nikola

export org into html used by static blog generator like https://github.com/getnikola/nikola
Emacs Lisp
26
star
17

myelpa

Mirror of Emacs packages I'm using
23
star
18

vscode-setup

21
star
19

gmail2bbdb

convert gmail contacts to BBDB file, easy to use, robust, no dependency
Emacs Lisp
20
star
20

vscode-matchit

Jump between matching HTML tags and brackets smartly in VS Code. It's ported from Vim matchit by Benji Fisher
TypeScript
19
star
21

find-by-pinyin-dired

Find file by first Pinyin characters of Chinese Hanzi. 输入拼音首字母定位对应的中文目录/文件
Emacs Lisp
18
star
22

imenu-extra

Add extra items into lsp-mode/js2-mode imenu items
Emacs Lisp
15
star
23

redguardtoo.github.io

my blog
HTML
14
star
24

NinjaWebCoder

Use keyboard to copy code from stackoverflow
HTML
14
star
25

pyim2fcitx

Conver pyim dictionary to fcitx dictionary
Python
12
star
26

dianyou

Search/Analyze mails in Gnus
Emacs Lisp
12
star
27

test-git-mergetool

toy project to test git mergetool
12
star
28

lazyflymake

Lightweight syntax checker for Emacs, alternative of `flymake-mode'
Emacs Lisp
11
star
29

evil-mark-replace

replace string in marked region effectively
Emacs Lisp
9
star
30

shellcop

Analyze errors reported in Emacs builtin shell
Emacs Lisp
9
star
31

counsel-bbdb

Quick search&input email from BBDB based on ivy
Emacs Lisp
9
star
32

js2hl

Highlight/rename things using `js2-mode' parser
Emacs Lisp
8
star
33

shenshou

download subtitles from opensubtitles.org
Emacs Lisp
8
star
34

spell-check-code-in-ci

Free and powerful solution to spell check code at Continuous integration server
Makefile
7
star
35

fastdef

Insert terminology faster
Emacs Lisp
6
star
36

root-dotfiles

my dotfiles as root at Linux host
Shell
6
star
37

jqcuo

Powerful and simple solution to spell check code in command line
Emacs Lisp
6
star
38

jest-coverage-for-files-outside-of-root

jest coverage for files outside of root
JavaScript
5
star
39

diff-lisp

Diff files&strings in pure Emacs Lisp.
Emacs Lisp
5
star
40

find-and-ctags

Use `find' and `ctags' for code navigation
Emacs Lisp
5
star
41

portable-percol

portable percol (https://github.com/mooz/percol)
Python
5
star
42

zhfreq

processing chinese text using word frequency data
Emacs Lisp
4
star
43

AX88772C_Source

my usb to net adapter
C
4
star
44

my-emacs.d-snapshot

Emacs Lisp
4
star
45

test-git-blame

A project to test git blame
JavaScript
3
star
46

roblox-mode

Emacs major mode to edit Roblox Studio rbxlx files
Emacs Lisp
3
star
47

org-mime

org html export for text/html MIME emails
3
star
48

perl-recordmydesktop

perl-recordmydesktop.pl is the frontend for recordMyDesktop screencast tool
Prolog
3
star
49

test-git-log

JavaScript
1
star
50

asus-pce-n53-11n-n600

ASUS PCE-N53 wireless patched driver and gentoo installation mini-guide
C
1
star
51

ms-frontend-sandbox

sandbox for interviewers
JavaScript
1
star
52

helloworld

hello world
C
1
star
53

wxwidgets-help

Look up wxWidgets API in Emacs by using local html manual
Emacs Lisp
1
star