Citre: 先进的 Ctags 前端

赞!我想你的 ignore-case 应该是写反了 :rofl:

太感谢了!我这周末的时候试试,暂时先用着懒猫大神的方法。我也看到后面有很多其他方式,我到时候也学习下~

:rofl: 没注意, 修改了

我知道了,原因是 lsp 即使不能给你补全符号,它的 backend 函数也会返回一大堆乱糟糟的结果而不是 nil。我再研究下。

@Youmu @songpeng 试一下这个。我在自己这测试通过了:

;; If you keep this as non-nil, `citre-mode' will override the combined backend
;; with its own (Citre only) capf backend.
(setq-default citre-enable-capf-intergration nil)

(defun lsp-citre-capf-function ()
  "A capf backend that tries lsp first, then Citre."
  (let ((lsp-result (lsp-completion-at-point)))
    (if (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))

现在没想好应该加在哪个 hook 里。即使加在 lsp-mode-hook 里,call lsp 之后 capf 后端还是会被盖掉。暂时需要启用 lsp 之后在当前 buffer 手动 call 一下 enable-lsp-citre-capf-backend

Edit: 暂时用 advice 解决了:

(define-advice lsp (:around (fn &rest args) lsp-citre-capf)
  (apply fn args)
  (enable-lsp-citre-capf-backend))

熟悉 lsp 的高手们有没有稍微普通一点的办法?

More edit: 话说我这个实现是先尝试 lsp,没有结果再用 Citre。大家究竟是想要这样的功能,还是想要把 lsp 和 Citre 的结果揉在一起呢?

3 个赞

其实 citre-ace-peek 之后敲一下回车就是抓当前符号 :rofl:

我在python 里面,开启了lsp后 completion-at-point-functions is a variable defined in ‘minibuffer.el’. Its value is (lsp-citre-capf-function lsp-completion-at-point), 这是否意味着其实lsp的completation 操作了两次? lsp的使用中,我没有配置过completation的事情,所以可能后面那个lsp-completion-at-point是lsp自动加入的?

另外手动call enable那个函数,是不是得加入interactive? 不过,后面有advice的使用,应该也就不需要这里手动了,多谢。

不会。除非后端有特别的设置,这个列表里的函数只会执行第一个。

你也许会问那为什么需要一个列表?实际上按 Emacs 的设计,后端可以告诉 Emacs:当我找不到定义,你就试试下一个函数。但是 Emacs 实现上有 bug,导致实际上不太可用。看这里

1 个赞

多谢。我在python中,如果写注释 ## filter blabla,在写的过程中, 会出现Company: backend company-capf error "Wrong type argument: integer-or-marker-p, nil" with args (prefix)。 在其他位置补全则没有这个错误,请问你知道这个可能是什么原因么?

不知道,下班帮你看看。

我更想了解一下这个问题:

嗯嗯,多谢。我想对于你感兴趣的问题,不同人可能倾向不同。对我来说,

  1. 我充分喜欢lsp,它目前的速度,补全能力,代码调转,代码refactor等都非常好用 (我主要利用lsp for python and R)。
  2. 我使用citre 主要是为了
  • jump 某些corner case (lsp work 不好的时候,如同一文件夹下,python调用另一个文件的成员,有时候lsp就不知所措,甚至还说我用的那个同文件夹下的module找不到)。这时候ctags 工作得很好。
  • citre peek,这个确实对于读代码很舒服。
  1. 所以回到补全上,我肯定是优先lsp,其次是citre。
2 个赞

:rofl: 我刚想到一个技巧,应该可以把「lsp 失败了再用 Citre 补」和「两个都用,结果放一起」 各自都实现了。

1 个赞

我今天在公司的代码库上试了一下,感觉ctags的索引速度有点慢。如果不选择语言的话,运行了太久我没耐心Ctrl-C了。选择只索引C++语言的话依然运行了好几分钟。我看了下CPU占用量,并没有用满所有的核心。我找了一下手册也没发现有什么选项可以启用多线程。不知将来是不是有可能加入多线程索引功能?

1 个赞

如果在windows上用 Universal Ctags,生成项目的TAGS传的参数是不是一样。记得以前在linux上生成了TAGS,但是相同方法在windows下没成功。

目前没有多线程,不好说将来有没有。我之前见过一个这个:GitHub - dalance/ptags: A parallel universal-ctags wrapper for git repository ,应该是 ctags 的一个多进程 wrapper,你要不试一下?

你在 Windows 上是用 cmd、PowerShell 还是 bash?

我对 Windows 没啥经验。我在给 Citre 添加一个生成 tags 的向导,是直接用进程来调 ctags 的,不需要经过命令行。如果不急的话可以等这个完成再用。

我是用windows下原生的emacs,用cmd来调Universal Ctags生成TAGS。那应该是我记错了,之前将emacs的bin目录下加到了环境变量。命令行生成的时候,用了bin目录的ctag来生成。后来我写了个函数,不过只会简单的调命令。灵活的我就不会了。

(setq path-to-ctags "d:/DevTools/ctags/ctags.exe") 
(defun my-create-tags ()
"Create tags file."
(interactive)
(let ((select-dir (read-directory-name "Select root directory: "))
      (select-language (read-string "Input language: ")))
  (shell-command (format "%s -f TAGS --languages=%s -e -R %s" path-to-ctags select-language (directory-file-name select-dir))))
)

能做个生成ctags就很好,因为我觉得哪些参数好多,蛮灵活的。

Windows 系统上生成的tags文件得改名为.tags ,不然 Emacs 会认为是TAGS,因为Windows 平台不区分大小写的。

1 个赞

开着 peek 但是光标一直移动到最下面的时候好像有些问题, 但是我不知道怎么描述好