SourceKit-LSP interaction in shell

Hi, just as a proof of concept, I'm trying to interact with SourceKit-LSP in the terminal, but can't get a response when I provide Content-Length: followed by any JSON-object. The only way I have managed to get a response is by omitting the header part, which gives me an error message before the server exits.

Just to make sure, I tried the same thing in a simple app using LanguageClient. In the app

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"rootUri":"file:\/\/\/Users\/einar\/","capabilities":{},"processId":40312}}

returns

{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"hoverProvider":true,"implementationProvider":true,"colorProvider":true,"codeActionProvider":true,"foldingRangeProvider":true,"documentHighlightProvider":true,"definitionProvider":true,"documentSymbolProvider":true,"executeCommandProvider":{"commands":["semantic.refactor.command"]},"completionProvider":{"resolveProvider":false,"triggerCharacters":["."]},"referencesProvider":true,"textDocumentSync":{"willSave":true,"save":{"includeText":false},"openClose":true,"change":2,"willSaveWaitUntil":false},"workspaceSymbolProvider":true,"workspace":{"workspaceFolders":{"changeNotifications":true,"supported":true}}}}}

But the same JSON (with the correct proc id for the server running) returns nothing when pasted/typed directly into the terminal. I have also tried controlling for backslash and byte count in the 'Content-Length:', and both with and without \r\n, but still, nothing.

What am I doing wrong?

1 Like

I just tried it as well and I think the main problem here is to send a carriage return to sourcekit-lsp using the macOS Terminal application because Terminal apparently translates carriage return to line feed even if you explicitly send a carriage return using the character viewer (aka. emoji picker).

The best way I have found to work around this was:

  • Create a text file with the messages you want to send with Windows line endings (e.g. in Sublime Text you can set the line endings)
  • In terminal create a pipe that we’ll use to feed the text input file to sourcekit-lsp: mkfifo /tmp/in (this will create a pipe “file” in /tmp/in)
  • Launch sourcekit-lsp with the input from the pipe: path/to/sourcekit-lsp < /tmp/in
  • In another terminal window send the contents of the input file to the pipe: (cat /path/to/input/file; sleep 1) > in. The sleep command appears to be necessary so cat doesn’t close the pipe when it’s done sending the contents. That way sourcekit-lsp has time to send its initialized notification.

The following text file worked for me (I assume copy pasting will mess up the line endings though)

Content-Length: 131

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"rootUri":"file:\/\/\/Users\/einar\/","capabilities":{},"processId":40312}}
1 Like

Indeed! Line break differences in Windows and Unix, and particular ways the shell interacts with the terminal makes it hard to feed stdin directly. I could get it to work by providing carriage return control character (ctrl-v ctrl-m) after each line, at least one time before the server exited. I guess there must be some form of IPC to keep things sane. Thank you for taking some time to figure this one out.