Skip to content

Commit ebb5690

Browse files
authored
Configurable I/O handles (#1617)
1 parent 8dbeae1 commit ebb5690

File tree

2 files changed

+31
-21
lines changed

2 files changed

+31
-21
lines changed

ghcide/src/Development/IDE/LSP/LanguageServer.hs

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import qualified Data.Text as T
2626
import qualified Development.IDE.GHC.Util as Ghcide
2727
import Development.IDE.LSP.Server
2828
import Development.IDE.Session (runWithDb)
29-
import GHC.IO.Handle (hDuplicate)
3029
import Ide.Types (traceWithSpan)
3130
import qualified Language.LSP.Server as LSP
3231
import Language.LSP.Types
@@ -48,25 +47,14 @@ import System.IO.Unsafe (unsafeInterleaveIO)
4847
runLanguageServer
4948
:: forall config. (Show config)
5049
=> LSP.Options
50+
-> Handle -- input
51+
-> Handle -- output
5152
-> (FilePath -> IO FilePath) -- ^ Map root paths to the location of the hiedb for the project
5253
-> (IdeState -> Value -> IO (Either T.Text config))
5354
-> LSP.Handlers (ServerM config)
5455
-> (LSP.LanguageContextEnv config -> VFSHandle -> Maybe FilePath -> HieDb -> IndexQueue -> IO IdeState)
5556
-> IO ()
56-
runLanguageServer options getHieDbLoc onConfigurationChange userHandlers getIdeState = do
57-
-- Move stdout to another file descriptor and duplicate stderr
58-
-- to stdout. This guards against stray prints from corrupting the JSON-RPC
59-
-- message stream.
60-
newStdout <- hDuplicate stdout
61-
stderr `Ghcide.hDuplicateTo'` stdout
62-
hSetBuffering stderr NoBuffering
63-
hSetBuffering stdout NoBuffering
64-
65-
-- Print out a single space to assert that the above redirection works.
66-
-- This is interleaved with the logger, hence we just print a space here in
67-
-- order not to mess up the output too much. Verified that this breaks
68-
-- the language server tests without the redirection.
69-
putStr " " >> hFlush stdout
57+
runLanguageServer options inH outH getHieDbLoc onConfigurationChange userHandlers getIdeState = do
7058

7159
-- These barriers are signaled when the threads reading from these chans exit.
7260
-- This should not happen but if it does, we will make sure that the whole server
@@ -126,8 +114,8 @@ runLanguageServer options getHieDbLoc onConfigurationChange userHandlers getIdeS
126114

127115
void $ waitAnyCancel =<< traverse async
128116
[ void $ LSP.runServerWithHandles
129-
stdin
130-
newStdout
117+
inH
118+
outH
131119
serverDefinition
132120
, void $ waitBarrier clientMsgBarrier
133121
]

ghcide/src/Development/IDE/Main.hs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import Data.Maybe (catMaybes, fromMaybe,
1414
isJust)
1515
import qualified Data.Text as T
1616
import qualified Data.Text.IO as T
17-
import Development.IDE (Action, Rules)
17+
import Development.IDE (Action, Rules,
18+
hDuplicateTo')
1819
import Development.IDE.Core.Debouncer (Debouncer,
1920
newAsyncDebouncer)
2021
import Development.IDE.Core.FileStore (makeVFSHandle)
@@ -54,6 +55,7 @@ import Development.IDE.Types.Options (IdeGhcSession,
5455
import Development.IDE.Types.Shake (Key (Key))
5556
import Development.Shake (action)
5657
import GHC.IO.Encoding (setLocaleEncoding)
58+
import GHC.IO.Handle (hDuplicate)
5759
import HIE.Bios.Cradle (findCradle)
5860
import Ide.Plugin.Config (CheckParents (NeverCheck),
5961
Config,
@@ -68,11 +70,12 @@ import System.Exit (ExitCode (ExitFailure),
6870
exitWith)
6971
import System.FilePath (takeExtension,
7072
takeFileName)
71-
import System.IO (BufferMode (LineBuffering),
73+
import System.IO (BufferMode (LineBuffering, NoBuffering),
74+
Handle, hFlush,
7275
hPutStrLn,
7376
hSetBuffering,
7477
hSetEncoding, stderr,
75-
stdout, utf8)
78+
stdin, stdout, utf8)
7679
import System.Time.Extra (offsetTime,
7780
showDuration)
7881
import Text.Printf (printf)
@@ -90,6 +93,8 @@ data Arguments = Arguments
9093
, argsDefaultHlsConfig :: Config
9194
, argsGetHieDbLoc :: FilePath -> IO FilePath -- ^ Map project roots to the location of the hiedb for the project
9295
, argsDebouncer :: IO (Debouncer NormalizedUri) -- ^ Debouncer used for diagnostics
96+
, argsHandleIn :: IO Handle
97+
, argsHandleOut :: IO Handle
9398
}
9499

95100
instance Default Arguments where
@@ -106,6 +111,21 @@ instance Default Arguments where
106111
, argsDefaultHlsConfig = def
107112
, argsGetHieDbLoc = getHieDbLoc
108113
, argsDebouncer = newAsyncDebouncer
114+
, argsHandleIn = pure stdin
115+
, argsHandleOut = do
116+
-- Move stdout to another file descriptor and duplicate stderr
117+
-- to stdout. This guards against stray prints from corrupting the JSON-RPC
118+
-- message stream.
119+
newStdout <- hDuplicate stdout
120+
stderr `hDuplicateTo'` stdout
121+
hSetBuffering stdout NoBuffering
122+
123+
-- Print out a single space to assert that the above redirection works.
124+
-- This is interleaved with the logger, hence we just print a space here in
125+
-- order not to mess up the output too much. Verified that this breaks
126+
-- the language server tests without the redirection.
127+
putStr " " >> hFlush stdout
128+
return newStdout
109129
}
110130

111131
-- | Cheap stderr logger that relies on LineBuffering
@@ -130,13 +150,15 @@ defaultMain Arguments{..} = do
130150
rules = argsRules >> pluginRules plugins
131151

132152
debouncer <- argsDebouncer
153+
inH <- argsHandleIn
154+
outH <- argsHandleOut
133155

134156
case argFiles of
135157
Nothing -> do
136158
t <- offsetTime
137159
hPutStrLn stderr "Starting LSP server..."
138160
hPutStrLn stderr "If you are seeing this in a terminal, you probably should have run ghcide WITHOUT the --lsp option!"
139-
runLanguageServer options argsGetHieDbLoc argsOnConfigChange (pluginHandlers plugins) $ \env vfs rootPath hiedb hieChan -> do
161+
runLanguageServer options inH outH argsGetHieDbLoc argsOnConfigChange (pluginHandlers plugins) $ \env vfs rootPath hiedb hieChan -> do
140162
t <- t
141163
hPutStrLn stderr $ "Started LSP server in " ++ showDuration t
142164

0 commit comments

Comments
 (0)