{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Main where import Control.Concurrent import Control.Lens import Control.Monad import Data.Proxy import qualified Data.Text.IO as T import qualified LSP.Client as Client import qualified Language.Haskell.LSP.TH.ClientCapabilities as LSP import qualified Language.Haskell.LSP.TH.DataTypesJSON as LSP import System.Directory import System.Environment import System.Exit import System.IO import System.Process import qualified Compat main :: IO () main = do progName <- getProgName args <- getArgs when (length args /= 1) $ do hPutStrLn stderr ("This program expects one argument: " ++ progName ++ " FILEPATH") exitFailure let [path] = args exists <- doesFileExist path unless exists $ do hPutStrLn stderr ("File does not exist: " ++ path) exitFailure file <- canonicalizePath path pid <- Compat.getPID let caps = LSP.ClientCapabilities (Just workspaceCaps) (Just textDocumentCaps) Nothing workspaceCaps = LSP.WorkspaceClientCapabilities (Just False) (Just (LSP.WorkspaceEditClientCapabilities (Just False))) (Just (LSP.DidChangeConfigurationClientCapabilities (Just False))) (Just (LSP.DidChangeWatchedFilesClientCapabilities (Just False))) (Just (LSP.SymbolClientCapabilities (Just False))) (Just (LSP.ExecuteClientCapabilities (Just False))) textDocumentCaps = LSP.TextDocumentClientCapabilities ( Just ( LSP.SynchronizationTextDocumentClientCapabilities (Just False) (Just False) (Just False) (Just False) ) ) ( Just ( LSP.CompletionClientCapabilities (Just False) (Just (LSP.CompletionItemClientCapabilities (Just False))) ) ) (Just (LSP.HoverClientCapabilities (Just False))) (Just (LSP.SignatureHelpClientCapabilities (Just False))) (Just (LSP.ReferencesClientCapabilities (Just False))) (Just (LSP.DocumentHighlightClientCapabilities (Just False))) (Just (LSP.DocumentSymbolClientCapabilities (Just False))) (Just (LSP.FormattingClientCapabilities (Just False))) (Just (LSP.RangeFormattingClientCapabilities (Just False))) (Just (LSP.OnTypeFormattingClientCapabilities (Just False))) (Just (LSP.DefinitionClientCapabilities (Just False))) (Just (LSP.CodeActionClientCapabilities (Just False))) (Just (LSP.CodeLensClientCapabilities (Just False))) (Just (LSP.DocumentLinkClientCapabilities (Just False))) (Just (LSP.RenameClientCapabilities (Just False))) (Just (LSP.CallHierarchyClientCapabilities (Just False))) initializeParams :: LSP.InitializeParams initializeParams = LSP.InitializeParams (Just pid) Nothing Nothing Nothing caps Nothing (Just inp, Just out, _, _) <- createProcess (proc "hie" ["--lsp", "-l", "/tmp/hie.log", "--debug"]) { std_in = CreatePipe , std_out = CreatePipe , std_err = CreatePipe } client <- Client.start (Client.Config inp out testNotificationMessageHandler testRequestMessageHandler) Client.sendClientRequest client (Proxy :: Proxy LSP.InitializeRequest) LSP.Initialize initializeParams Client.sendClientNotification client LSP.Initialized (Just LSP.InitializedParams) txt <- T.readFile file let uri = LSP.filePathToUri file Client.sendClientNotification client LSP.TextDocumentDidOpen (Just (LSP.DidOpenTextDocumentParams (LSP.TextDocumentItem uri "haskell" 1 txt))) Client.sendClientRequest client (Proxy :: Proxy LSP.DefinitionRequest) LSP.TextDocumentDefinition (LSP.TextDocumentPositionParams (LSP.TextDocumentIdentifier uri) (LSP.Position 88 36)) >>= \case Just (Right pos) -> print pos _ -> putStrLn "Server couldn't give us defnition position" Client.sendClientRequest client (Proxy :: Proxy LSP.DocumentSymbolRequest) LSP.TextDocumentDocumentSymbol (LSP.DocumentSymbolParams (LSP.TextDocumentIdentifier uri)) >>= \case Just (Right as) -> mapM_ T.putStrLn (as ^.. traverse . LSP.name) _ -> putStrLn "Server couldn't give us document symbol information" Client.sendClientRequest client (Proxy :: Proxy LSP.ShutdownRequest) LSP.Shutdown Nothing Client.sendClientNotification client LSP.Exit (Just LSP.ExitParams) Client.stop client testRequestMessageHandler :: Client.RequestMessageHandler testRequestMessageHandler = Client.RequestMessageHandler (\m -> emptyResponse m <$ print m) (\m -> emptyResponse m <$ print m) (\m -> emptyResponse m <$ print m) (\m -> emptyResponse m <$ print m) where toRspId (LSP.IdInt i) = LSP.IdRspInt i toRspId (LSP.IdString t) = LSP.IdRspString t emptyResponse :: LSP.RequestMessage m req resp -> LSP.ResponseMessage a emptyResponse m = LSP.ResponseMessage (m ^. LSP.jsonrpc) (toRspId (m ^. LSP.id)) Nothing Nothing testNotificationMessageHandler :: Client.NotificationMessageHandler testNotificationMessageHandler = Client.NotificationMessageHandler (T.putStrLn . view (LSP.params . LSP.message)) (T.putStrLn . view (LSP.params . LSP.message)) (print . view LSP.params) (mapM_ T.putStrLn . (^.. LSP.params . LSP.diagnostics . traverse . LSP.message))