kak-lsp is a Language Server Protocol client for Kakoune implemented in Rust.
Note
|
kak-lsp.toml destination in all described installation methods is just an example.
Also, kak-lsp doesn’t read the configuration file from the current working directory or binary’s dir by default.
Please consult Configuring kak-lsp to figure out where does kak-lsp expect kak-lsp.toml
to be in your environment and how to specify a custom path to it.
However, if you don’t need to change configuration then feel free to skip copying it anywhere as the default configuration is embedded into the kak-lsp binary.
|
curl -O -L https://github.com/kak-lsp/kak-lsp/releases/download/v11.0.1/kak-lsp-v11.0.1-x86_64-apple-darwin.tar.gz
tar xzvf kak-lsp-v11.0.1-x86_64-apple-darwin.tar.gz
# replace `~/.local/bin/` with something on your `$PATH`
mv kak-lsp ~/.local/bin/
mkdir -p ~/.config/kak-lsp
mv kak-lsp.toml ~/.config/kak-lsp/
-
Arch Linux:
pacman -S kak-lsp
or AUR/kak-lsp-git -
Void Linux:
xbps-install -S kak-lsp
-
Fedora Copr:
sudo dnf copr enable atim/kakoune -y && sudo dnf install kak-lsp
wget https://github.com/kak-lsp/kak-lsp/releases/download/v11.0.1/kak-lsp-v11.0.1-x86_64-unknown-linux-musl.tar.gz
tar xzvf kak-lsp-v11.0.1-x86_64-unknown-linux-musl.tar.gz
# replace `~/.local/bin/` with something on your `$PATH`
mv kak-lsp ~/.local/bin/
mkdir -p ~/.config/kak-lsp
mv kak-lsp.toml ~/.config/kak-lsp/
Generally, you need the latest stable version of Rust to build kak-lsp.
git clone https://github.com/kak-lsp/kak-lsp
cd kak-lsp
cargo install --locked --force --path .
# replace `~/.config` with OS-specific dir as described at https://docs.rs/dirs/2.0.1/dirs/fn.config_dir.html
mkdir -p ~/.config/kak-lsp
# or just link if you are okay with default config
cp kak-lsp.toml ~/.config/kak-lsp/
If you don’t mind using a plugin manager, you can install kak-lsp
via plug.kak. Add this code to your kakrc
:
plug "kak-lsp/kak-lsp" do %{
cargo install --locked --force --path .
}
You can replace cargo install
with ln -sf $PWD/target/release/kak-lsp ~/.local/bin/
where ~/.local/bin/
can be replaced with something in your $PATH
.
Examples of configuration with plug.kak can be found at Wiki.
kak-lsp doesn’t manage installation of language servers, please install them by yourself for the languages you plan to use kak-lsp with. Please consult the How to install servers wiki page for quick installation of language servers supported by kak-lsp out of the box.
Note
|
Contents below corresponds to the master branch HEAD and could be slightly out-of-sync with the version installed from pre-built binaries. The most common case is new commands being in a pre-release testing stage. Please refer to the README.asciidoc revision tagged with the version you use or the README.asciidoc from the release archive. |
To enable LSP support for configured languages (see the next section) just add the following
commands to your kakrc
:
eval %sh{kak-lsp --kakoune -s $kak_session} # Not needed if you load it with plug.kak.
lsp-enable
A bit more involved but recommended way is to enable kak-lsp only for specific filetypes you need
via lsp-enable-window
, e.g.:
eval %sh{kak-lsp --kakoune -s $kak_session} # Not needed if you load it with plug.kak.
hook global WinSetOption filetype=(rust|python|go|javascript|typescript|c|cpp) %{
lsp-enable-window
}
Either way you get:
-
completions
-
lsp-definition
command to go to definition, mapped togd
by default -
lsp-hover
command to show hover info (including relevant diagnostics when available) in the info box.-
lsp-hover-buffer
command to show the same in a scratch buffer. -
to automatically show hover when you move around, use
lsp-auto-hover-enable
-
to show hover anchored to hovered position, use
set global lsp_hover_anchor true
-
to exclude diagnostics, use
set-option global lsp_show_hover_format 'printf %s "${lsp_info}"'
-
-
lsp-declaration
command to jump to the declaration of the symbol under the main cursor -
lsp-definition
command to jump to the definition of the symbol under the main cursor -
lsp-type-definition
command to jump to the definition of the type of the symbol under the main cursor -
lsp-implementation
command to find implementations for the symbol under the main cursor -
lsp-references
command to find references to the symbol under the main cursor, mapped togr
by default-
for the previous five commands, the
*goto*
buffer has filetypelsp-goto
, so you can press<ret>
on a line or use thelsp-jump
command
-
-
lsp-find-error
command to jump to the next or previous error in the current file -
lsp-next-location
andlsp-previous-location
to jump to the next or previous location listed in a buffer with thelsp-goto
filetype. These also work for buffers*grep*
,*lint*
and*make*
-
lsp-highlight-references
command to highlight all references to the symbol under the main cursor in the current buffer with theReference
face (which is equal to theMatchingChar
face by default) -
lsp-document-symbol
command to list the current buffer’s symbols -
lsp-workspace-symbol
command to list project-wide symbols matching the query -
lsp-workspace-symbol-incr
command to incrementally list project-wide symbols matching the query-
*symbols*
buffer has filetypelsp-goto
so you can press<ret>
on a line or use thelsp-jump
command
-
-
lsp-diagnostics
command to list project-wide diagnostics (current buffer determines project and language to collect diagnostics for)-
*diagnostics*
buffer has filetypelsp-goto
so you can press<ret>
on a line or use thelsp-jump
command
-
-
lsp-incoming-calls
andlsp-outgoing-calls
commands to list callers and callees of the function at the cursor.-
*callers*
and*callees*
buffers have filetypelsp-goto
so you can press<ret>
on a line or use thelsp-jump
command
-
-
inline diagnostics highlighting using the
DiagnosticError
,DiagnosticHint
,DiagnosticInfo
andDiagnosticWarning
faces; can be disabled withlsp-inline-diagnostics-disable
command -
flags in the left margin on lines with errors or other diagnostics; can be disabled with
lsp-diagnostic-lines-disable
command -
lsp-formatting
command to format current buffer, according to thetabstop
andlsp_insert_spaces
options -
lsp-formatting-sync
command to format current buffer synchronously, suitable for use withBufWritePre
hook: -
lsp-next-symbol
andlsp-previous-symbol
command to go to the buffer’s next and current/previous symbol. -
lsp-hover-next-symbol
andlsp-hover-previous-symbol
to show hover of the buffer’s next and current/previous symbol.
hook global WinSetOption filetype=rust %{
hook window BufWritePre .* lsp-formatting-sync
}
-
lsp-rename <new_name>
andlsp-rename-prompt
commands to rename the symbol under the main cursor. -
If
lsp_auto_show_code_actions
istrue
, a lightbulb in the mode line whenever code actions are available at the main cursor position-
To customize the lightbulb, you can override
lsp-show-code-actions
andlsp-hide-code-actions
-
-
lsp-code-actions
to open a menu to choose a code action to run-
To customize the menu, you can override
lsp-perform-code-action
-
-
lsp-code-action
to run the code action matching the given pattern. -
lsp_diagnostic_error_count
,lsp_diagnostic_hint_count
,lsp_diagnostic_info_count
andlsp_diagnostic_warning_count
options which contain the number of diagnostics of the respective level for the current buffer. For example, you can put it into your modeline to see at a glance if there are errors in the current file -
starting new kak-lsp session when Kakoune session begins and stopping it when Kakoune session ends
Note
|
By default, kak-lsp exits when it doesn’t receive any request from Kakoune for 30 minutes,
even if the Kakoune session is still up and running. Change server.timeout in kak-lsp.toml
to tweak this duration, or set it to 0 to disable this behavior. In any scenario, a new request
would spin up a fresh server if it is down.
|
-
lsp
user mode. The following example mapping gives you access to the shortcuts from below table after typing,l
.
map global user l %{: enter-user-mode lsp<ret>} -docstring "LSP mode"
Binding | Command |
---|---|
a |
lsp-code-actions |
c |
lsp-capabilities |
d |
lsp-definition |
e |
lsp-diagnostics |
f |
lsp-formatting |
h |
lsp-hover |
i |
lsp-implementation |
j |
lsp-outgoing-calls |
k |
lsp-incoming-calls |
r |
lsp-references |
R |
lsp-rename-prompt |
s |
lsp-signature-help |
S |
lsp-document-symbol |
o |
lsp-workspace-symbol-incr |
n |
lsp-find-error |
p |
lsp-find-error --previous |
y |
lsp-type-definition |
9 |
lsp-hover-previous-function |
0 |
lsp-hover-next-function |
& |
lsp-highlight-references |
( |
lsp-previous-function |
) |
lsp-next-function |
[ |
lsp-hover-previous-symbol |
] |
lsp-hover-next-symbol |
{ |
lsp-previous-symbol |
} |
lsp-next-symbol |
To know which subset of kak-lsp commands is backed by the current buffer’s filetype’s language server use
lsp-capabilities
command.
All commands are also represented as subcommands of the lsp
umbrella command if you prefer this style.
For example, you can use lsp references
instead of lsp-references
.
kak-lsp itself has configuration, but it also adds configuration options to Kakoune that affect the Kakoune integration.
kak-lsp is configured via a configuration file in TOML format. By
default kak-lsp tries to read kak-lsp/kak-lsp.toml
under OS-specific config dir as described here,
but you can override it with command-line option --config
. Look into the default
kak-lsp.toml
, it should be quite self-explanatory.
Important: The configuration file does not extend the default configuration, but rather overrides it. This means that if you want to customize any of the configuration, you must copy the entire default configuration and then edit it.
In the language section of kak-lsp.toml
, the roots
parameter is a list of file globs.
Whenever your editor session wants to send an LSP request, the first glob that matches a file
in any of the current buffer’s parent directories will cause kak-lsp
to set the project root
to that parent directory.
You can define an environment variable like KAK_LSP_PROJECT_ROOT_RUST=/my/project
to always
use /my/project
as root for Rust files inside /my/project
. Substitute RUST
with another
language ID to do the same for other file types.
The environment variable KAK_LSP_FORCE_PROJECT_ROOT=/my/project
will make kak-lsp
always
use /my/project
as project root, even for files outside this directory. This avoids starting
separate language servers for files outside /my/project
, and ensures that your language server
is aware of your project’s build configuration even when navigating library code.
If you are setting any server options via cli, do not forget to append them to
%sh{kak-lsp --kakoune …}
in your kakrc
. It’s not needed if you change options in
~/.config/kak-lsp/kak-lsp.toml
.
Please let us know if you have any ideas about how to make the default config more sensible.
Many servers accept configuration options that are not part of the LSP spec. The TOML table
[language.<filetype>.settings]
holds those configuration options. It has the same structure
as the corresponding fragments from VSCode’s settings.json
. For example:
[language.go]
...
settings_section = "gopls"
[language.go.settings.gopls]
"formatting.gofumpt" = true
During server initialization, kak-lsp sends the section specified by settings_section
; in this
case {"formatting.gofumpt":true}
. Whenever you change the Kakoune option lsp_config
, the
same section is sent via workspace/didChangeConfiguration
. Additionally, kak-lsp will send
arbitrary sections that are requested by the server in workspace/configuration
.
kak-lsp’s Kakoune integration declares the following options:
-
lsp_completion_trigger
(str): This option is set to a Kakoune command, which is executed every time the user pauses in insert mode. If the command succeeds, kak-lsp will send a completion request to the language server. -
lsp_diagnostic_line_error_sign
,lsp_diagnostic_line_hint_sign
,lsp_diagnostic_line_info_sign
, andlsp_diagnostic_line_warning_sign
(str): When usinglsp-diagnostic-lines-enable
and the language server detects an error or another diagnostic, kak-lsp will add a flag to the left-most column of the window, using this string and one of the corresponding facesLineFlagError
,LineFlagHint
,LineFlagInfo
orLineFlagWarning
. -
lsp_hover_anchor
(bool): When usinglsp-hover
orlsp-auto-hover-enable
, if this option istrue
then the hover information will be displayed next to the active selection. Otherwise, the information will be displayed in a box in the lower-right corner. -
lsp_hover_max_lines
(int): If greater than 0 then limit rendered hover information to the given number of lines. -
lsp_hover_insert_mode_trigger
(str): This option is set to a Kakoune command. When usinglsp-auto-hover-insert-mode-enable
, this command is executed every time the user pauses in insert mode. If the command succeeds, kak-lsp will send a hover-information request for the text selected by the command. -
lsp_insert_spaces
(bool): When usinglsp-formatting
, if this option istrue
, kak-lsp will ask the language server to indent with spaces rather than tabs. -
lsp_auto_highlight_references
(bool): If this option istrue
thenlsp-highlight-references
is executed every time the user pauses in normal mode. -
lsp_auto_show_code_actions
(bool): If this option istrue
thenlsp-code-actions
is executed every time the user pauses in normal mode. -
lsp_config
(str): This is a TOML string of the same format askak-lsp.toml
, except it only supports one settings:-
[language.<filetype>.settings]
: this works just like the static configuration of the same name inkak-lsp.toml
, see the section about server-specific configuration. This will override the static configuration of the given language.
-
For example, you can toggle an option dynamically with a command like this:
set-option global lsp_config %{
[language.go.settings.gopls]
"formatting.gofumpt" = true
}
Inlay hints are a feature supported by rust-analyzer, which show inferred types, parameter names in function calls, and the types of chained calls inline in the code. To enable support for it in kak-lsp, add the following to your kakrc
:
hook global WinSetOption filetype=rust %{
hook window -group rust-inlay-hints BufReload .* rust-analyzer-inlay-hints
hook window -group rust-inlay-hints NormalIdle .* rust-analyzer-inlay-hints
hook window -group rust-inlay-hints InsertIdle .* rust-analyzer-inlay-hints
hook -once -always window WinSetOption filetype=.* %{
remove-hooks window rust-inlay-hints
}
}
You can change the hints' face with set-face global InlayHint <face>
.
kak-lsp supports the semanticTokens feature for semantic highlighting. If the language server supports it, you can enable it with:
hook global WinSetOption filetype=<language> %{
hook window -group semantic-tokens BufReload .* lsp-semantic-tokens
hook window -group semantic-tokens NormalIdle .* lsp-semantic-tokens
hook window -group semantic-tokens InsertIdle .* lsp-semantic-tokens
hook -once -always window WinSetOption filetype=.* %{
remove-hooks window semantic-tokens
}
}
The faces used for semantic tokens and modifiers can be modified in kak-lsp.toml
, under the semantic_tokens
section.
The syntax for such an entry is
[[semantic_tokens]]
token = "variable"
face = "const_variable_declaration"
modifiers = ["constant", "declaration"]
where token
is the token’s name as reported by the language server (see lsp-capabilities
), face
is the face that will be applied in Kakoune (you’ll want to define these in your theme/config) and modifiers
is an array of modifier names (also reported by the language server). modifiers
may be omitted, but token
and face
are required.
You may create any arbitrary number of definitions with permutations between the token names and modifiers reported by the server. For an entry to match a token, all the entry’s modifiers must exist on the token. However, the token may have additional modifiers not assigned in the config entry.
kak-lsp
will find the most specific matching configuration to apply, where specificity is defined as the number of matching modifiers. If multiple matching entries have the same number of modifiers, the one that was defined last in the configuration wins.
Example:
Assuming the following configuration,
[[semantic_tokens]]
token = "variable"
face = "const_variable_declaration"
modifiers = ["constant", "declaration"]
[[semantic_tokens]]
token = "variable"
face = "const_variable"
modifiers = ["constant"]
[[semantic_tokens]]
token = "variable"
face = "variable"
kak-lsp
will perform these mappings:
Token | Modifiers | Face | Comment |
---|---|---|---|
|
|
|
First entry matches with 2 modifiers. |
|
|
|
First and second entry match with 1 modifier, second wins. |
|
|
|
Only third entry matches. First entry doesn’t match, because |
|
|
Third entry matches. |
|
|
No entries match and no face is applied. |
kak-lsp supports showing diagnostics inline after their respective line, but this behavior can be somewhat buggy and must be enabled explicitly:
lsp-inlay-diagnostics-enable global
kak-lsp shows some additional information provided by the language server in an info box. This information includes documentation for the token under the cursor (lsp-hover
) and documentation for completion candidates. In both cases, the Language Server Protocol allows for both plain text and Markdown, and most servers do implement Markdown.
To make use of Markdown, kak-lsp transpiles it into Kakoune’s markup language, utilizing various faces for styling.
These faces all default to the Information
face, to ensure that the text in the info box works with any color scheme.
To enable Markdown highlighting, define some of the following faces in your theme or kakrc
:
Face | Usage |
---|---|
|
The default text color. You’ll likely want to leave this at the default |
|
The face used for code blocks. Language specific syntax highlighting for code blocks is not supported. |
|
The face used for block quotes. The |
|
The face used to highlight the list symbol for both ordered and unordered lists. For list items' text, |
|
The face used for headings. There is currently no distinction between different heading levels. |
|
The face used to highlight link titles. Maybe some classic |
|
This face is assigned to inline code spans within link titles, such as in the following Markdown snippet. Here, the word [the `format` function](https://example.com) |
|
The face used for inline code spans (backtick strings). |
|
The face used for horizontal lines (rules). |
|
Used for error messages in the diagnostics inside hover info. This defaults to Kakoune’s built-in |
|
Used for hints in the diagnostics inside hover info. |
|
Used for informational messages in the diagnostics inside hover info. |
|
Used for warnings in the diagnostics inside hover info. |
For convenience, here is a snippet to paste into your theme/config:
face global InfoDefault Information
face global InfoBlock Information
face global InfoBlockQuote Information
face global InfoBullet Information
face global InfoHeader Information
face global InfoLink Information
face global InfoLinkMono Information
face global InfoMono Information
face global InfoRule Information
face global InfoDiagnosticError Information
face global InfoDiagnosticHint Information
face global InfoDiagnosticInformation Information
face global InfoDiagnosticWarning Information
Current limitations of this feature are:
-
Language specific syntax highlighting for code blocks is not supported.
-
For hyperlinks, only their title (the pretty name) is shown.
-
The original syntax for headings is retained to visualize their level.
kak-lsp has experimental support for snippets. It is enabled by setting snippet_support = true
at the top level of the config.
It uses the two faces SnippetsNextPlaceholders
and SnippetsOtherPlaceholders
, you may want to customize those.
To properly use snippets, you’ll probably want something like this:
def -hidden insert-c-n %{
try %{
lsp-snippets-select-next-placeholders
exec '<a-;>d'
} catch %{
exec -with-hooks '<c-n>'
}
}
map global insert <c-n> "<a-;>: insert-c-n<ret>"
This maps <c-n>
to select the next placeholder if there is one, and otherwise executes <c-n>
as normal
Currently, kak-lsp doesn’t conform to the spec regarding the interpretation of Position.character
.
LSP spec says that
A position inside a document (see Position definition below) is expressed as a zero-based line and character offset. The offsets are based on a UTF-16 string representation. So for a string of the form
a𐐀b
the character offset of the charactera
is 0, the character offset of𐐀
is 1 and the character offset ofb
is 3 since𐐀
is represented using two code units in UTF-16.
However, kak-lsp treats Position.character
as an offset in UTF-8 code points by default.
Fortunately, it appears to produce the same result within the Basic Multilingual Plane (BMP) which
includes a lot of characters.
Unfortunately, many language servers violate the spec as well, and in an inconsistent manner. Please refer microsoft/language-server-protocol#376 for more information. There are two main types of violations we met in the wild:
1) Using UTF-8 code points, just like kak-lsp does. Those should work well with kak-lsp for characters outside BMP out of the box.
2) Using UTF-8 code units (bytes), just like Kakoune does. Those are supported by kak-lsp but
require adding offset_encoding = "utf-8"
to the language server configuration in kak-lsp.toml
.
If kak-lsp fails try to put this line in your kakrc
after kak-lsp --kakoune
invocation:
set global lsp_cmd "kak-lsp -s %val{session} -vvv --log /tmp/kak-lsp.log"
to enable debug logging.
If it does not give enough insight to fix the problem or if the problem is a bug in kak-lsp itself please don’t hesitate to raise an issue.
Please also try to reproduce the issue with a minimal configuration. Sometimes the problem occurs only with specific settings in your ~/.config/kak-lsp/kak-lsp.toml
and/or ~/.config/kak/
. Use this command to start Kakoune with kak-lsp enabled, both with pristine settings.
HOME=$(mktemp -d) kak -e '
eval %sh{kak-lsp --kakoune -s $kak_session}
set global lsp_cmd "kak-lsp -s %val{session} -vvvv --log /tmp/kak-lsp.log"
lsp-enable'
Note
|
Some Kakoune plugins could interfere with kak-lsp, particularly completions providers.
E.g. racer.kak competes for autocompletion in Rust files.
|
kak-lsp follows SemVer with one notable difference from common practice: we don’t use 0 major version to indicate that product is not yet reached stability. Even for non-stable and not feature-complete product user should be clearly informed about breaking change. Therefore we start with major version 1 and increment it each time when upgrade requires user’s attention.