{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
module Development.IDE.LSP.LanguageServer
( runLanguageServer
, setupLSP
, Log(..)
) where
import Control.Concurrent.STM
import Control.Monad.Extra
import Control.Monad.IO.Class
import Control.Monad.Reader
import Data.Aeson (Value)
import Data.Maybe
import qualified Data.Set as Set
import qualified Data.Text as T
import Development.IDE.LSP.Server
import Development.IDE.Session (runWithDb)
import Ide.Types (traceWithSpan)
import Language.LSP.Protocol.Message
import Language.LSP.Protocol.Types
import qualified Language.LSP.Server as LSP
import System.IO
import UnliftIO.Async
import UnliftIO.Concurrent
import UnliftIO.Directory
import UnliftIO.Exception
import qualified Colog.Core as Colog
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Development.IDE.Core.IdeConfiguration
import Development.IDE.Core.Shake hiding (Log, Priority)
import Development.IDE.Core.Tracing
import qualified Development.IDE.Session as Session
import Development.IDE.Types.Shake (WithHieDb)
import Ide.Logger
import Language.LSP.Server (LanguageContextEnv,
LspServerLog,
type (<~>))
import System.IO.Unsafe (unsafeInterleaveIO)
data Log
= LogRegisteringIdeConfig !IdeConfiguration
| LogReactorThreadException !SomeException
| LogReactorMessageActionException !SomeException
| LogReactorThreadStopped
| LogCancelledRequest !SomeLspId
| LogSession Session.Log
| LogLspServer LspServerLog
deriving Int -> Log -> ShowS
[Log] -> ShowS
Log -> String
(Int -> Log -> ShowS)
-> (Log -> String) -> ([Log] -> ShowS) -> Show Log
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Log -> ShowS
showsPrec :: Int -> Log -> ShowS
$cshow :: Log -> String
show :: Log -> String
$cshowList :: [Log] -> ShowS
showList :: [Log] -> ShowS
Show
instance Pretty Log where
pretty :: forall ann. Log -> Doc ann
pretty = \case
LogRegisteringIdeConfig IdeConfiguration
ideConfig ->
Doc ann
"Registering IDE configuration:" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> IdeConfiguration -> Doc ann
forall a ann. Show a => a -> Doc ann
viaShow IdeConfiguration
ideConfig
LogReactorThreadException SomeException
e ->
[Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vcat
[ Doc ann
"ReactorThreadException"
, String -> Doc ann
forall ann. String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (String -> Doc ann) -> String -> Doc ann
forall a b. (a -> b) -> a -> b
$ SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
e ]
LogReactorMessageActionException SomeException
e ->
[Doc ann] -> Doc ann
forall ann. [Doc ann] -> Doc ann
vcat
[ Doc ann
"ReactorMessageActionException"
, String -> Doc ann
forall ann. String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (String -> Doc ann) -> String -> Doc ann
forall a b. (a -> b) -> a -> b
$ SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
e ]
Log
LogReactorThreadStopped ->
Doc ann
"Reactor thread stopped"
LogCancelledRequest SomeLspId
requestId ->
Doc ann
"Cancelled request" Doc ann -> Doc ann -> Doc ann
forall ann. Doc ann -> Doc ann -> Doc ann
<+> SomeLspId -> Doc ann
forall a ann. Show a => a -> Doc ann
viaShow SomeLspId
requestId
LogSession Log
msg -> Log -> Doc ann
forall a ann. Pretty a => a -> Doc ann
forall ann. Log -> Doc ann
pretty Log
msg
LogLspServer LspServerLog
msg -> LspServerLog -> Doc ann
forall a ann. Pretty a => a -> Doc ann
forall ann. LspServerLog -> Doc ann
pretty LspServerLog
msg
newtype WithHieDbShield = WithHieDbShield WithHieDb
runLanguageServer
:: forall config a m. (Show config)
=> Recorder (WithPriority Log)
-> LSP.Options
-> Handle
-> Handle
-> config
-> (config -> Value -> Either T.Text config)
-> (config -> m config ())
-> (MVar ()
-> IO (LSP.LanguageContextEnv config -> TRequestMessage Method_Initialize -> IO (Either ResponseError (LSP.LanguageContextEnv config, a)),
LSP.Handlers (m config),
(LanguageContextEnv config, a) -> m config <~> IO))
-> IO ()
runLanguageServer :: forall config a (m :: * -> * -> *).
Show config =>
Recorder (WithPriority Log)
-> Options
-> Handle
-> Handle
-> config
-> (config -> Value -> Either Text config)
-> (config -> m config ())
-> (MVar ()
-> IO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a)),
Handlers (m config),
(LanguageContextEnv config, a) -> m config <~> IO))
-> IO ()
runLanguageServer Recorder (WithPriority Log)
recorder Options
options Handle
inH Handle
outH config
defaultConfig config -> Value -> Either Text config
parseConfig config -> m config ()
onConfigChange MVar ()
-> IO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a)),
Handlers (m config),
(LanguageContextEnv config, a) -> m config <~> IO)
setup = do
MVar ()
clientMsgVar <- IO (MVar ())
forall (m :: * -> *) a. MonadIO m => m (MVar a)
newEmptyMVar
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a))
doInitialize, Handlers (m config)
staticHandlers, (LanguageContextEnv config, a) -> m config <~> IO
interpretHandler) <- MVar ()
-> IO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a)),
Handlers (m config),
(LanguageContextEnv config, a) -> m config <~> IO)
setup MVar ()
clientMsgVar
let serverDefinition :: ServerDefinition config
serverDefinition = LSP.ServerDefinition
{ parseConfig :: config -> Value -> Either Text config
LSP.parseConfig = config -> Value -> Either Text config
parseConfig
, onConfigChange :: config -> m config ()
LSP.onConfigChange = config -> m config ()
onConfigChange
, defaultConfig :: config
LSP.defaultConfig = config
defaultConfig
, configSection :: Text
LSP.configSection = Text
"haskell"
, doInitialize :: LanguageContextEnv config
-> TMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a))
LSP.doInitialize = LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a))
LanguageContextEnv config
-> TMessage 'Method_Initialize
-> IO (Either ResponseError (LanguageContextEnv config, a))
doInitialize
, staticHandlers :: ClientCapabilities -> Handlers (m config)
LSP.staticHandlers = Handlers (m config) -> ClientCapabilities -> Handlers (m config)
forall a b. a -> b -> a
const Handlers (m config)
staticHandlers
, interpretHandler :: (LanguageContextEnv config, a) -> m config <~> IO
LSP.interpretHandler = (LanguageContextEnv config, a) -> m config <~> IO
interpretHandler
, options :: Options
LSP.options = Options -> Options
modifyOptions Options
options
}
let lspCologAction :: MonadIO m2 => Colog.LogAction m2 (Colog.WithSeverity LspServerLog)
lspCologAction :: forall (m2 :: * -> *).
MonadIO m2 =>
LogAction m2 (WithSeverity LspServerLog)
lspCologAction = Recorder (WithPriority LspServerLog)
-> LogAction m2 (WithSeverity LspServerLog)
forall (m :: * -> *) msg.
(MonadIO m, HasCallStack) =>
Recorder (WithPriority msg) -> LogAction m (WithSeverity msg)
toCologActionWithPrio ((LspServerLog -> Log)
-> Recorder (WithPriority Log)
-> Recorder (WithPriority LspServerLog)
forall a b.
(a -> b) -> Recorder (WithPriority b) -> Recorder (WithPriority a)
cmapWithPrio LspServerLog -> Log
LogLspServer Recorder (WithPriority Log)
recorder)
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> IO () -> IO ()
forall (m :: * -> *). MonadUnliftIO m => MVar () -> m () -> m ()
untilMVar MVar ()
clientMsgVar (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IO Int -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Int -> IO ()) -> IO Int -> IO ()
forall a b. (a -> b) -> a -> b
$ LogAction IO (WithSeverity LspServerLog)
-> LogAction (LspM config) (WithSeverity LspServerLog)
-> Handle
-> Handle
-> ServerDefinition config
-> IO Int
forall config.
LogAction IO (WithSeverity LspServerLog)
-> LogAction (LspM config) (WithSeverity LspServerLog)
-> Handle
-> Handle
-> ServerDefinition config
-> IO Int
LSP.runServerWithHandles
LogAction IO (WithSeverity LspServerLog)
forall (m2 :: * -> *).
MonadIO m2 =>
LogAction m2 (WithSeverity LspServerLog)
lspCologAction
LogAction (LspM config) (WithSeverity LspServerLog)
forall (m2 :: * -> *).
MonadIO m2 =>
LogAction m2 (WithSeverity LspServerLog)
lspCologAction
Handle
inH
Handle
outH
ServerDefinition config
serverDefinition
setupLSP ::
forall config err.
Recorder (WithPriority Log)
-> (FilePath -> IO FilePath)
-> LSP.Handlers (ServerM config)
-> (LSP.LanguageContextEnv config -> Maybe FilePath -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO (LSP.LanguageContextEnv config -> TRequestMessage Method_Initialize -> IO (Either err (LSP.LanguageContextEnv config, IdeState)),
LSP.Handlers (ServerM config),
(LanguageContextEnv config, IdeState) -> ServerM config <~> IO)
setupLSP :: forall config err.
Recorder (WithPriority Log)
-> (String -> IO String)
-> Handlers (ServerM config)
-> (LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState)),
Handlers (ServerM config),
(LanguageContextEnv config, IdeState) -> ServerM config <~> IO)
setupLSP Recorder (WithPriority Log)
recorder String -> IO String
getHieDbLoc Handlers (ServerM config)
userHandlers LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState
getIdeState MVar ()
clientMsgVar = do
Chan ReactorMessage
clientMsgChan :: Chan ReactorMessage <- IO (Chan ReactorMessage)
forall (m :: * -> *) a. MonadIO m => m (Chan a)
newChan
MVar ()
reactorLifetime <- IO (MVar ())
forall (m :: * -> *) a. MonadIO m => m (MVar a)
newEmptyMVar
let stopReactorLoop :: IO ()
stopReactorLoop = IO Bool -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Bool -> IO ()) -> IO Bool -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> () -> IO Bool
forall (m :: * -> *) a. MonadIO m => MVar a -> a -> m Bool
tryPutMVar MVar ()
reactorLifetime ()
let exit :: IO ()
exit = IO Bool -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Bool -> IO ()) -> IO Bool -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar () -> () -> IO Bool
forall (m :: * -> *) a. MonadIO m => MVar a -> a -> m Bool
tryPutMVar MVar ()
clientMsgVar ()
TVar (Set SomeLspId)
pendingRequests <- Set SomeLspId -> IO (TVar (Set SomeLspId))
forall a. a -> IO (TVar a)
newTVarIO Set SomeLspId
forall a. Set a
Set.empty
TVar (Set SomeLspId)
cancelledRequests <- Set SomeLspId -> IO (TVar (Set SomeLspId))
forall a. a -> IO (TVar a)
newTVarIO Set SomeLspId
forall a. Set a
Set.empty
let cancelRequest :: SomeLspId -> IO ()
cancelRequest SomeLspId
reqId = STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Set SomeLspId
queued <- TVar (Set SomeLspId) -> STM (Set SomeLspId)
forall a. TVar a -> STM a
readTVar TVar (Set SomeLspId)
pendingRequests
Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (SomeLspId
reqId SomeLspId -> Set SomeLspId -> Bool
forall a. Eq a => a -> Set a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Set SomeLspId
queued) (STM () -> STM ()) -> STM () -> STM ()
forall a b. (a -> b) -> a -> b
$
TVar (Set SomeLspId) -> (Set SomeLspId -> Set SomeLspId) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar TVar (Set SomeLspId)
cancelledRequests (SomeLspId -> Set SomeLspId -> Set SomeLspId
forall a. Ord a => a -> Set a -> Set a
Set.insert SomeLspId
reqId)
let clearReqId :: SomeLspId -> IO ()
clearReqId SomeLspId
reqId = STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
TVar (Set SomeLspId) -> (Set SomeLspId -> Set SomeLspId) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar TVar (Set SomeLspId)
pendingRequests (SomeLspId -> Set SomeLspId -> Set SomeLspId
forall a. Ord a => a -> Set a -> Set a
Set.delete SomeLspId
reqId)
TVar (Set SomeLspId) -> (Set SomeLspId -> Set SomeLspId) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar TVar (Set SomeLspId)
cancelledRequests (SomeLspId -> Set SomeLspId -> Set SomeLspId
forall a. Ord a => a -> Set a -> Set a
Set.delete SomeLspId
reqId)
let waitForCancel :: SomeLspId -> IO ()
waitForCancel SomeLspId
reqId = STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Set SomeLspId
cancelled <- TVar (Set SomeLspId) -> STM (Set SomeLspId)
forall a. TVar a -> STM a
readTVar TVar (Set SomeLspId)
cancelledRequests
Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (SomeLspId
reqId SomeLspId -> Set SomeLspId -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set SomeLspId
cancelled) STM ()
forall a. STM a
retry
let asyncHandlers :: Handlers (ServerM config)
asyncHandlers = [Handlers (ServerM config)] -> Handlers (ServerM config)
forall a. Monoid a => [a] -> a
mconcat
[ Handlers (ServerM config)
userHandlers
, (SomeLspId -> IO ()) -> Handlers (ServerM config)
forall c. (SomeLspId -> IO ()) -> Handlers (ServerM c)
cancelHandler SomeLspId -> IO ()
cancelRequest
, IO () -> Handlers (ServerM config)
forall c. IO () -> Handlers (ServerM c)
exitHandler IO ()
exit
, IO () -> Handlers (ServerM config)
forall c. IO () -> Handlers (ServerM c)
shutdownHandler IO ()
stopReactorLoop
]
let doInitialize :: LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
doInitialize = Recorder (WithPriority Log)
-> (String -> IO String)
-> (LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
forall config err.
Recorder (WithPriority Log)
-> (String -> IO String)
-> (LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
handleInit Recorder (WithPriority Log)
recorder String -> IO String
getHieDbLoc LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState
getIdeState MVar ()
reactorLifetime IO ()
exit SomeLspId -> IO ()
clearReqId SomeLspId -> IO ()
waitForCancel Chan ReactorMessage
clientMsgChan
let interpretHandler :: (LanguageContextEnv config, IdeState) -> ServerM config <~> IO
interpretHandler (LanguageContextEnv config
env, IdeState
st) = (forall a. ServerM config a -> IO a)
-> (forall a. IO a -> ServerM config a) -> ServerM config <~> IO
forall {k} (m :: k -> *) (n :: k -> *).
(forall (a :: k). m a -> n a)
-> (forall (a :: k). n a -> m a) -> m <~> n
LSP.Iso (LanguageContextEnv config -> LspT config IO a -> IO a
forall config (m :: * -> *) a.
LanguageContextEnv config -> LspT config m a -> m a
LSP.runLspT LanguageContextEnv config
env (LspT config IO a -> IO a)
-> (ServerM config a -> LspT config IO a)
-> ServerM config a
-> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ServerM config a
-> (Chan ReactorMessage, IdeState) -> LspT config IO a)
-> (Chan ReactorMessage, IdeState)
-> ServerM config a
-> LspT config IO a
forall a b c. (a -> b -> c) -> b -> a -> c
flip (ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
-> (Chan ReactorMessage, IdeState) -> LspT config IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
-> (Chan ReactorMessage, IdeState) -> LspT config IO a)
-> (ServerM config a
-> ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a)
-> ServerM config a
-> (Chan ReactorMessage, IdeState)
-> LspT config IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ServerM config a
-> ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
forall c a.
ServerM c a -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) a
unServerM) (Chan ReactorMessage
clientMsgChan,IdeState
st)) IO a -> ServerM config a
forall a. IO a -> ServerM config a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState)),
Handlers (ServerM config),
(LanguageContextEnv config, IdeState) -> ServerM config <~> IO)
-> IO
(LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState)),
Handlers (ServerM config),
(LanguageContextEnv config, IdeState) -> ServerM config <~> IO)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
doInitialize, Handlers (ServerM config)
asyncHandlers, (LanguageContextEnv config, IdeState) -> ServerM config <~> IO
interpretHandler)
handleInit
:: Recorder (WithPriority Log)
-> (FilePath -> IO FilePath)
-> (LSP.LanguageContextEnv config -> Maybe FilePath -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LSP.LanguageContextEnv config -> TRequestMessage Method_Initialize -> IO (Either err (LSP.LanguageContextEnv config, IdeState))
handleInit :: forall config err.
Recorder (WithPriority Log)
-> (String -> IO String)
-> (LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState)
-> MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> TRequestMessage 'Method_Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
handleInit Recorder (WithPriority Log)
recorder String -> IO String
getHieDbLoc LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState
getIdeState MVar ()
lifetime IO ()
exitClientMsg SomeLspId -> IO ()
clearReqId SomeLspId -> IO ()
waitForCancel Chan ReactorMessage
clientMsgChan LanguageContextEnv config
env (TRequestMessage Text
_ LspId 'Method_Initialize
_ SMethod 'Method_Initialize
m MessageParams 'Method_Initialize
params) = String
-> String
-> (SpanInFlight
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> IO (Either err (LanguageContextEnv config, IdeState))
forall (m :: * -> *) a.
MonadUnliftIO m =>
String -> String -> (SpanInFlight -> m a) -> m a
otTracedHandler String
"Initialize" (SMethod 'Method_Initialize -> String
forall a. Show a => a -> String
show SMethod 'Method_Initialize
m) ((SpanInFlight
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> (SpanInFlight
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> IO (Either err (LanguageContextEnv config, IdeState))
forall a b. (a -> b) -> a -> b
$ \SpanInFlight
sp -> do
SpanInFlight -> InitializeParams -> IO ()
forall a. HasTracing a => SpanInFlight -> a -> IO ()
traceWithSpan SpanInFlight
sp InitializeParams
MessageParams 'Method_Initialize
params
let root :: Maybe String
root = LanguageContextEnv config -> Maybe String
forall config. LanguageContextEnv config -> Maybe String
LSP.resRootPath LanguageContextEnv config
env
String
dir <- IO String -> (String -> IO String) -> Maybe String -> IO String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO String
forall (m :: * -> *). MonadIO m => m String
getCurrentDirectory String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
root
String
dbLoc <- String -> IO String
getHieDbLoc String
dir
MVar (WithHieDbShield, IndexQueue)
dbMVar <- IO (MVar (WithHieDbShield, IndexQueue))
forall (m :: * -> *) a. MonadIO m => m (MVar a)
newEmptyMVar
~(WithHieDbShield WithHieDb
withHieDb,IndexQueue
hieChan) <- IO (WithHieDbShield, IndexQueue)
-> IO (WithHieDbShield, IndexQueue)
forall a. IO a -> IO a
unsafeInterleaveIO (IO (WithHieDbShield, IndexQueue)
-> IO (WithHieDbShield, IndexQueue))
-> IO (WithHieDbShield, IndexQueue)
-> IO (WithHieDbShield, IndexQueue)
forall a b. (a -> b) -> a -> b
$ MVar (WithHieDbShield, IndexQueue)
-> IO (WithHieDbShield, IndexQueue)
forall (m :: * -> *) a. MonadIO m => MVar a -> m a
takeMVar MVar (WithHieDbShield, IndexQueue)
dbMVar
IdeState
ide <- LanguageContextEnv config
-> Maybe String -> WithHieDb -> IndexQueue -> IO IdeState
getIdeState LanguageContextEnv config
env Maybe String
root (HieDb -> IO a) -> IO a
WithHieDb
withHieDb IndexQueue
hieChan
let initConfig :: IdeConfiguration
initConfig = InitializeParams -> IdeConfiguration
parseConfiguration InitializeParams
MessageParams 'Method_Initialize
params
Recorder (WithPriority Log) -> Priority -> Log -> IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Info (Log -> IO ()) -> Log -> IO ()
forall a b. (a -> b) -> a -> b
$ IdeConfiguration -> Log
LogRegisteringIdeConfig IdeConfiguration
initConfig
ShakeExtras -> IdeConfiguration -> IO ()
registerIdeConfiguration (IdeState -> ShakeExtras
shakeExtras IdeState
ide) IdeConfiguration
initConfig
let handleServerException :: Either SomeException () -> IO ()
handleServerException (Left SomeException
e) = do
Recorder (WithPriority Log) -> Priority -> Log -> IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Error (Log -> IO ()) -> Log -> IO ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Log
LogReactorThreadException SomeException
e
IO ()
exitClientMsg
handleServerException (Right ()
_) = () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
exceptionInHandler :: SomeException -> IO ()
exceptionInHandler SomeException
e = do
Recorder (WithPriority Log) -> Priority -> Log -> IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Error (Log -> IO ()) -> Log -> IO ()
forall a b. (a -> b) -> a -> b
$ SomeException -> Log
LogReactorMessageActionException SomeException
e
checkCancelled :: SomeLspId -> IO () -> (ResponseError -> IO ()) -> IO ()
checkCancelled SomeLspId
_id IO ()
act ResponseError -> IO ()
k =
(IO () -> IO () -> IO ()) -> IO () -> IO () -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip IO () -> IO () -> IO ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m a
finally (SomeLspId -> IO ()
clearReqId SomeLspId
_id) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IO () -> (SomeException -> IO ()) -> IO ()
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
catch (do
Either () ()
cancelOrRes <- IO () -> IO () -> IO (Either () ())
forall (m :: * -> *) a b.
MonadUnliftIO m =>
m a -> m b -> m (Either a b)
race (SomeLspId -> IO ()
waitForCancel SomeLspId
_id) IO ()
act
case Either () ()
cancelOrRes of
Left () -> do
Recorder (WithPriority Log) -> Priority -> Log -> IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Debug (Log -> IO ()) -> Log -> IO ()
forall a b. (a -> b) -> a -> b
$ SomeLspId -> Log
LogCancelledRequest SomeLspId
_id
ResponseError -> IO ()
k (ResponseError -> IO ()) -> ResponseError -> IO ()
forall a b. (a -> b) -> a -> b
$ (LSPErrorCodes |? ErrorCodes)
-> Text -> Maybe Value -> ResponseError
ResponseError (LSPErrorCodes -> LSPErrorCodes |? ErrorCodes
forall a b. a -> a |? b
InL LSPErrorCodes
LSPErrorCodes_RequestCancelled) Text
"" Maybe Value
forall a. Maybe a
Nothing
Right ()
res -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
res
) ((SomeException -> IO ()) -> IO ())
-> (SomeException -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(SomeException
e :: SomeException) -> do
SomeException -> IO ()
exceptionInHandler SomeException
e
ResponseError -> IO ()
k (ResponseError -> IO ()) -> ResponseError -> IO ()
forall a b. (a -> b) -> a -> b
$ (LSPErrorCodes |? ErrorCodes)
-> Text -> Maybe Value -> ResponseError
ResponseError (ErrorCodes -> LSPErrorCodes |? ErrorCodes
forall a b. b -> a |? b
InR ErrorCodes
ErrorCodes_InternalError) (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ SomeException -> String
forall a. Show a => a -> String
show SomeException
e) Maybe Value
forall a. Maybe a
Nothing
ThreadId
_ <- (IO () -> (Either SomeException () -> IO ()) -> IO ThreadId)
-> (Either SomeException () -> IO ()) -> IO () -> IO ThreadId
forall a b c. (a -> b -> c) -> b -> a -> c
flip IO () -> (Either SomeException () -> IO ()) -> IO ThreadId
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (Either SomeException a -> m ()) -> m ThreadId
forkFinally Either SomeException () -> IO ()
handleServerException (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do
MVar () -> IO () -> IO ()
forall (m :: * -> *). MonadUnliftIO m => MVar () -> m () -> m ()
untilMVar MVar ()
lifetime (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Recorder (WithPriority Log)
-> String -> (WithHieDb -> IndexQueue -> IO ()) -> IO ()
runWithDb ((Log -> Log)
-> Recorder (WithPriority Log) -> Recorder (WithPriority Log)
forall a b.
(a -> b) -> Recorder (WithPriority b) -> Recorder (WithPriority a)
cmapWithPrio Log -> Log
LogSession Recorder (WithPriority Log)
recorder) String
dbLoc ((WithHieDb -> IndexQueue -> IO ()) -> IO ())
-> (WithHieDb -> IndexQueue -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \WithHieDb
withHieDb' IndexQueue
hieChan' -> do
MVar (WithHieDbShield, IndexQueue)
-> (WithHieDbShield, IndexQueue) -> IO ()
forall (m :: * -> *) a. MonadIO m => MVar a -> a -> m ()
putMVar MVar (WithHieDbShield, IndexQueue)
dbMVar (WithHieDb -> WithHieDbShield
WithHieDbShield (HieDb -> IO a) -> IO a
WithHieDb
withHieDb',IndexQueue
hieChan')
IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
ReactorMessage
msg <- Chan ReactorMessage -> IO ReactorMessage
forall (m :: * -> *) a. MonadIO m => Chan a -> m a
readChan Chan ReactorMessage
clientMsgChan
case ReactorMessage
msg of
ReactorNotification IO ()
act -> (SomeException -> IO ()) -> IO () -> IO ()
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
(e -> m a) -> m a -> m a
handle SomeException -> IO ()
exceptionInHandler IO ()
act
ReactorRequest SomeLspId
_id IO ()
act ResponseError -> IO ()
k -> IO (Async ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Async ()) -> IO ()) -> IO (Async ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO (Async ())
forall (m :: * -> *) a. MonadUnliftIO m => m a -> m (Async a)
async (IO () -> IO (Async ())) -> IO () -> IO (Async ())
forall a b. (a -> b) -> a -> b
$ SomeLspId -> IO () -> (ResponseError -> IO ()) -> IO ()
checkCancelled SomeLspId
_id IO ()
act ResponseError -> IO ()
k
Recorder (WithPriority Log) -> Priority -> Log -> IO ()
forall (m :: * -> *) msg.
(HasCallStack, MonadIO m) =>
Recorder (WithPriority msg) -> Priority -> msg -> m ()
logWith Recorder (WithPriority Log)
recorder Priority
Info Log
LogReactorThreadStopped
Either err (LanguageContextEnv config, IdeState)
-> IO (Either err (LanguageContextEnv config, IdeState))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either err (LanguageContextEnv config, IdeState)
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> Either err (LanguageContextEnv config, IdeState)
-> IO (Either err (LanguageContextEnv config, IdeState))
forall a b. (a -> b) -> a -> b
$ (LanguageContextEnv config, IdeState)
-> Either err (LanguageContextEnv config, IdeState)
forall a b. b -> Either a b
Right (LanguageContextEnv config
env,IdeState
ide)
untilMVar :: MonadUnliftIO m => MVar () -> m () -> m ()
untilMVar :: forall (m :: * -> *). MonadUnliftIO m => MVar () -> m () -> m ()
untilMVar MVar ()
mvar m ()
io = m (Async (), ()) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (Async (), ()) -> m ()) -> m (Async (), ()) -> m ()
forall a b. (a -> b) -> a -> b
$
[Async ()] -> m (Async (), ())
forall (m :: * -> *) a. MonadIO m => [Async a] -> m (Async a, a)
waitAnyCancel ([Async ()] -> m (Async (), ()))
-> m [Async ()] -> m (Async (), ())
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (m () -> m (Async ())) -> [m ()] -> m [Async ()]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse m () -> m (Async ())
forall (m :: * -> *) a. MonadUnliftIO m => m a -> m (Async a)
async [ m ()
io , MVar () -> m ()
forall (m :: * -> *) a. MonadIO m => MVar a -> m a
readMVar MVar ()
mvar ]
cancelHandler :: (SomeLspId -> IO ()) -> LSP.Handlers (ServerM c)
cancelHandler :: forall c. (SomeLspId -> IO ()) -> Handlers (ServerM c)
cancelHandler SomeLspId -> IO ()
cancelRequest = SMethod 'Method_CancelRequest
-> Handler (ServerM c) 'Method_CancelRequest
-> Handlers (ServerM c)
forall (m :: Method 'ClientToServer 'Notification) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.notificationHandler SMethod 'Method_CancelRequest
forall {f :: MessageDirection}. SMethod 'Method_CancelRequest
SMethod_CancelRequest (Handler (ServerM c) 'Method_CancelRequest -> Handlers (ServerM c))
-> Handler (ServerM c) 'Method_CancelRequest
-> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ \TNotificationMessage{$sel:_params:TNotificationMessage :: forall (f :: MessageDirection) (m :: Method f 'Notification).
TNotificationMessage m -> MessageParams m
_params=CancelParams{Int32 |? Text
_id :: Int32 |? Text
$sel:_id:CancelParams :: CancelParams -> Int32 |? Text
_id}} ->
IO () -> ServerM c ()
forall a. IO a -> ServerM c a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ServerM c ()) -> IO () -> ServerM c ()
forall a b. (a -> b) -> a -> b
$ SomeLspId -> IO ()
cancelRequest (LspId Any -> SomeLspId
forall {f :: MessageDirection} (m :: Method f 'Request).
LspId m -> SomeLspId
SomeLspId ((Int32 |? Text) -> LspId Any
forall {f :: MessageDirection} (a :: Method f 'Request).
(Int32 |? Text) -> LspId a
toLspId Int32 |? Text
_id))
where toLspId :: (Int32 |? T.Text) -> LspId a
toLspId :: forall {f :: MessageDirection} (a :: Method f 'Request).
(Int32 |? Text) -> LspId a
toLspId (InL Int32
x) = Int32 -> LspId a
forall (f :: MessageDirection) (m :: Method f 'Request).
Int32 -> LspId m
IdInt Int32
x
toLspId (InR Text
y) = Text -> LspId a
forall (f :: MessageDirection) (m :: Method f 'Request).
Text -> LspId m
IdString Text
y
shutdownHandler :: IO () -> LSP.Handlers (ServerM c)
shutdownHandler :: forall c. IO () -> Handlers (ServerM c)
shutdownHandler IO ()
stopReactor = SMethod 'Method_Shutdown
-> Handler (ServerM c) 'Method_Shutdown -> Handlers (ServerM c)
forall (m :: Method 'ClientToServer 'Request) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.requestHandler SMethod 'Method_Shutdown
SMethod_Shutdown (Handler (ServerM c) 'Method_Shutdown -> Handlers (ServerM c))
-> Handler (ServerM c) 'Method_Shutdown -> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ \TRequestMessage 'Method_Shutdown
_ Either ResponseError Null -> ServerM c ()
resp -> do
(Chan ReactorMessage
_, IdeState
ide) <- ServerM c (Chan ReactorMessage, IdeState)
forall r (m :: * -> *). MonadReader r m => m r
ask
IO () -> ServerM c ()
forall a. IO a -> ServerM c a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ServerM c ()) -> IO () -> ServerM c ()
forall a b. (a -> b) -> a -> b
$ Logger -> Text -> IO ()
logDebug (IdeState -> Logger
ideLogger IdeState
ide) Text
"Received shutdown message"
IO () -> ServerM c ()
forall a. IO a -> ServerM c a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
stopReactor
IO () -> ServerM c ()
forall a. IO a -> ServerM c a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ServerM c ()) -> IO () -> ServerM c ()
forall a b. (a -> b) -> a -> b
$ IdeState -> IO ()
shakeShut IdeState
ide
Either ResponseError Null -> ServerM c ()
resp (Either ResponseError Null -> ServerM c ())
-> Either ResponseError Null -> ServerM c ()
forall a b. (a -> b) -> a -> b
$ Null -> Either ResponseError Null
forall a b. b -> Either a b
Right Null
Null
exitHandler :: IO () -> LSP.Handlers (ServerM c)
exitHandler :: forall c. IO () -> Handlers (ServerM c)
exitHandler IO ()
exit = SMethod 'Method_Exit
-> Handler (ServerM c) 'Method_Exit -> Handlers (ServerM c)
forall (m :: Method 'ClientToServer 'Notification) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.notificationHandler SMethod 'Method_Exit
SMethod_Exit (Handler (ServerM c) 'Method_Exit -> Handlers (ServerM c))
-> Handler (ServerM c) 'Method_Exit -> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ ServerM c () -> TNotificationMessage 'Method_Exit -> ServerM c ()
forall a b. a -> b -> a
const (ServerM c () -> TNotificationMessage 'Method_Exit -> ServerM c ())
-> ServerM c ()
-> TNotificationMessage 'Method_Exit
-> ServerM c ()
forall a b. (a -> b) -> a -> b
$ IO () -> ServerM c ()
forall a. IO a -> ServerM c a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
exit
modifyOptions :: LSP.Options -> LSP.Options
modifyOptions :: Options -> Options
modifyOptions Options
x = Options
x{ LSP.optTextDocumentSync = Just $ tweakTDS origTDS
}
where
tweakTDS :: TextDocumentSyncOptions -> TextDocumentSyncOptions
tweakTDS TextDocumentSyncOptions
tds = TextDocumentSyncOptions
tds{_openClose=Just True, _change=Just TextDocumentSyncKind_Incremental, _save=Just $ InR $ SaveOptions Nothing}
origTDS :: TextDocumentSyncOptions
origTDS = TextDocumentSyncOptions
-> Maybe TextDocumentSyncOptions -> TextDocumentSyncOptions
forall a. a -> Maybe a -> a
fromMaybe TextDocumentSyncOptions
tdsDefault (Maybe TextDocumentSyncOptions -> TextDocumentSyncOptions)
-> Maybe TextDocumentSyncOptions -> TextDocumentSyncOptions
forall a b. (a -> b) -> a -> b
$ Options -> Maybe TextDocumentSyncOptions
LSP.optTextDocumentSync Options
x
tdsDefault :: TextDocumentSyncOptions
tdsDefault = Maybe Bool
-> Maybe TextDocumentSyncKind
-> Maybe Bool
-> Maybe Bool
-> Maybe (Bool |? SaveOptions)
-> TextDocumentSyncOptions
TextDocumentSyncOptions Maybe Bool
forall a. Maybe a
Nothing Maybe TextDocumentSyncKind
forall a. Maybe a
Nothing Maybe Bool
forall a. Maybe a
Nothing Maybe Bool
forall a. Maybe a
Nothing Maybe (Bool |? SaveOptions)
forall a. Maybe a
Nothing