Citre: 先进的 Ctags 前端

使用与lsp结合的代码时报错了

|  emacs-version | 27.2           |
|  citre         | 20210924.1215  |
|  xref          | 1.2.2          |

||emacs-version|27.2| |ss|sss|

backtrace

Debugger entered--Lisp error: (void-variable fetcher)
  (funcall fetcher)
  (condition-case err (funcall fetcher) ((debug error) (message "%s, fallback to citre" err) nil))
  (or (condition-case err (funcall fetcher) ((debug error) (message "%s, fallback to citre" err) nil)) (funcall citre-fetcher))
  (lambda nil (or (condition-case err (funcall fetcher) ((debug error) (message "%s, fallback to citre" err) nil)) (funcall citre-fetcher)))()
  xref--show-defs-buffer((lambda nil (or (condition-case err (funcall fetcher) ((debug error) (message "%s, fallback to citre" err) nil)) (funcall citre-fetcher))) ((window . #<window 3 on main.c>) (display-action)))
  xref--show-defs((lambda nil (or (condition-case err (funcall fetcher) ((debug error) (message "%s, fallback to citre" err) nil)) (funcall citre-fetcher))) nil)
  xref--find-definitions(#("cache_op_inner" 0 14 (citre-xref-get-at-point t citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.t..." citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main...." citre-syntax function citre-bounds (2349 . 2363))) nil)
  xref-find-definitions(#("cache_op_inner" 0 14 (citre-xref-get-at-point t citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.t..." citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main...." citre-syntax function citre-bounds (2349 . 2363))))
  funcall-interactively(xref-find-definitions #("cache_op_inner" 0 14 (citre-xref-get-at-point t citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.t..." citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main...." citre-syntax function citre-bounds (2349 . 2363))))
  call-interactively(xref-find-definitions nil nil)
  command-execute(xref-find-definitions)

自己加的debutlog打印

citre-fetcher = #[0 "\212\307\303!\203\0\303q\210\3101\0\304b0\202\0\210\202\0\210\306\305\302\"\211\204&\0\311\301\300\"\210\211\262)\207" [#("cache_op_inner" 0 14 (citre-bounds (2349 . 2363) citre-syntax function citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main.c" citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.tags" citre-xref-get-at-point t)) definitions #("cache_op_inner" 0 14 (citre-bounds (2349 . 2363) citre-syntax function citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main.c" citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.tags" citre-xref-get-at-point t)) #<buffer main.c> 2351 citre xref-backend-definitions buffer-live-p (error) xref--not-found-error] 4]
fetcher = #[0 "\212\307\303!\203\0\303q\210\3101\0\304b0\202\0\210\202\0\210\306\305\302\"\211\204&\0\311\301\300\"\210\211\262)\207" [#("cache_op_inner" 0 14 (citre-bounds (2349 . 2363) citre-syntax function citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main.c" citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.tags" citre-xref-get-at-point t)) definitions #("cache_op_inner" 0 14 (citre-bounds (2349 . 2363) citre-syntax function citre-file-path "/mnt/work/src/optee_os/core/arch/arm/plat-ti/main.c" citre-tags-file "/home/schspa/.cache/tags/!mnt!work!src!optee_os!.tags" citre-xref-get-at-point t)) #<buffer main.c> 2351 citre xref-backend-definitions buffer-live-p (error) xref--not-found-error] 4]
Entering debugger...
funcall-interactively: Buffer is read-only: #<buffer *Messages*> [2 times]

配置代码, 从 .emacs.d/init-ctags.el at master · seagle0128/.emacs.d · GitHub 抄来的

;; Ctags IDE on the True Editor
;; @see https://github.com/universal-ctags/citre#quick-start
(when emacs/>=26p
  (use-package citre
    :diminish
    :bind (("C-x c j" . citre-jump+)
           ("C-x c k" . citre-jump-back)
           ("C-x c p" . citre-peek)
           ("C-x c a" . citre-ace-peek)
           ("C-x c u" . citre-update-this-tags-file))
    :init
    (require 'citre-config)
    (setq citre-auto-enable-citre-mode-modes '(prog-mode))

    (defun citre-jump+ ()
      "Jump to the definition of the symbol at point.
Fallback to `xref-find-definitions'."
      (interactive)
      (condition-case _
          (citre-jump)
        (error (call-interactively #'xref-find-definitions))))
    :config
    (with-no-warnings
      (with-eval-after-load 'projectile
        (setq citre-project-root-function #'projectile-project-root))

      ;; Integrate with `lsp-mode' and `eglot'
      (define-advice xref--create-fetcher (:around (fn &rest args) fallback)
        (let ((fetcher (apply fn args))
              (citre-fetcher
               (let ((xref-backend-functions '(citre-xref-backend t)))
                 (ignore xref-backend-functions)
                 (apply fn args))))
          (message "citre-fetcher = %S" citre-fetcher)
          (message "fetcher = %S" fetcher)
          (lambda ()
            (or (with-demoted-errors "%s, fallback to citre"
                  (funcall fetcher))
                (funcall citre-fetcher)))))

      (defun lsp-citre-capf-function ()
        "A capf backend that tries lsp first, then Citre."
        (let ((lsp-result (pcase centaur-lsp
                            ('lsp-mode
                             (and (fboundp #'lsp-completion-at-point)
                                  (lsp-completion-at-point)))
                            ('eglot
                             (and (fboundp #'eglot-completion-at-point)
                                  (eglot-completion-at-point))))))
          (if (and lsp-result
                   (try-completion
                    (buffer-substring (nth 0 lsp-result)
                                      (nth 1 lsp-result))
                    (nth 2 lsp-result)))
              lsp-result
            (citre-completion-at-point))))

      (defun enable-lsp-citre-capf-backend ()
        "Enable the lsp + Citre capf backend in current buffer."
        (add-hook 'completion-at-point-functions #'lsp-citre-capf-function nil t))

      (add-hook 'citre-mode-hook #'enable-lsp-citre-capf-backend))))

你要在你的配置文件里启用 lexical-binding。像这样:

;;; citre-core.el --- A readtags abstraction layer -*- lexical-binding: t -*-
1 个赞

这样可以了 :grinning:

citre-global-gtags-args 在 repo 中好像没有这个变量啊

写文档的时候是有的,后来代码改了,逻辑都放在 citre-global-create-database 里了 :rofl:

稍后我再检查一下文档

我在windows下使用gtags,发现设置parser为pygment后,对非内置语言做gtags --explain尝试,总会收到一个gtags: unexpected EOF.的错误,而且所有的GTAGS文件都是空的。我不太会用gtags,不知道这个是咋回事呢?是我少了啥步骤吗?

谢谢;

详细的错误长什么样,是不是还有个 “No module named pygments.lexers”?

我觉得pygments这个模块应该有的;完整的信息如下:

  • File ‘docs/conf.py’ is handled as follows: suffix: |.py| language: |Python| parser: |parser| library: |pygments-parser| gtags: unexpected EOF.

我感觉这个错误应该还是从 Pygments 插件里出来的。Global 的源码里有个 /global/plugin-factory/pygments_parser.py.in,这个在编译时应该会被转换成 /usr/share/gtags/script/pygments_parser.py(我也不知道 Windows 上会在哪,这个是 pygments 插件的入口,应该调试一下这个文件看看错误是哪抛出来的。我在网上看到一个原因是 shebang 写得不对。之后我也做点实验试试吧

Edit: 这篇文章 是关于 Windows 上用 gtags 的,你要不参考下?好像提到 pygments parser 在 Windows 上的一个 bug 了。

话说你的错误就长这样吗?没有一个 traceback 吗?

我找到错误了。我的cygwin中有python和python3两个版本;python链接的是python2,而pygments模块我安装在python3中,所以应该还是找不到模块;但奇怪的是确实没有报找不到模块的错误; 我把链接改成连接到python3上,就不报错了;我试试看查找怎么样;

另外是我设置了GTAGSOBJDIRPREFIX这个全局变量,好像不起作用?我用gtags --explain后,看到生成的GTAGS三个文件还是在原目录下;这个是不是还需要设置啥才能生效?

谢谢;

gtags 要带 --objdir 参数。

我查了一下–objdir这个选项,好像不支持windows,不知道是不是说明太老了,但是我在windows上确实是设置不成功。 你那边可以试试windows系统吗?或者代码中判断一下非windows系统再在参数中增加–objdir这个选项?我执行create-database会出错,显示gtags: Objdir not found. 目录是提前创建好的,但gtags好像不认识;

你查到哪里说的?

实在不行就不要设那个环境变量呗。

网上有人遇到同样的问题,在回答中说到的,我也不知道对不对,但是去掉这个选项就不报错了;gtags的帮助中确实也没说在windows中不能用。 这个环境变量设不设,只要有–objdir这个选项都会报错。我在shell中尝试也是同样的问题。

你那边有windows环境吗?能不能试试看?

谢谢;

行吧,我试一下

citre-global可以查看definition吗?我看说明里只有查reference的函数? 是不是查definition还需要生成一套tags文件?这样有点重叠了吧?

Ctags 查定义质量比 global 高,我自己也不想用 global 查定义。

Emacs 插件都是完全透明的,而且 citre-global 的实现很简单,完全可以自己满足自己的需求。

lsp-mode 有个lsp-imenu-index-symbol-kinds 配置imenu显示哪些内容。

请问Citre有类似的配置吗?想配置成只显示 函数 和 类

没有。imenu 后端返回的结果本身就是分好类的,我想你是不是用了某些会把结果拍平展示的 UI。