Setting up kak-lsp to use clojure-lsp

I’m attempting to set up the clojure-lsp language server for use with kak-lsp. I don’t know for sure whether this is even possible, but if it is, it would be great to get it working.

Link to clojure-lsp, the language server for Clojure:

So far, I’ve successfully managed to set up kak-lsp for c/cpp with clangd, so that much is working.

I installed kak-lsp via plug.kak as follows (based on andreyorst’s dotfiles):

plug "ul/kak-lsp" do %{
  cargo build --release --locked
  cargo install --force --path .
} config %{
  set-option global lsp_diagnostic_line_error_sign "!"
  set-option global lsp_diagnostic_line_warning_sign "?"
  
  hook global WinSetOption filetype=(c|cpp|clojure) %{
      map window user "l" ": enter-user-mode lsp<ret>" -docstring "LSP mode"
      lsp-enable-window
      lsp-auto-hover-enable
      lsp-auto-hover-insert-mode-disable
      set-option window lsp_hover_anchor true
      set-face window DiagnosticError default+u
      set-face window DiagnosticWarning default+u
  }
  
  hook global KakEnd .* lsp-exit
}

I copied the default kak-lsp.toml from the plugin install directory into ~/.config/kak-lsp/kak-lsp.toml, and am modifying it there. I’ve tried a few different things, but the relevant config for the Clojure server is currently as follows:

[language.clojure]
filetypes = ["clojure"]
roots = ["project.clj", "deps.edn", ".git"]
command = "clojure-lsp"

This config is an educated guess. It seems fairly straightforward, but an explicit explanation on what should go on each line could be helpful.

Following the debugging strategy given in this post, I’m receiving the following output, which seems revealing, but I don’t know enough to act on it:

Jul 09 16:05:12.657 INFO Starting main event loop, module: kak_lsp::session:29
Jul 09 16:05:27.373 INFO Starting Language server `clojure-lsp `, module: kak_lsp::language_server_trans
port:21
Jul 09 16:05:27.374 ERRO panic: panicked at 'Failed to start language server: Os { code: 8, kind: Other,
message: "Exec format error" }', src/libcore/result.rs:1188:5, module: kak_lsp:252
Jul 09 16:05:27.376 INFO Waiting for Controller to finish..., module: kak_lsp::thread_worker:18
Jul 09 16:05:27.383 INFO ... Controller terminated with err, module: kak_lsp::thread_worker:20
Jul 09 16:05:27.384 ERRO panic: panicked at src/thread_worker.rs:29:17, module: kak_lsp:252
Jul 09 16:05:27.384 INFO Waiting for Messages to editor to finish..., module: kak_lsp::thread_worker:18
Jul 09 16:05:27.385 INFO ... Messages to editor terminated with ok, module: kak_lsp::thread_worker:20

Any insight into how I might proceed here, or in regards to configuring non-default language servers in general would be appreciated.

Thanks in advance!

This would seem to be the important bit:

Jul 09 16:05:27.374 ERRO panic: panicked at 'Failed to start language server: Os { code: 8, kind: Other,
message: "Exec format error" }', src/libcore/result.rs:1188:5, module: kak_lsp:252

“Exec format error” generally means that the program was found, but the OS kernel couldn’t figure out how to run it. Possible problems include:

  • it’s a 32-bit binary, but your OS only includes 64-bit libraries, or vice-versa
  • it’s a binary built for a different OS
    • macOS versus FreeBSD or FreeBSD versus Linux, or whatever
  • it’s VM code rather than machine-code, and the kernel can’t find the appropriate VM to run it in
    • Python bytecode in a .pyc file, or Java classes in a .jar, etc.

Specifically, since this is Clojure we’re talking about, I’m guessing the command should be something more like java -jar /path/to/clojure-lsp.jar or similar - although I’ve never used Clojure or it’s LSP before, so if the LSP is written in Node or something, then the problem’s probably somewhere else.

1 Like

Thanks for the insight. I looked closer into the clojure-lsp side of things and figured out that I could run the clojure-lsp directly, and test it by typing {}\n\n (that’s two presses of the return key), which would spit back a response indicating that it’s working.

Then I after some further digging, I reworked the kak-lsp.toml configuration and got it working:

[language.clojure]
filetypes = ["clojure"]
roots = ["project.clj", "deps.edn", ".git"]
command = "sh"
args = ["-c", "/usr/local/bin/clojure-lsp"]

However, I should make note of a couple of things.

  1. It takes several seconds for the lsp server to start up (don’t know if this is true for all language servers).
  2. The file ./.lsp/sqlite.1.db is automatically created in the project directory.

After further testing, the capabilities provided by clojure-lsp are working well. There are, however, additional refactorings provided that require additional configuration.

The clojure-clj readme states:

Calling executeCommand with the following commands and additional args will notify the client with applyEdit . All commands expect the first three args to be [document-uri, line, column] (eg ["file:///home/snoe/file.clj", 13, 11] )

Other clients might provide a higher level interface to workspace/executeCommand you need to pass the path, line and column numbers.

Further down is an example for Vim:

function! Expand(exp) abort
    let l:result = expand(a:exp)
    return l:result ==# '' ? '' : "file://" . l:result
endfunction

nnoremap <silent> crcc :call LanguageClient#workspace_executeCommand('cycle-coll', [Expand('%:p'), line('.') - 1, col('.') - 1])<CR>
nnoremap <silent> crth :call LanguageClient#workspace_executeCommand('thread-first', [Expand('%:p'), line('.') - 1, col('.') - 1])<CR>
...

Is there a way to call the executeCommand function for the kak-lsp client?

the equivalent is something like

define-command clojure-cycle-coll %{
	evaluate-commands -save-regs lc %{
		evaluate-commands %sh{
			echo set-register l $((kak_cursor_line - 1))
			echo set-register c $((kak_cursor_char_column - 1))
		}
		lsp-execute-command cycle-coll """[\""file://%val{buffile}\"", %reg{l}, %reg{c}]"""
	}
}

Note that for this specific command, there is an equivalent code action (a mapping in the lsp user mode) labeled “Change coll” which requires no configuration :slight_smile: