@hackage lsp1.1.1.0

Haskell library for the Microsoft Language Server Protocol

CI Hackage Hackage

lsp

Haskell library for the Microsoft Language Server Protocol. It currently implements all of the 3.15 specification.

It is split into two separate packages, lsp and lsp-types

  • lsp-types provides type-safe definitions that match up with the typescript definitions laid out in the specification
  • lsp is a library for building language servers, handling:
    • JSON-RPC transport
    • Keeping track of the document state in memory with the Virtual File System (VFS)
    • Responding to notifications and requests via handlers
    • Setting the server capabilities in the initialize request based on registered handlers
    • Dynamic registration of capabilities
    • Cancellable requests and progress notifications
    • Publishing and flushing of diagnostics

Language servers built on lsp

Example language servers

There are two example language servers in the example/ folder. Simple.hs provides a minimal example:

{-# LANGUAGE OverloadedStrings #-}

import Language.LSP.Server
import Language.LSP.Types
import Control.Monad.IO.Class
import qualified Data.Text as T

handlers :: Handlers (LspM ())
handlers = mconcat
  [ notificationHandler SInitialized $ \_not -> do
      let params = ShowMessageRequestParams MtInfo "Turn on code lenses?"
            (Just [MessageActionItem "Turn on", MessageActionItem "Don't"])
      _ <- sendRequest SWindowShowMessageRequest params $ \res ->
        case res of
          Right (Just (MessageActionItem "Turn on")) -> do
            let regOpts = CodeLensRegistrationOptions Nothing Nothing (Just False)
              
            _ <- registerCapability STextDocumentCodeLens regOpts $ \_req responder -> do
              let cmd = Command "Say hello" "lsp-hello-command" Nothing
                  rsp = List [CodeLens (mkRange 0 0 0 100) (Just cmd) Nothing]
              responder (Right rsp)
            pure ()
          Right _ ->
            sendNotification SWindowShowMessage (ShowMessageParams MtInfo "Not turning on code lenses")
          Left err ->
            sendNotification SWindowShowMessage (ShowMessageParams MtError $ "Something went wrong!\n" <> T.pack (show err))
      pure ()
  , requestHandler STextDocumentHover $ \req responder -> do
      let RequestMessage _ _ _ (HoverParams _doc pos _workDone) = req
          Position _l _c' = pos
          rsp = Hover ms (Just range)
          ms = HoverContents $ markedUpContent "lsp-demo-simple-server" "Hello world"
          range = Range pos pos
      responder (Right $ Just rsp)
  ]

main :: IO Int
main = runServer $ ServerDefinition
  { onConfigurationChange = const $ pure $ Right ()
  , doInitialize = \env _req -> pure $ Right env
  , staticHandlers = handlers
  , interpretHandler = \env -> Iso (runLspT env) liftIO
  , options = defaultOptions
  }

Whilst Reactor.hs shows how a reactor design can be used to handle all requests on a separate thread, such in a way that we could then execute them on multiple threads without blocking server communication. They can be installed from source with

cabal install lsp-demo-simple-server lsp-demo-reactor-server
stack install :lsp-demo-simple-server :lsp-demo-reactor-server --flag haskell-lsp:demo

Other resources

See #haskell-ide-engine on IRC freenode