How to use ctags in Emacs effectively
Exuberant Ctags is used for code completion and code navigation. It supports many programming languages.
Please read EmacsWiki for basic usage.
Ctags creates an index file named "TAGS". The path of TAGS is stored in a Emacs variable
(setq tags-table-list '("~/wxWidgets-master/TAGS" "~/projs/Loris/src/desktop/TAGS"))
M-x find-tag, the tag files in
tags-table-list is read to find the definition of the symbol under cursor.
Here is my strategy to manage TAGS automatically:
- I hard coded path of TAGS in
.emacsbecause I don't change project path frequently
- In major mode hook like
js2-mode-hookI check the path current file. If it matches project name, the file is part of the project
- TAGS for the project is created
- When saving the file, update TAGS by the value of
(defun my-project-name-contains-substring (regex) (let ((dir (if (buffer-file-name) (file-name-directory (buffer-file-name)) ""))) (string-match-p regex dir))) (defun my-create-tags-if-needed (SRC-DIR &optional FORCE) "Return the full path of tags file." (let ((dir (file-name-as-directory (file-truename SRC-DIR)) ) file) (setq file (concat dir "TAGS")) (when (or FORCE (not (file-exists-p file))) (message "Creating TAGS in %s ..." dir) (shell-command (format "ctags -f %s -e -R %s" file dir))) file)) (defvar my-tags-updated-time nil) (defun my-update-tags () "Check the tags in tags-table-list and re-create it." (interactive) (dolist (tag tags-table-list) (my-create-tags-if-needed (file-name-directory tag) t))) (defun my-auto-update-tags-when-save () (interactive) (cond ((not my-tags-updated-time) (setq my-tags-updated-time (current-time))) ((< (- (float-time (current-time)) (float-time my-tags-updated-time)) 300) ;; < 300 seconds ;; do nothing ) (t (setq my-tags-updated-time (current-time)) (my-update-tags) (message "updated tags after %d seconds." (- (float-time (current-time)) (float-time my-tags-updated-time)))))) (defun my-setup-develop-environment () (when (my-project-name-contains-substring "Loris") (cond ((my-project-name-contains-substring "src/desktop") ;; C++ project don't need html tags (setq tags-table-list (list (my-create-tags-if-needed (concat (file-name-as-directory (getenv "WXWIN")) "include")) (my-create-tags-if-needed "~/projs/Loris/loris/src/desktop")))) ((my-project-name-contains-substring "src/html") ;; html project donot need C++ tags (setq tags-table-list (list (my-create-tags-if-needed "~/projs/Loris/loris/src/html"))))))) (add-hook 'after-save-hook 'my-auto-update-tags-when-save) (add-hook 'js2-mode-hook 'my-setup-develop-environment) (add-hook 'web-mode-hook 'my-setup-develop-environment) (add-hook 'c++-mode-hook 'my-setup-develop-environment) (add-hook 'c-mode-hook 'my-setup-develop-environment)
UPDATE: Ctags is discussed at Google Plus. Kaushal Modi recommended three Emacs plugins:
I tried them. My code has same features as
etags-table. I prefer my own code because it's simpler and controllable.
But I do like
etags-select, it provides better UI for finding tag and I will use it from now on.
UPDATE: I have developed my own ctags solution for Emacs,
- counsel-etags for code navigation and imenu
- company-ctags for code completion