rzk-0.7.4: src/Language/Rzk/VSCode/Lsp.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
module Language.Rzk.VSCode.Lsp where
import Control.Monad.IO.Class
import Control.Monad.Reader
import Data.Default.Class (Default (def))
import qualified Data.Text as T
import Language.LSP.Protocol.Message
import Language.LSP.Protocol.Types
import Language.LSP.Server
import Data.Aeson (Result (Error, Success),
fromJSON)
import Language.Rzk.VSCode.Config (ServerConfig (..))
import Language.Rzk.VSCode.Env
import Language.Rzk.VSCode.Handlers
-- | The maximum number of diagnostic messages to send to the client
maxDiagnosticCount :: Int
maxDiagnosticCount = 100
handlers :: Handlers LSP
handlers =
mconcat
[ notificationHandler SMethod_Initialized $ const typecheckFromConfigFile
-- TODO: add logging
-- Empty handlers to silence the errors
, notificationHandler SMethod_TextDocumentDidOpen $ \_msg -> pure ()
, notificationHandler SMethod_TextDocumentDidChange $ \_msg -> pure ()
, notificationHandler SMethod_TextDocumentDidClose $ \_msg -> pure ()
, notificationHandler SMethod_WorkspaceDidChangeWatchedFiles handleFilesChanged
, notificationHandler SMethod_TextDocumentDidSave $ \_msg -> do
-- TODO: check if the file is included in the config's `include` list.
-- If not (and not in `exclude`) either, issue a warning.
return () -- FIXME: typecheck standalone files (if they are not a part of the project)
-- An empty hadler is needed to silence the error since it is already handled by the LSP package
, notificationHandler SMethod_WorkspaceDidChangeConfiguration $ const $ pure ()
-- , requestHandler SMethod_TextDocumentHover $ \req responder -> do
-- TODO: Read from the list of symbols that is supposed to be cached by the typechecker
-- let TRequestMessage _ _ _ (HoverParams _doc pos _workDone) = req
-- Position _l _c' = pos
-- rsp = Hover (InL ms) (Just range')
-- ms = mkMarkdown "Hello world"
-- range' = Range pos pos
-- responder (Right $ InL rsp)
, requestHandler SMethod_TextDocumentCompletion provideCompletions
, requestHandler SMethod_TextDocumentSemanticTokensFull provideSemanticTokens
, requestHandler SMethod_TextDocumentFormatting formatDocument
]
syncOptions :: TextDocumentSyncOptions
syncOptions = TextDocumentSyncOptions
{ _openClose = Just True
, _change = Just TextDocumentSyncKind_Full
, _willSave = Just False
, _willSaveWaitUntil = Just False
, _save = Just $ InR $ SaveOptions { _includeText = Just True }
}
runLsp :: IO Int
runLsp = do
rzkEnv <- defaultRzkEnv
runServer $
ServerDefinition
{ configSection = "rzk"
, parseConfig = \_oldConfig newObject -> case fromJSON newObject of
-- TODO: handle partial config updates from VS Code by updating oldConfig rather than parsing from scratch
Error err -> Left $ T.pack err
Success rzkConfig -> Right rzkConfig
, onConfigChange = const $ pure ()
, doInitialize = const . pure . Right
, staticHandlers = const handlers
, interpretHandler = \env -> Iso (flip runReaderT rzkEnv . runLspT env) liftIO
, options = defaultOptions { optTextDocumentSync = Just syncOptions }
, defaultConfig = def :: ServerConfig
}