{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
module Development.IDE.LSP.LanguageServer
( runLanguageServer
) 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 qualified Language.LSP.Server as LSP
import Language.LSP.Types
import System.IO
import UnliftIO.Async
import UnliftIO.Concurrent
import UnliftIO.Directory
import UnliftIO.Exception
import Development.IDE.Core.FileStore
import Development.IDE.Core.IdeConfiguration
import Development.IDE.Core.Shake
import Development.IDE.Core.Tracing
import Development.IDE.LSP.HoverDefinition
import Development.IDE.Types.Logger
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Development.IDE.Types.Shake (WithHieDb)
import System.IO.Unsafe (unsafeInterleaveIO)
issueTrackerUrl :: T.Text
issueTrackerUrl :: Text
issueTrackerUrl = Text
"https://github.com/haskell/haskell-language-server/issues"
newtype WithHieDbShield = WithHieDbShield WithHieDb
runLanguageServer
:: forall config. (Show config)
=> LSP.Options
-> Handle
-> Handle
-> (FilePath -> IO FilePath)
-> config
-> (config -> Value -> Either T.Text config)
-> LSP.Handlers (ServerM config)
-> (LSP.LanguageContextEnv config -> VFSHandle -> Maybe FilePath -> WithHieDb -> IndexQueue -> IO IdeState)
-> IO ()
runLanguageServer :: Options
-> Handle
-> Handle
-> (FilePath -> IO FilePath)
-> config
-> (config -> Value -> Either Text config)
-> Handlers (ServerM config)
-> (LanguageContextEnv config
-> VFSHandle
-> Maybe FilePath
-> WithHieDb
-> IndexQueue
-> IO IdeState)
-> IO ()
runLanguageServer Options
options Handle
inH Handle
outH FilePath -> IO FilePath
getHieDbLoc config
defaultConfig config -> Value -> Either Text config
onConfigurationChange Handlers (ServerM config)
userHandlers LanguageContextEnv config
-> VFSHandle
-> Maybe FilePath
-> WithHieDb
-> IndexQueue
-> IO IdeState
getIdeState = do
MVar ()
clientMsgVar <- IO (MVar ())
forall (m :: * -> *) a. MonadIO m => m (MVar a)
newEmptyMVar
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 ()
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 ()
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 (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 ideHandlers :: Handlers (ServerM config)
ideHandlers = [Handlers (ServerM config)] -> Handlers (ServerM config)
forall a. Monoid a => [a] -> a
mconcat
[ Handlers (ServerM config)
forall c. Handlers (ServerM c)
setIdeHandlers
, Handlers (ServerM config)
userHandlers
]
Chan ReactorMessage
clientMsgChan :: Chan ReactorMessage <- IO (Chan ReactorMessage)
forall (m :: * -> *) a. MonadIO m => m (Chan a)
newChan
let asyncHandlers :: Handlers (ServerM config)
asyncHandlers = [Handlers (ServerM config)] -> Handlers (ServerM config)
forall a. Monoid a => [a] -> a
mconcat
[ Handlers (ServerM config)
ideHandlers
, (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 serverDefinition :: ServerDefinition config
serverDefinition = ServerDefinition :: forall config (m :: * -> *) a.
config
-> (config -> Value -> Either Text config)
-> (LanguageContextEnv config
-> Message 'Initialize -> IO (Either ResponseError a))
-> Handlers m
-> (a -> m <~> IO)
-> Options
-> ServerDefinition config
LSP.ServerDefinition
{ onConfigurationChange :: config -> Value -> Either Text config
LSP.onConfigurationChange = config -> Value -> Either Text config
onConfigurationChange
, defaultConfig :: config
LSP.defaultConfig = config
defaultConfig
, doInitialize :: LanguageContextEnv config
-> Message 'Initialize
-> IO (Either ResponseError (LanguageContextEnv config, IdeState))
LSP.doInitialize = MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> RequestMessage 'Initialize
-> IO (Either ResponseError (LanguageContextEnv config, IdeState))
forall err.
MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> RequestMessage 'Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
handleInit MVar ()
reactorLifetime IO ()
exit SomeLspId -> IO ()
clearReqId SomeLspId -> IO ()
waitForCancel Chan ReactorMessage
clientMsgChan
, staticHandlers :: Handlers (ServerM config)
LSP.staticHandlers = Handlers (ServerM config)
asyncHandlers
, interpretHandler :: (LanguageContextEnv config, IdeState) -> ServerM config <~> IO
LSP.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)
-> (ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
-> LspT config IO a)
-> ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
-> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) a
-> (Chan ReactorMessage, IdeState) -> LspT config IO a)
-> (Chan ReactorMessage, IdeState)
-> ReaderT (Chan ReactorMessage, IdeState) (LspT config IO) 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 (Chan ReactorMessage
clientMsgChan,IdeState
st)) forall a. IO a -> ServerM config a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
, options :: Options
LSP.options = Options -> Options
modifyOptions Options
options
}
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
$ Handle -> Handle -> ServerDefinition config -> IO Int
forall config.
Handle -> Handle -> ServerDefinition config -> IO Int
LSP.runServerWithHandles
Handle
inH
Handle
outH
ServerDefinition config
serverDefinition
where
handleInit
:: MVar () -> IO () -> (SomeLspId -> IO ()) -> (SomeLspId -> IO ()) -> Chan ReactorMessage
-> LSP.LanguageContextEnv config -> RequestMessage Initialize -> IO (Either err (LSP.LanguageContextEnv config, IdeState))
handleInit :: MVar ()
-> IO ()
-> (SomeLspId -> IO ())
-> (SomeLspId -> IO ())
-> Chan ReactorMessage
-> LanguageContextEnv config
-> RequestMessage 'Initialize
-> IO (Either err (LanguageContextEnv config, IdeState))
handleInit MVar ()
lifetime IO ()
exitClientMsg SomeLspId -> IO ()
clearReqId SomeLspId -> IO ()
waitForCancel Chan ReactorMessage
clientMsgChan LanguageContextEnv config
env (RequestMessage Text
_ LspId 'Initialize
_ SMethod 'Initialize
m MessageParams 'Initialize
params) = FilePath
-> FilePath
-> (SpanInFlight
-> IO (Either err (LanguageContextEnv config, IdeState)))
-> IO (Either err (LanguageContextEnv config, IdeState))
forall (m :: * -> *) a.
MonadUnliftIO m =>
FilePath -> FilePath -> (SpanInFlight -> m a) -> m a
otTracedHandler FilePath
"Initialize" (SMethod 'Initialize -> FilePath
forall a. Show a => a -> FilePath
show SMethod '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 MessageParams 'Initialize
InitializeParams
params
let root :: Maybe FilePath
root = LanguageContextEnv config -> Maybe FilePath
forall config. LanguageContextEnv config -> Maybe FilePath
LSP.resRootPath LanguageContextEnv config
env
FilePath
dir <- IO FilePath
-> (FilePath -> IO FilePath) -> Maybe FilePath -> IO FilePath
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO FilePath
forall (m :: * -> *). MonadIO m => m FilePath
getCurrentDirectory FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe FilePath
root
FilePath
dbLoc <- FilePath -> IO FilePath
getHieDbLoc FilePath
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
-> VFSHandle
-> Maybe FilePath
-> WithHieDb
-> IndexQueue
-> IO IdeState
getIdeState LanguageContextEnv config
env (LanguageContextEnv config -> VFSHandle
forall c. LanguageContextEnv c -> VFSHandle
makeLSPVFSHandle LanguageContextEnv config
env) Maybe FilePath
root WithHieDb
withHieDb IndexQueue
hieChan
let initConfig :: IdeConfiguration
initConfig = InitializeParams -> IdeConfiguration
parseConfiguration MessageParams 'Initialize
InitializeParams
params
Logger -> Text -> IO ()
logInfo (IdeState -> Logger
ideLogger IdeState
ide) (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath
"Registering ide configuration: " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> IdeConfiguration -> FilePath
forall a. Show a => a -> FilePath
show IdeConfiguration
initConfig
ShakeExtras -> IdeConfiguration -> IO ()
registerIdeConfiguration (IdeState -> ShakeExtras
shakeExtras IdeState
ide) IdeConfiguration
initConfig
let handleServerException :: Either SomeException () -> IO ()
handleServerException (Left SomeException
e) = do
Logger -> Text -> IO ()
logError Logger
logger (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$
FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath
"Fatal error in server thread: " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> SomeException -> FilePath
forall a. Show a => a -> FilePath
show SomeException
e
SomeException -> IO ()
sendErrorMessage SomeException
e
IO ()
exitClientMsg
handleServerException (Right ()
_) = () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
sendErrorMessage :: SomeException -> IO ()
sendErrorMessage (SomeException
e :: SomeException) = do
LanguageContextEnv config -> LspT config IO () -> IO ()
forall config (m :: * -> *) a.
LanguageContextEnv config -> LspT config m a -> m a
LSP.runLspT LanguageContextEnv config
env (LspT config IO () -> IO ()) -> LspT config IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ SServerMethod 'WindowShowMessage
-> MessageParams 'WindowShowMessage -> LspT config IO ()
forall (m :: Method 'FromServer 'Notification) (f :: * -> *)
config.
MonadLsp config f =>
SServerMethod m -> MessageParams m -> f ()
LSP.sendNotification SServerMethod 'WindowShowMessage
SWindowShowMessage (MessageParams 'WindowShowMessage -> LspT config IO ())
-> MessageParams 'WindowShowMessage -> LspT config IO ()
forall a b. (a -> b) -> a -> b
$
MessageType -> Text -> ShowMessageParams
ShowMessageParams MessageType
MtError (Text -> ShowMessageParams) -> Text -> ShowMessageParams
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.unlines
[ Text
"Unhandled exception, please [report](" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
issueTrackerUrl Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): "
, FilePath -> Text
T.pack(SomeException -> FilePath
forall a. Show a => a -> FilePath
show SomeException
e)
]
exceptionInHandler :: SomeException -> IO ()
exceptionInHandler SomeException
e = do
Logger -> Text -> IO ()
logError Logger
logger (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$
FilePath
"Unexpected exception, please report!\n" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
FilePath
"Exception: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ SomeException -> FilePath
forall a. Show a => a -> FilePath
show SomeException
e
SomeException -> IO ()
sendErrorMessage SomeException
e
logger :: Logger
logger = IdeState -> Logger
ideLogger IdeState
ide
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
Logger -> Text -> IO ()
logDebug (IdeState -> Logger
ideLogger IdeState
ide) (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ FilePath
"Cancelled request " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> SomeLspId -> FilePath
forall a. Show a => a -> FilePath
show SomeLspId
_id
ResponseError -> IO ()
k (ResponseError -> IO ()) -> ResponseError -> IO ()
forall a b. (a -> b) -> a -> b
$ ErrorCode -> Text -> Maybe Value -> ResponseError
ResponseError ErrorCode
RequestCancelled Text
"" Maybe Value
forall a. Maybe a
Nothing
Right ()
res -> () -> IO ()
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
$ ErrorCode -> Text -> Maybe Value -> ResponseError
ResponseError ErrorCode
InternalError (FilePath -> Text
T.pack (FilePath -> Text) -> FilePath -> Text
forall a b. (a -> b) -> a -> b
$ SomeException -> FilePath
forall a. Show a => a -> FilePath
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
$ Logger -> FilePath -> (WithHieDb -> IndexQueue -> IO ()) -> IO ()
runWithDb Logger
logger FilePath
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 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
Logger -> Text -> IO ()
logInfo Logger
logger Text
"Reactor thread stopped"
Either err (LanguageContextEnv config, IdeState)
-> IO (Either err (LanguageContextEnv config, IdeState))
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 :: 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)
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 :: (SomeLspId -> IO ()) -> Handlers (ServerM c)
cancelHandler SomeLspId -> IO ()
cancelRequest = SMethod 'CancelRequest
-> Handler (ServerM c) 'CancelRequest -> Handlers (ServerM c)
forall (m :: Method 'FromClient 'Notification) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.notificationHandler SMethod 'CancelRequest
forall (f :: From). SMethod 'CancelRequest
SCancelRequest (Handler (ServerM c) 'CancelRequest -> Handlers (ServerM c))
-> Handler (ServerM c) 'CancelRequest -> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ \NotificationMessage{$sel:_params:NotificationMessage :: forall (f :: From) (m :: Method f 'Notification).
NotificationMessage m -> MessageParams m
_params=CancelParams{_id}} ->
IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ())
-> IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. (a -> b) -> a -> b
$ SomeLspId -> IO ()
cancelRequest (LspId m -> SomeLspId
forall (f :: From) (m :: Method f 'Request). LspId m -> SomeLspId
SomeLspId LspId m
_id)
shutdownHandler :: IO () -> LSP.Handlers (ServerM c)
shutdownHandler :: IO () -> Handlers (ServerM c)
shutdownHandler IO ()
stopReactor = SMethod 'Shutdown
-> Handler (ServerM c) 'Shutdown -> Handlers (ServerM c)
forall (m :: Method 'FromClient 'Request) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.requestHandler SMethod 'Shutdown
SShutdown (Handler (ServerM c) 'Shutdown -> Handlers (ServerM c))
-> Handler (ServerM c) 'Shutdown -> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ \RequestMessage 'Shutdown
_ Either ResponseError Empty
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
resp -> do
(Chan ReactorMessage
_, IdeState
ide) <- ReaderT
(Chan ReactorMessage, IdeState)
(LspM c)
(Chan ReactorMessage, IdeState)
forall r (m :: * -> *). MonadReader r m => m r
ask
IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ())
-> IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. (a -> b) -> a -> b
$ Logger -> Text -> IO ()
logDebug (IdeState -> Logger
ideLogger IdeState
ide) Text
"Received shutdown message"
IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
stopReactor
IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ())
-> IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. (a -> b) -> a -> b
$ IdeState -> IO ()
shakeShut IdeState
ide
Either ResponseError Empty
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
resp (Either ResponseError Empty
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ())
-> Either ResponseError Empty
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. (a -> b) -> a -> b
$ Empty -> Either ResponseError Empty
forall a b. b -> Either a b
Right Empty
Empty
exitHandler :: IO () -> LSP.Handlers (ServerM c)
exitHandler :: IO () -> Handlers (ServerM c)
exitHandler IO ()
exit = SMethod 'Exit -> Handler (ServerM c) 'Exit -> Handlers (ServerM c)
forall (m :: Method 'FromClient 'Notification) (f :: * -> *).
SMethod m -> Handler f m -> Handlers f
LSP.notificationHandler SMethod 'Exit
SExit (Handler (ServerM c) 'Exit -> Handlers (ServerM c))
-> Handler (ServerM c) 'Exit -> Handlers (ServerM c)
forall a b. (a -> b) -> a -> b
$ ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
-> NotificationMessage 'Exit
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. a -> b -> a
const (ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
-> NotificationMessage 'Exit
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ())
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
-> NotificationMessage 'Exit
-> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
forall a b. (a -> b) -> a -> b
$ IO () -> ReaderT (Chan ReactorMessage, IdeState) (LspM c) ()
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{ textDocumentSync :: Maybe TextDocumentSyncOptions
LSP.textDocumentSync = TextDocumentSyncOptions -> Maybe TextDocumentSyncOptions
forall a. a -> Maybe a
Just (TextDocumentSyncOptions -> Maybe TextDocumentSyncOptions)
-> TextDocumentSyncOptions -> Maybe TextDocumentSyncOptions
forall a b. (a -> b) -> a -> b
$ TextDocumentSyncOptions -> TextDocumentSyncOptions
tweakTDS TextDocumentSyncOptions
origTDS
}
where
tweakTDS :: TextDocumentSyncOptions -> TextDocumentSyncOptions
tweakTDS TextDocumentSyncOptions
tds = TextDocumentSyncOptions
tds{$sel:_openClose:TextDocumentSyncOptions :: Maybe Bool
_openClose=Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True, $sel:_change:TextDocumentSyncOptions :: Maybe TextDocumentSyncKind
_change=TextDocumentSyncKind -> Maybe TextDocumentSyncKind
forall a. a -> Maybe a
Just TextDocumentSyncKind
TdSyncIncremental, $sel:_save:TextDocumentSyncOptions :: Maybe (Bool |? SaveOptions)
_save=(Bool |? SaveOptions) -> Maybe (Bool |? SaveOptions)
forall a. a -> Maybe a
Just ((Bool |? SaveOptions) -> Maybe (Bool |? SaveOptions))
-> (Bool |? SaveOptions) -> Maybe (Bool |? SaveOptions)
forall a b. (a -> b) -> a -> b
$ SaveOptions -> Bool |? SaveOptions
forall a b. b -> a |? b
InR (SaveOptions -> Bool |? SaveOptions)
-> SaveOptions -> Bool |? SaveOptions
forall a b. (a -> b) -> a -> b
$ Maybe Bool -> SaveOptions
SaveOptions Maybe Bool
forall a. Maybe a
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.textDocumentSync 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