[kak-lsp] Tips for correctly setting up Deno LSP?

I have these settings in ~/.config/kak-lsp/kak-lsp.toml:

...
[language.deno]
filetypes = ["typescript", "javascript"]
roots = [".git"]
command = "deno"
args = ["lsp"]

[language.typescript]
filetypes = ["typescript"]
roots = ["package.json", "tsconfig.json"]
command = "typescript-language-server"
args = ["--stdio"]

I also set the following options at the end of kakrc:

set-option global lsp_server_configuration deno.enable="true"

When I open a TypeScript file, the TypeScript LSP overrides Deno’s and displays invalid errors. If I disable the TypeScript LSP, Deno LSP doesn’t appear to work. Any tips for making the two play nice with each other?

PS: Excuse my ignorance if I’m doing something wrong, I’m very new to Kakoune.

Edit: lsp-capabilities shows a list of supported commands, but none actually work.

deno requires some extra initialization options in the kak-lsp config.

Add this extra block in kak-lsp.toml and it should start working.

[language.deno.initialization_options]
enable = true
lint = true
2 Likes

Thanks. It does work, but how do I set it up per-project? I don’t want Deno to enable itself in all TypeScript projects.

How do you distinguish Deno projects from other TypeScript projects? kak-lsp tries to base it on Kakoune’s filetype option, but that’s not enough because filetype=typescript could be either. If there’s some other way, maybe kak-lsp can be taught to recognise it, or maybe Kakoune can be taught to use a different filetype value for TypeScript-in-Deno files, and then kak-lsp can key off that.

I guess you can differentiate based on project root in the kak-lsp config?

.git for deno and package.json for node-based projects?

That is, if you don’t use node in deno projects, of course.

VSCode and Vim CoC allow overriding initialization options via a separate configuration file placed in the project directory. I guess kak-lsp doesn’t have that feature yet.

1 Like

Has anyone experienced kak-lsp successfully connecting to Deno’s LSP server, but then Deno just returns null whenever an lsp command is sent? I can confirm that VSCode on my machine can communicate with Deno’s language server just fine, but not kak-lsp.

Here’s an except from a log file (configured using kak-lsp’s recommended method for logging out lang server interactions). You can see that Deno is responding back to kak-lsp (I’ve bolded the part where you can see it’s deno):

So, you’d think everything would be fine…but when Deno’s language server gets any request sent to it, it just responds with null. Here’s what I’m seeing in the log file when I move my cursor with lsp-auto-hover enabled:

Toggle below if you wanted to see the entire log output for the interaction of opening up kakoune, moving the cursor once (with auto hover enabled), and then quitting.

Full log output for opening up a typescript file

Here’s all the versioning info that I think would be relevant:

And here’s my kak-lsp.toml:

Sorry…that was a ton of text…anybody got any ideas as too what might be going on? Or any additional troubleshooting ideas?

I should note that o experienced this with Deon 1.13 too

Unfortunately, the new settings parameter is not a drop-in replacement for initialization_options. We added settings to work around `workspace/configuration` is impossible to implement on the client side ¡ Issue #972 ¡ microsoft/language-server-protocol ¡ GitHub Essentially it allows us to send server configuration both during initialization, and as response to workspace/configuration.

Your log does not contain lint, that immediately hints at a configuration issue (because we should send "lint":true to deno).
The log does however contain

{"jsonrpc":"2.0","method":"workspace/configuration","params":{"items":[{"section":"deno"}]},"id":1}, module: kak_lsp::language_server_transport:151 Sep 17

This means that the language server is asking for the configuration section deno, but there is none in your settings. If you’re ever unsure of how this should look like, you can check the corresponding VSCode configuration. This can help because kak-lsp’s settings use exactly the same structure, only with TOML syntax instead of JSON.
A valid VSCode configuration probably looks something like

{
  "deno": {
    "enable": true,
    "lint": true
  }
}

To match that structure, let’s just wrap the options in a deno section.

[language.typescript.settings.deno]
enable = true
lint = true

or, equivalently

[language.typescript.settings]
deno.enable = true
deno.lint = true
Extra info (not relevant for deno)

For some other servers it’s also necessary to add something like settings_section = "deno". The kak-lsp documentation states that

During server initialization, kak-lsp sends the section specified by settings_section

this means that during initialization, it will send {"enable":true,"lint":true}. Without setting settings_section, kak-lsp will send no parameters during initialization. Additionally, this is used for workspace/didChangeConfiguration

settings_section is mainly needed for servers that don’t implement workspace/configuration.

[language.deno]

“deno” should probably be “typescript”; this is the LSP languageId that is sent to the server. Without that change I got this error in kak-lsp’s log

Unsupported language id "deno" received for document "file:///home/johannes/git/kak-lsp/t/test.ts"

This config works for me:

[language.typescript]
filetypes = ["typescript"]
roots = [".git"]
command = "deno"
args = ["lsp"]
[language.typescript.settings.deno]
enable = true
lint = true

Improvements to the default config/docs/wiki are always welcome :wink:

How do you distinguish Deno projects from other TypeScript projects?

My proposal would be to extend the dynamic server configuration thing, so users can write something like

# Dynamically activate deno config
set-option global lsp_config %{
    [language.typescript]
    filetypes = ["typescript"]
    roots = [".git"]
    command = "deno"
    args = ["lsp"]
    [language.typescript.settings.deno]
    enable = true
    lint = true
}
# Dynamically activate typescript config
set-option global lsp_config %{
    [language.typescript]
    filetypes = ["typescript"]
    roots = [".git"]
    command = "typescript-language-server"
    args = ["--stdio"]
}

this doesn’t work yet - only the language.typescript.settings.deno part is supported.

For now, I recommend starting separate Kakoune sessions, and starting kak-lsp with different config files depending on whether it’s a deno project or not.

VSCode and Vim CoC allow overriding initialization options via a separate configuration file placed in the project directory.

This can be done by setting the lsp_config option depending on the project, see GitHub - kak-lsp/kak-lsp: Kakoune Language Server Protocol Client. The deprecated alternative lsp_server_configuration is still supported but less powerful.

This currently only supports toggling server options, but not switching between servers yet (see the end of my previous comment).

First and foremost, thank you for taking so much time to provide such a detailed response to all of these little issues. It’s very generous of you! I really appreciated the window into understanding the complexities of this new world of language servers.

The example toml you gave was spot on - everything is working perfectly locally for me now with Deno!

In regards to your proposal of extending dynamic config support beyond a single language.<foo>.settings, would it be helpful if I wrote up a ticket on the kak-lsp issue tracker as a feature request? Regretfully I don’t know Rust (yet!), but I’m happy to help in at least writing up an issue to document the use-case.

For those that need guidance on how to setup the “dynamic toml switching” that @krobelus proposes above, here’s how I went about doing it:

my main kakrc file:

eval %sh{kak-lsp --kakoune -s $kak_session}

declare-option str lsp_toml_path 'path/to/my/usual/kak-lsp.toml' 

hook global WinSetOption filetype=(typescript) %{
    set global lsp_cmd "kak-lsp -s %val{session} --config %opt{lsp_toml_path}"
    lsp-enable-window
}

# Look for a file named .kakrc.local in working directory on kakoune startup  
evaluate-commands %sh{
    if [ -f .kakrc.local ]; then
        printf "source .kakrc.local"
    fi
}

Then, for any directory that I want to override my standard kak-lsp.toml I drop a file in there named .kakrc.local and then throw in the override:

set-option global lsp_toml_path 'path/to/my/special/kak-lsp-deno.toml'

NOTE: It’s very important that you start kakoune from the directory that contains .kakrc.local, not from a subdirectory!

Regarding the per-project server selection I opened Recommended way to select language servers depending on project · Issue #537 · kak-lsp/kak-lsp · GitHub - it’s not super important but it can’t hurt to gather ideas there.

I updated kak-lsp today and found out that there’s a new option required to send the settings. A full configuration for Deno now would look like the following:

[language.typescript]
filetypes = ["typescript"]
roots = [".git"]
command = "deno"
args = ["lsp"]
offset_encoding = "utf-8"
settings_section = "deno" # THIS IS THE NEW CONFIG PROPERTY

[language.typescript.settings.deno]
enable = true
lint = true
unstable = true

More details can be found here:

1 Like

Only slightly more robust, but I modified your example to work with plug.kak and so that it works inside subdirectories. Though it’s slightly less generic. Thanks for the working example @schickm!

plug "ul/kak-lsp" do %{
    [...]
} config %{
    declare-option str lsp_toml_path '$HOME/.config/kak-lsp/kak-lsp.toml'

    evaluate-commands %sh{
        ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)"
        if [ -f "${ROOT_DIR:-.}/deno.json" ]; then
            printf "set-option global lsp_toml_path '$HOME/.config/kak-lsp/kak-lsp-deno.toml'"
        fi
    }

    set global lsp_cmd "kak-lsp -s %val{session} --config %opt{lsp_toml_path}" 

    [...]
}