diff --git a/documentation/content/en/articles/freebsd-src-lsp/_index.adoc b/documentation/content/en/articles/freebsd-src-lsp/_index.adoc new file mode 100644 --- /dev/null +++ b/documentation/content/en/articles/freebsd-src-lsp/_index.adoc @@ -0,0 +1,244 @@ +--- +title: Using language server in the FreeBSD src tree +authors: + - author: Ka Ho Ng + email: khng@FreeBSD.org +copyright: 2021 The FreeBSD Foundation +description: Using language server in the FreeBSD src tree to get precise go-to-definition and completion results. +trademarks: ["freebsd"] +tags: ["FreeBSD", "Language", "Server", "lsp"] +--- + += Using language server in the FreeBSD src tree +:doctype: article +:toc: macro +:toclevels: 2 +:icons: font +:sectnums: +:sectnumlevels: 6 +:source-highlighter: rouge +:experimental: + +toc::[] + +[[intro]] +== Introduction + +This guide is about setting up a FreeBSD src tree with language servers performing source code indexing. + +[[ports-required]] +== Required Ports + +Some ports are required throughout the guide. +Choose your favorite combinations from each categories of tools below: + +* Language server implementations +** package:devel/ccls[] +** package:devel/llvm12[] (Other versions are okay, but newer is better. Replace `clangd12` with clangdN in case other versions are used.) +* Editors +** package:editors/vim[] +** package:editors/neovim[] +** package:editors/vscode[] +* Compilation database generator +** package:devel/python[] (For llvm's scan-build-py implementation) +** package:devel/py-pip[] (For rizsotto's scan-build implementation) +** package:devel/bear[] + +[[editor-settings]] +== Editor settings + +[[settings-vim]] +=== Vim/Neovim + +==== LSP client plugins + +The builtin plugin manager is used for both editors in this example. +The LSP client plugin used is link:https://github.com/prabirshrestha/vim-lsp[prabirshrestha/vim-lsp]. + +To set up the LSP client plugin for Neovim: + +[source,shell] +.... +# mkdir -p ~/.config/nvim/pack/lsp/start +# git clone https://github.com/prabirshrestha/vim-lsp ~/.config/nvim/pack/lsp/start/vim-lsp +.... + +and for Vim: + +[source,shell] +.... +# mkdir -p ~/.vim/pack/lsp/start +# git clone https://github.com/prabirshrestha/vim-lsp ~/.vim/pack/lsp/start/vim-lsp +.... + +To enable the LSP client plugin in the editor, add the following snippet into [.filepath]#~/.config/nvim/init.vim# if you are using Neovim, or [.filepath]#~/.vim/vimrc# if you are using Vim: + +.For ccls +[source,vim] +.... +au User lsp_setup call lsp#register_server({ + \ 'name': 'ccls', + \ 'cmd': {server_info->['ccls']}, + \ 'whitelist': ['c', 'cpp', 'objc'], + \ 'initialization_options': { + \ 'cache': { + \ 'hierarchicalPath': v:true + \ } + \ }}) +.... + +.For clangd +[source,vim] +.... +au User lsp_setup call lsp#register_server({ + \ 'name': 'clangd', + \ 'cmd': {server_info->['clangd12', '--background-index', '--header-insertion=never']}, + \ 'whitelist': ['c', 'cpp', 'objc'], + \ 'initialization_options': {}, + \ }) +.... + +Read link:https://github.com/prabirshrestha/vim-lsp/blob/master/README.md#registering-servers[] to learn setting up the keybindings and code completion. +The official site of clangd is link:https://clangd.llvm.org[], and the repository link of ccls is link:https://github.com/MaskRay/ccls/[]. + +Below is the reference settings of keybindings and code completions. +Put the following snippet into [.filepath]#~/.config/nvim/init.vim#, or [.filepath]#~/.vim/vimrc# for Vim users to use it: + +[source,vim] +.... +function! s:on_lsp_buffer_enabled() abort + setlocal omnifunc=lsp#complete + setlocal completeopt-=preview + setlocal keywordprg=:LspHover + + nmap (lsp-definition) + nmap ] (lsp-peek-definition) + nmap (lsp-peek-definition) + nmap gr (lsp-references) + nmap (lsp-next-reference) + nmap (lsp-previous-reference) + nmap gI (lsp-implementation) + nmap go (lsp-document-symbol) + nmap gS (lsp-workspace-symbol) + nmap ga (lsp-code-action) + nmap gR (lsp-rename) + nmap gm (lsp-signature-help) +endfunction + +augroup lsp_install + au! + autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled() +augroup END +.... + +[[settings-vscode]] +=== VSCode + +==== LSP client plugins + +LSP client plugins are required to launch language server daemon. +Press `Ctrl+Shift+X` to show the extension online search panel. +Enter `llvm-vs-code-extensions.vscode-clangd` if you run clangd, or `ccls-project.ccls` if you run ccls. + +Then, press `Ctrl+Shift+P` to show the editor commands palette. +Enter `Preferences: Open Settings (JSON)` into the palette and hit `Enter` to open [.filepath]#settings.json#. +Depending on the language server implementations being used, put one the following JSON key/value pairs in [.filepath]#settings.json#: + +.For clangd +[source,json] +.... +[ + /* Begin of your existing configurations */ + ... + /* End of your existing configurations */ + "clangd.arguments": [ + "--background-index", + "--header-insertion=never" + ], + "clangd.path": "clangd12" +] +.... + +.For ccls +[source,json] +.... +[ + /* Begin of your existing configurations */ + ... + /* End of your existing configurations */ + "ccls.cache.hierarchicalPath": true +] +.... + +[[cdb]] +== Compilation database + +Compilation database contains an array of command, directory and file tuples to compile a source file. +The compilation database file is usually [.filename]#compiler_commands.json#. +The database is used by language server implementations for indexing purpose. + +[[cdb-generators]] +=== Generators + +[[generators-scan-build-py]] +==== Using scan-build-py + +===== Installation + +`intercept-build` tool from scan-build-py is used to generate compilation +database. + +Install package:devel/python[] to get python interpreter first. To get +`intercept-build` from LLVM: + +[source,shell] +.... +# git clone https://github.com/llvm/llvm-project /path/to/llvm-project +.... + +where [.filename]#/path/to/llvm-project/# is your desired path for the repository. Make an alias in the shell configuration file for convenience: + +[source,shell] +.... +alias intercept-build='/path/to/llvm-project/clang/tools/scan-build-py/bin/intercept-build' +.... + +You can also use scan-build from link:https://github.com/rizsotto/scan-build[rizsotto/scan-build] instead of LLVM's scan-build-py. +The LLVM's scan-build-py was rizsotto/scan-build merged into the LLVM tree. +This implementation can be installed by `pip install --user scan-build`. +The `intercept-build` script is in [.filename]#~/.local/bin# by default. + +===== Usage + +In the top-level directory of the FreeBSD src tree, to generate compilation database with `intercept-build`: + +[source,shell] +.... +# intercept-build --append make buildworld buildkernel -j`sysctl -n hw.ncpu` +.... + +The `--append` flag tells the `intercept-build` to read an existing compilation database (if a compilation database exists) and append the results to the database. +Entries with duplicated command key are merged. +The generated compilation database by default is saved in the current working directory as [.filename]#compiler_commands.json#. + +[[generators-bear]] +==== Using devel/bear + +===== Usage + +In the top-level directory of the FreeBSD src tree, to generate compilation database with `bear`: + +[source,shell] +.... +# bear -a make buildworld buildkernel -j`sysctl -n hw.ncpu` +.... + +The `-a` flag tells `bear` to read an existing compilation database if it presents, and append the results to the database. Entries with duplicated command key are merged. +The generated compilation database by default is saved in the current working directory as [.filename]#compiler_commands.json#. + +[[final]] +== Final + +Once compilation database is generated, you can open any source files in the FreeBSD src tree and LSP server daemon will be launched as well in background. +Opening source files in the src tree for the first time is significantly longer before the LSP server is able to give complete result, due to initial background indexing by LSP server compiling all the listed entries in the compilation database. +The language server daemon however does not index the source files not appearing in compilation database, thus you would not see complete results on source files not being compiled during the `make`. \ No newline at end of file