haskell / haskell-language-server

Official haskell ide support via language server (LSP). Successor of ghcide & haskell-ide-engine.
Apache License 2.0
2.66k stars 358 forks source link

Debugging a custom LSP client for HLS #3467

Closed chrislemaire closed 1 year ago

chrislemaire commented 1 year ago

I am trying to write a client for HLS, but so far things haven't been in my favour... I'm trying to debug why no connection is setup with HLS after the LSP library I'm using did not help with any useful error messages, but I fear I don't really understand the way LSP is implemented (perhaps in general).

Starting HLS with the following command gives me some output:

$ haskell-language-server-wrapper --lsp
No 'hie.yaml' found. Try to discover the project type!
Run entered for haskell-language-server-wrapper(haskell-language-server-wrapper) Version 1.9.0.0 x86_64 ghc-9.4.4
Current directory: /home/clemaire/Documents/idea-projects/haskell-sandbox
Operating system: linux
Arguments: ["--lsp"]
Cradle directory: /home/clemaire/Documents/idea-projects/haskell-sandbox
Cradle type: Stack

Tool versions found on the $PATH
cabal:          3.8.1.0
stack:          2.9.3
ghc:            9.2.5

Consulting the cradle to get project GHC version...
Project GHC version: 9.0.2
haskell-language-server exe candidates: ["haskell-language-server-9.0.2","haskell-language-server"]
Launching haskell-language-server exe at:/home/clemaire/.ghcup/bin/haskell-language-server-9.0.2
2023-01-26T12:02:00.858692Z | Info | No log file specified; using stderr.
2023-01-26T12:02:00.859161Z | Info | haskell-language-server version: 1.9.0.0 (GHC: 9.0.2) (PATH: /home/clemaire/.ghcup/hls/1.9.0.0/lib/haskell-language-server-1.9.0.0/bin/haskell-language-server-9.0.2)
2023-01-26T12:02:00.859785Z | Info | Directory: /home/clemaire/Documents/idea-projects/haskell-sandbox
2023-01-26T12:02:00.860088Z | Info | Starting (haskell-language-server) LSP server...
  GhcideArguments {argsCommand = LSP, argsCwd = Nothing, argsShakeProfiling = Nothing, argsTesting = False, argsExamplePlugin = False, argsDebugOn = False, argsLogFile = Nothing, argsThreads = 0, argsProjectGhcVersion = False}
  PluginIds: [ pragmas
             , LSPRecorderCallback
             , rename
             , ghcide-completions
             , class
             , refineImports
             , splice
             , cabal
             , changeTypeSignature
             , qualifyImportedNames
             , alternateNumberFormat
             , hlint
             , cabalfmt
             , explicit-fields
             , ghcide-code-actions-fill-holes
             , floskell
             , ghcide-extend-import-action
             , codeRange
             , haddockComments
             , importLens
             , retrie
             , ghcide-type-lenses
             , ghcide-code-actions-imports-exports
             , ghcide-hover-and-symbols
             , eval
             , gadt
             , fourmolu
             , tactics
             , callHierarchy
             , stylish-haskell
             , ghcide-code-actions-type-signatures
             , ghcide-code-actions-bindings
             , moduleName
             , ormolu
             , ghcide-core
             , explicit-fixity ]
2023-01-26T12:02:00.863910Z | Info | Logging heap statistics every 60.00s
 2023-01-26T12:02:00.871435Z | Info | Starting LSP server...
  If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!
  PluginIds: [ pragmas
             , LSPRecorderCallback
             , rename
             , ghcide-completions
             , class
             , refineImports
             , splice
             , cabal
             , changeTypeSignature
             , qualifyImportedNames
             , alternateNumberFormat
             , hlint
             , cabalfmt
             , explicit-fields
             , ghcide-code-actions-fill-holes
             , floskell
             , ghcide-extend-import-action
             , codeRange
             , haddockComments
             , importLens
             , retrie
             , ghcide-type-lenses
             , ghcide-code-actions-imports-exports
             , ghcide-hover-and-symbols
             , eval
             , gadt
             , fourmolu
             , tactics
             , callHierarchy
             , stylish-haskell
             , ghcide-code-actions-type-signatures
             , ghcide-code-actions-bindings
             , moduleName
             , ormolu
             , ghcide-core
             , explicit-fixity ]
2023-01-26T12:02:00.871977Z | Info | Starting server

I presume this means the server has started and can be used from this terminal? I tried sending bogus messages on this terminal and noticed a few things.

  1. Parsing of messages over the terminal is instant, probably because you're supposed to send messages in full.
  2. I can't seem to get any other message other than "Failed to parse message header: : string" out of this process.

In short, I have the following questions:

  1. Is it possible to manually debug an instance of HLS running in a terminal?
  2. When a message parsing error occurs, does HLS always instantly quit?
  3. Am I supposed to write directly to the input of the HLS process and read from the output, or is this process running a server that is accessed in a different way?
  4. When parsing JSON-RPC messages, are line endings required to be "\r\n"? So an invalid, but parsable message could be something like "Content-Length: 2\r\n\r\n{}". If so, that might also be the cause of some troubles while testing...

Your environment

Which OS do you use? Ubuntu

Which version of GHC do you use and how did you install it?

- How is your project built (alternative: link to the project)? -

Which LSP client (editor/plugin) do you use? Custom

Which version of HLS do you use and how did you install it? -

Have you configured HLS in any way (especially: a hie.yaml file)? -

What's wrong?

Debug information

fendor commented 1 year ago

Is it possible to manually debug an instance of HLS running in a terminal?

Not that I know of. Especially in LSP mode, where only protocol compliant clients are expected.

Am I supposed to write directly to the input of the HLS process and read from the output, or is this process running a server that is accessed in a different way?

That is correct, you write to hls's stdin, and you read the stdout.

When parsing JSON-RPC messages, are line endings required to be "\r\n"?

I believe so, but for details, you should read the LSP specification https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#headerPart

We are at least compliant with that, if we accept more, then feel free to open a bug-report.

michaelpj commented 1 year ago

No activity, closing as stale.