Citre 在Emacs 中的使用

Citre 是基于ctags 的Emacs 自动补全前端, 可以提供代码跳转和自动补全功能, 后端基于 ctags 或者 universal-ctags
由于在Emacs 中一直没有把 verilog 的 LSP 用起来, 之前用的是gtags, Citre 比gtags 定制性更好些, 而且速度更快

下载 Citre 到本地

1
2
cd ~/.doom.d/elisp/
git clone https://github.com/universal-ctags/citre.git

安装Ctags

看 Citre 的Readme

Windows

https://github.com/universal-ctags/ctags-win32
下载最新的Ctags 解压后记住路径 配置Emacs 中用到

查看当前ctgas 支持多少种语言
ctags --list-languages | wc -l

Macos

1
brew install --HEAD universal-ctags/universal-ctags/universal-ctags

Linux

自行编译

配置Emacs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
(use-package! citre
  :defer t
  :load-path "~/.doom.d/elisp/citre"
  :init
  ;; This is needed in `:init' block for lazy load to work.
  (require 'citre-config)
  ;; Bind your frequently used commands.  Alternatively, you can define them
  ;; in `citre-mode-map' so you can only use them when `citre-mode' is enabled.
  :config
  (map!
   (:map verilog-mode-map
    ;; Navigation
    "C-/"     #'citre-peek
    "M-]"     #'citre-jump
    "M-["     #'citre-jump-back
    ;; "M-<f12>"     #'helm-gtags-find-rtag
    ;; "C-M-]"     #'helm-gtags-find-tag
    ;; "C-M-t"     #'helm-gtags-find-tag-other-window)
    ;; "C-c c" #'my/verilog-compile-only
    "C-c c" #'my/run-vcs-with-compile
    "C-c a" #'my/verilog-compile-download
    "C-c d" #'my/verilog-download
    "C-c l" 'my/find-vcs-sim-log-file
    "C-c m" 'my/run-modelsim-nogui
    "C-c M" 'my/run-modelsim-gui
    "C-c s" 'my/run-vcs-with-nogui
    "C-c S" 'my/run-vcs-with-gui
    "C-c k" 'my/kill-vcs-modelsim-gui-process
    "C-c A" 'my/open-anlogic-prj
    "C-c q" 'my/open-quartus-prj
    ))
  ;; Set these if readtags/ctags is not in your path.
  (cond ((file-exists-p "E:\\work\\tools\\ctags-p5.9.20210905.0-x64\\ctags.exe")
         (setq
          citre-readtags-program "E:\\work\\tools\\ctags-p5.9.20210905.0-x64\\readtags.exe"
          citre-ctags-program "E:\\work\\tools\\ctags-p5.9.20210905.0-x64\\ctags.exe"))
        ((file-exists-p "/usr/local/bin/ctags")
         (setq
          citre-readtags-program "/usr/local/bin/readtags"
          citre-ctags-program "/usr/local/bin/ctags"))
        )
  (setq
   ;; Set this if you use project management plugin like projectile.  It's
   ;; used for things like displaying paths relatively, see its docstring.
   citre-project-root-function #'projectile-project-root
   ;; Set this if you want to always use one location to create a tags file.
   citre-default-create-tags-file-location 'global-cache
   ;; See the "Create tags file" section above to know these options
   citre-use-project-root-when-creating-tags t
   citre-prompt-language-for-ctags-command t
   ;; By default, when you open any file, and a tags file can be found for it,
   ;; `citre-mode' is automatically enabled.  If you only want this to work for
   ;; certain modes (like `prog-mode'), set it like this.
   citre-auto-enable-citre-mode-modes '(verilog-mode)
   citre-edit-cmd-buf-default-cmd "ctags\n-o\n%TAGSFILE%\n--languages=[verilog,systemverilog]\n--kinds-all=*\n--fields=*\n--extras=*\n
;; exclude file or dir use --exclude=   can use multi line
-R\n;; add dirs/files to scan here, one line per dir/file\n"
   )

  (defun my/citre-jump ()
    "Jump to the definition of the symbol at point.
        When there's multiple definitions, it lets you pick one using the
        `completing-read' UI, or you could use your own UI by customizing
        `citre-select-definition-function'.
     append add goto keyword pos "
    (interactive)
    (let* ((marker (point-marker))
           (symbol (citre-get-symbol))
           (definitions
             (citre-get-definitions-maybe-update-tags-file symbol))
           (root (funcall citre-project-root-function)))
      (when (null definitions)
        (user-error "Can't find definition for %s" symbol))
      (citre-jump-show symbol definitions marker root)
      ;; 跳到symbol 处
      (beginning-of-line)
      (search-forward symbol (line-end-position) t)
      (backward-char)
      (unless (citre-tags-file-path)
        (setq citre--tags-file
              (with-current-buffer (marker-buffer marker)
                (citre-tags-file-path))))))
  (advice-add #'citre-jump :override #'my/citre-jump))

简单用法

确保该工程没有用citre 建立过 tags, 如果有建立则先删除, 一般会存在 ~/.cache/tags 目录下

直接在工程里打开任意文件, M-x: citre-update-this-tags-file 输入语言, 如果有多种语言, 用逗号隔开, 如: verilog,systemverilog 大小写不敏感

如果不知道具体的语言, 可以使用 citre-edit-cmd-buf-add-lang 查看

回车即可在 ~/.cache/tags 下生成对应的tags 文件

修改ctags 参数

M-x: citre-edit-tags-file-recipe

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
;; Edit the command line for creating the tags file
;;
;; Syntax:
;;
;; - One command line argument in one line
;; - Lines start with ;; are ignored
;; - Use %TAGSFILE% to refer to the tags file
;; - "%" (other than those in %TAGSFILE%) and "\" need escaping
;;
;; Commands:
;;
;; - C-c l: Insert a language (needs Universal Ctags)
;; - C-c f: Insert a dir or file
;; - C-c C-c: Commit
;; - C-c C-k: Cancel

ctags
-o
%TAGSFILE%
--languages=verilog,systemverilog
--kinds-all=*
--fields=*
--extras=*
--exclude=simulation/*
--exclude=src/spi/spi_ctrl_quad.v
--exclude=src/psram/*
-R

如果要排除掉一些文件 可以使用 –exclude 选项, 如果要排除多个目录需用多个 –exclude
更多参数配置参考 ctags --help

更新 tags 文件

M-x: citre-update-this-tags-file

跳转到定义

M-] citre-jump

跳转后返回

M-[ citre-back

不离当前文件查看定义

C-/ citre-peek

Citre 的一个BUG ( 打开verilog 文件导致Emacs 卡死 )

当打开某些含有很多`define 语句的 .svh 或者 .sv 文件时, 使用默认的配置的话, 很容易导致Emacs 卡死( C-g 都无解 )
最后通过二分法最终查到了 citre 的 citre-config.el 头上

解决办法

把 citre-config.el 里面的

1
(add-hook 'find-file-hook #'citre-auto-enable-citre-mode)

注释掉