原文 https://maskray.me/blog/2017-12-03-c++-language-server-cquery
Tag system 流派
libparser/C.c
。用 Berkeley DB 存储 definition/reference/path name。带有插件系统可以使用 ctags idutils 的 parser。对于 Emacs/Vim 用户来说,可能是 tag 流派中最好用的工具了。辅以一些 heuristics 和 ripgrep 等,很多用户不觉得自己生活在水深火热中……clang 流派
std::vector
(cquery 风格)足够应对大部分使用场景。很担心他们走上歧路。ReferencesProvider,HoverProvider,DefinitionProvider
,且交互使用可能有极大延迟。大多数人并不在意 C++ Haskell Python 代码间无缝跳转。info,symbols,symnames,targets,tokens,usrs
(过多),没有使用 in-memory 索引,查找引用请求会读项目所有 translation units 的文件。导致性能低下https://github.com/Andersbakken/rtags/issues/1007。std::vector
(src/indexer.h
)。有一些 Emacs 用户积极贡献code navigation 功能。IDE(Any sufficiently complicated IDE contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of C++.)
https://github.com/jacobdufault/cquery。Arch Linux 可用aur/cquery-git。
textDocument/hover
请求,language server 返回变量 /函数声明信息textDocument/definition
请求textDocument/references
请求textDocument/documentSymbol
请求workspace/symbol
请求textDocument/completion
textDocument/didChange
安装lsp-mode,参照https://github.com/jacobdufault/cquery/wiki/Emacs配置。lsp-mode 会设置xref-backend-functions
,把以下函数
xref-find-definitions
(默认M-.
),对应textDocument/definition
xref-find-references
(默认M-?
),对应textDocument/references
xref-find-apropos
(默认M-?
),对应workspace/symbol
textDocument/documentSymbol
定向到 lsp-mode 中的处理函数,发送textDocument/definition
等请求并渲染。
如果使用helm,可以考虑安装helm-xref,xref-show-xrefs-function
会使用helm-xref-show-xrefs
。但目前有两个 issues 影响了我的使用体验:
xref-prompt-for-identifier
添加到xref-prompt-for-identifier
,https://github.com/emacs-lsp/lsp-mode/issues/194。注意协议中定义返回结果为Location[] | null
,只含位置信息,不包含代码行内容,如果要显示行内容。若文件在某个 buffer 内,则显示该 buffer 相应行;若未打开则需要打开该文件。
Emacs Lisp dynamic scoping 使得我们可以很容易复用已有代码。可以基于 evil-jumps 做一个用于 xref 的 jump list。我喜欢 xref jump list 和正常 jump list 分离。因为查找定义 /引用后会进行一些局部跳转,喜欢有快捷键回到定义 /引用跳转前的位置。并且需要能双向移动,不能只是 jump stack,xref.el
用 ring buffer 实现的是 stack。
(defmacro my-xref//with-evil-jumps (&rest body)
"Make `evil-jumps.el' commands work on `my-xref--jumps'."
(declare (indent 1))
`(let ((evil--jumps-window-jumps ,my-xref--jumps))
,@body))
(with-eval-after-load 'evil-jumps
(evil-define-motion my-xref/evil-jump-backward (count)
(my-xref//with-evil-jumps
(evil--jump-backward count)
(run-hooks 'xref-after-return-hook)))
(evil-define-motion my-xref/evil-jump-forward (count)
(my-xref//with-evil-jumps
(evil--jump-forward count)
(run-hooks 'xref-after-return-hook))))
最近的新包https://github.com/emacs-lsp/lsp-ui包含 code lens、flycheck 等功能,以及一个基于quick-peek的find-{definitions,references,apropos}
。
https://github.com/MaskRay/Config/blob/master/home/.emacs.d/layers/%2Bmy/my-code/funcs.el
reference-handler
(类似于跳转到定义的jump-handler
)也很有用: https://github.com/syl20bnr/spacemacs/pull/9911(setq-local eldoc-documentation-function ...)
,对于这类 minor-mode 冲突问题,如果能设置优先级就能优雅解决。参照https://github.com/autozimu/LanguageClient-neovim/wiki/cquery
nn <leader>ji :Denite documentSymbol<cr>
nn <leader>jI :Denite workspaceSymbol<cr>
" 终端限制,<C-,>不可用。ord(`,`) & 64 为 0 无法表示
nn <M-,> :Denite references<cr>
nn <silent> <C-j> :MarkPush<cr>:call LanguageClient_textDocument_definition()<cr>
不清楚怎么把定义 /引用改造成使用可双向移动的 jump list。
% mkdir build
% (cd build; cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=YES ..)
% ln -s build/compile_commands.json
Bear is a tool that generates a compilation database for clang tooling. It can be used for any project based on Makefile
.
bear make
# generates compile_commands.json
ninja -t compdb rule_names... > compile_commands.json
SQLITE_ENABLE_LOCKING_STYLE
、flock 很难。索引 Linux kernel
wget 'https://git.archlinux.org/svntogit/packages.git/plain/trunk/config?h=packages/linux' -O .config
yes '' | make config
bear make -j bzImage modules
生成 3GiB 文件。
索引 llvm,du -sh => 1.1GB
,索引完内存占用 2G。
查看 LSP requests/responses
sudo sysdig -As999 --unbuffered -p '%evt.type %evt.buffer' "proc.pid=$(pgrep -fn build/app) and fd.type=pipe" | egrep -v '^Content|^$'
生成compile_commands.json,参考https://github.com/jacobdufault/cquery/wiki。
希望有朝一日 Debug Protocol 也能获得重视,https://github.com/Microsoft/vscode-debugadapter-node/blob/master/protocol/src/debugProtocol.ts,让realgud轻松一点。
和 YouCompleteMe 等项目一样,cquery 默认下载prebuilt clang+llvm,即.h .so .a
。用户不需要编译完整的 llvm,开发门槛比 clangd 低。
感谢 ngkaho1234。
1
glacier2002 2017-12-09 16:30:09 +08:00
完全没看懂。。。。
|
2
htfy96 2017-12-09 16:40:07 +08:00 via Android
cquery 感觉的确是现代的方案…时间不太够只能维护下 cquery-git 了
|
3
forestyuan 2017-12-09 21:46:23 +08:00
这是来推广的吗?
|
4
MaskRay OP @glacier2002 原文裏有幾張圖,內容改了點……這裏編輯困難
|
5
MaskRay OP @forestyuan 是的。希望能找到更多有 C/C++代碼閱讀需求的 geek 用戶貢獻這個項目。很多 code assistant 功能靠 clangd 這種大教堂模式是搞不好的
|
6
YeT9 2017-12-10 10:23:58 +08:00
Ray 教授啊!火钳流明~资瓷一个~
|
7
congeec 2017-12-10 11:18:29 +08:00
cquery 目前 hover definition 不能显示函数签名,跟 YouCompleteMe 比还差好多。不过能重构,也是屌屌的
|
8
ivechan 2017-12-10 15:48:00 +08:00
之前试用了一下 clangd, 实在太难用了,有时候性能极差,还不如直接用 fzf ack 这类工具。
|
9
skt041959 2017-12-10 16:54:48 +08:00
LanguageClient-neovim 是 rust 写的,没法编译。试了一下 vim-lsp 好像不会用。有其他支持的 vim/neovim LSP plugin 么?
|
10
bookit 2017-12-10 20:03:44 +08:00
善,哪一天能赶上 vax 就好了。
|
13
ivechan 2017-12-22 15:27:20 +08:00
之前看了但是还没尝试, 今天去尝试了一下, 在 vim 下体验比其他的好。谢谢。
|
14
5thcat 2018-01-06 01:52:11 +08:00
非常感谢! 终于找到了失散多年的阅读代码工具!
|
15
skt041959 2018-01-08 13:23:44 +08:00
@autozimu #11 之前理解错了,以为必须编译 rust 才能用。其实不用编译,直接用 python 的就可以了
|
16
bef0rewind 2018-01-26 09:40:55 +08:00
很有意思的项目啊
|
17
f2ed 2018-04-18 17:38:07 +08:00
我用的 vscode-cquery,表示 C++符号经常找不到啊,c 语言还可以
|
18
MaskRay OP 原來都已經半年了……我現在用自己的 fork https://github.com/MaskRay/ccls 了
移除了不必要的第三方依賴 import_pipeline.cc 比原來簡單的多,效果更好(index merge, id map 都是 cquery 中不妥當的設計,我上週移除了) mem index 有少量提升 https://github.com/autozimu/LanguageClient-neovim/issues/293 自定義 cross reference 能支持就最好了 |