# pkg install ccls
在 FreeBSD 源代码树中使用语言服务器进行开发
目录
1. 简介
本指南介绍如何在 FreeBSD 源代码树中设置语言服务器以执行源代码索引。本指南描述了 Vim/NeoVim 和 VSCode 的步骤。如果您使用其他文本编辑器,可以将本指南作为参考,并搜索您首选编辑器的等效命令。
2. 需求
为了遵循本指南,我们需要安装某些需求。我们需要一个语言服务器,ccls
或 clangd
,以及可选的编译数据库。
语言服务器的安装可以通过 pkg
或通过 ports 进行。如果我们选择 clangd
,则需要安装 llvm
。
使用 pkg
安装 ccls
如果我们想使用 clangd
,我们需要安装 llvm
(示例命令使用 llvm15
,但选择您想要的版本)
# pkg install llvm15
要通过 ports 安装,请从以下每个类别中选择您喜欢的工具组合
语言服务器实现
devel/llvm12(其他版本也可以,但较新的版本更好。如果使用其他版本,请将
clangd12
替换为 clangdN。)
编辑器
编译数据库生成器
devel/python(用于 llvm 的 scan-build-py 实现)
devel/py-pip(用于 rizsotto 的 scan-build 实现)
3. 编辑器设置
3.1. Vim/Neovim
3.1.1. LSP 客户端插件
本示例中两个编辑器都使用内置的插件管理器。使用的 LSP 客户端插件是 prabirshrestha/vim-lsp。
要为 Neovim 设置 LSP 客户端插件
# mkdir -p ~/.config/nvim/pack/lsp/start
# git clone https://github.com/prabirshrestha/vim-lsp ~/.config/nvim/pack/lsp/start/vim-lsp
以及 Vim
# mkdir -p ~/.vim/pack/lsp/start
# git clone https://github.com/prabirshrestha/vim-lsp ~/.vim/pack/lsp/start/vim-lsp
要在编辑器中启用 LSP 客户端插件,在使用 Neovim 时将以下代码段添加到 ~/.config/nvim/init.vim 中,或者在使用 Vim 时添加到 ~/.vim/vimrc 中
au User lsp_setup call lsp#register_server({
\ 'name': 'ccls',
\ 'cmd': {server_info->['ccls']},
\ 'allowlist': ['c', 'cpp', 'objc'],
\ 'initialization_options': {
\ 'cache': {
\ 'hierarchicalPath': v:true
\ }
\ }})
au User lsp_setup call lsp#register_server({
\ 'name': 'clangd',
\ 'cmd': {server_info->['clangd15', '--background-index', '--header-insertion=never']},
\ 'allowlist': ['c', 'cpp', 'objc'],
\ 'initialization_options': {},
\ })
根据您为 clangd
安装的版本,您可能需要更新 server-info
以指向正确的二进制文件。
请参阅 https://github.com/prabirshrestha/vim-lsp/blob/master/README.md#registering-servers 了解有关设置键绑定和代码补全的信息。clangd 的官方网站是 https://clangd.llvm.org,ccls 的存储库链接是 https://github.com/MaskRay/ccls/。
以下是键绑定和代码补全的参考设置。将以下代码段放入 ~/.config/nvim/init.vim 或 Vim 用户的 ~/.vim/vimrc 中以使用它
function! s:on_lsp_buffer_enabled() abort
setlocal omnifunc=lsp#complete
setlocal completeopt-=preview
setlocal keywordprg=:LspHover
nmap <buffer> <C-]> <plug>(lsp-definition)
nmap <buffer> <C-W>] <plug>(lsp-peek-definition)
nmap <buffer> <C-W><C-]> <plug>(lsp-peek-definition)
nmap <buffer> gr <plug>(lsp-references)
nmap <buffer> <C-n> <plug>(lsp-next-reference)
nmap <buffer> <C-p> <plug>(lsp-previous-reference)
nmap <buffer> gI <plug>(lsp-implementation)
nmap <buffer> go <plug>(lsp-document-symbol)
nmap <buffer> gS <plug>(lsp-workspace-symbol)
nmap <buffer> ga <plug>(lsp-code-action)
nmap <buffer> gR <plug>(lsp-rename)
nmap <buffer> gm <plug>(lsp-signature-help)
endfunction
augroup lsp_install
au!
autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
augroup END
3.2. VSCode
3.2.1. LSP 客户端插件
需要 LSP 客户端插件来启动语言服务器守护进程。按 Ctrl+Shift+X
显示扩展在线搜索面板。运行 clangd 时输入 llvm-vs-code-extensions.vscode-clangd
,或运行 ccls 时输入 ccls-project.ccls
。
然后,按 Ctrl+Shift+P
显示编辑器命令面板。在面板中输入 Preferences: Open Settings (JSON)
并按 Enter
打开 settings.json。根据语言服务器的实现,将以下 JSON 键/值对之一放入 settings.json 中
[
/* Begin of your existing configurations */
...
/* End of your existing configurations */
"clangd.arguments": [
"--background-index",
"--header-insertion=never"
],
"clangd.path": "clangd12"
]
[
/* Begin of your existing configurations */
...
/* End of your existing configurations */
"ccls.cache.hierarchicalPath": true
]
4. 编译数据库
编译数据库包含一个编译命令对象的数组。每个对象指定编译源文件的方式。编译数据库文件通常为 compile_commands.json。数据库用于语言服务器实现的索引目的。
请参阅 https://clang.llvm.net.cn/docs/JSONCompilationDatabase.html#format 了解编译数据库文件格式的详细信息。
4.1. 生成器
4.1.1. 使用 scan-build-py
4.1.1.1. 安装
scan-build-py 中的 intercept-build
工具用于生成编译数据库。
首先安装 devel/python 以获取 python 解释器。要从 LLVM 获取 intercept-build
# git clone https://github.com/llvm/llvm-project /path/to/llvm-project
其中 /path/to/llvm-project/ 是您所需的存储库路径。为方便起见,在 shell 配置文件中创建一个别名
alias intercept-build='/path/to/llvm-project/clang/tools/scan-build-py/bin/intercept-build'
rizsotto/scan-build 可以替代 LLVM 的 scan-build-py。LLVM 的 scan-build-py 是 rizsotto/scan-build 合并到 LLVM 树中的。此实现可以通过 pip install --user scan-build
进行安装。intercept-build
脚本默认位于 ~/.local/bin 中。
5. 总结
生成编译数据库后,在 FreeBSD 源代码树中打开任何源文件,语言服务器守护进程也会在后台启动。首次在源代码树中打开源文件需要花费更长的时间,然后语言服务器才能给出完整的结果,这是因为语言服务器在后台初始索引,并编译编译数据库中列出的所有条目。但是,语言服务器守护进程不会索引编译期间未出现在编译数据库中的源文件,因此在未编译的源文件中不会显示完整的结果。
上次修改时间:2023 年 12 月 21 日,作者 rilysh