Kak-lsp + ccls

Install kak-lsp (git clone https://github.com/ul/kak-lsp; cd kak-lsp; cargo install --locked --force --path .; cp target/release/kak-lsp ~/.local/bin/) (~/.local/bin is in my PATH)

~/.config/kak-lsp/kak-lsp.toml

snippet_support = false
verbosity = 2

[server]
# exit session if no requests were received during given period in seconds
# works only in unix sockets mode (-s/--session)
# set to 0 to disable
timeout = 1800 # seconds = 30 minutes

[language.c_cpp]
filetypes = ["c", "cpp"]
roots = [".ccls-root", ".ccls", "compile_commands.json"]
# ensure `ccls` is in a PATH directory, see https://github.com/MaskRay/ccls/wiki/Install#shell-script-wrapper
command = "ccls"
# kak-lsp does not support newText yet
args = ["--init={\"completion\":{\"detailedLabel\":false}}"]

Add the following to my ~/.config/kak/kakrc:

eval %sh{kak-lsp --kakoune -s $kak_session}
hook global WinSetOption filetype=(c|cpp) %{
    lsp-enable-window
}

.ccls can be hierarchical (Project Setup · MaskRay/ccls Wiki · GitHub). I hope .ccls-root has the highest priority but I am not sure whether that is the case.

cd /tmp; mkdir d; cd d
touch .ccls  # an empty .ccls ensures all .c/.cc/.cpp files are indexed with the default clang command line options
touch a.cc
kak a.cc

Note about completion.detailedLabel: false

If I delete this initialization option, the completion items will look weird.

What ccls responds (to the textDocument/completion request) is something like this:

{"label":"foo(int a, int b) -> void","kind":3,"detail":"","sortText":"    ","filterText":"foo","insertTextFormat
":1,"textEdit":{"range":{"start":{"line":4,"character":4},"end":{"line":4,"character":7}},"newText":"foo"}

The client is expected to insert newText instead of label in the buffer.

1 Like

I can’t understand if this is an instruction or a complaint?

Both an instruction and a complaint (I have to workaround the textEdit feature that is not supported). ul pointed me to https://github.com/mawww/kakoune/issues/2898

It’s nice to have you here. Thanks for working on ccls, it’s really good.

what advantages does it have over clangd?

IMO ccls has a better global index model.

Better performance, better indexing features, more initialization options for customization. clangd has recently provided some niche features that I’d like to investigate: clang-tidy integration, expanding macros, expanding auto, etc.

The core of ccls is significantly simpler than clangd. It is much less clang-oriented. In theory it can be easily adapted to create language servers for other programming languages. Yes, I have to say a lot of language servers do not do cross references correctly.

Better performance, better indexing features

in my experience it is the opposite. I’m using network mounted file system via sshfs and clangd instantly works insanely fast on our project, which is pretty big, while ccls had to build some cache before becoming responsible and later had some issues with snappiness. Though this may be outdated information, because I’ve tried ccls maybe half a year ago or more.

The other feature of clangd that I like, is that it can either use compile_commands.json or compile_flags.txt. ccls also can use compile_commands.json, but .ccls is much more complex, compared to compile_flags.txt which I can basically use in my Makefiles like so: CFLAGS = $(shell cat compile_flags.txt | tr '\n' ' ') and then have identical flags for linting and compilation.

in my experience it is the opposite. I’m using network mounted file system via sshfs and clangd instantly works insanely fast on our project, which is pretty big, while ccls had to build some cache before becoming responsible and later had some issues with snappiness. Though this may be outdated information, because I’ve tried ccls maybe half a year ago or more.

I think that is because you don’t use clangd -background-index. You will not get project-wide references.

You can get similar behavior from ccls with the initialization option index.initialBlacklist

args = ["--init={\"index\":{\"initialBlackList\":["."]}}"]

The other feature of clangd that I like, is that it can either use compile_commands.json or compile_flags.txt . ccls also can use compile_commands.json , but .ccls is much more complex

Yes, it supports some %cpp directives, but you can use it as if you are using compile_flags.txt. I have provided some examples (Project Setup · MaskRay/ccls Wiki · GitHub) but I understand that people may be reluctant to read the full description.

For that simple use case, the only difference between compile_flags.txt and .ccls is that .ccls requires explicit mention of the compiler driver, which is usually clang. There are good reasons to behave this way, you may try aarch64-linux-gnu-clang and clang-cl.

I don’t use references at all, so I think I can live with that.