1
1
-- Copyright (c) 2019 The DAML Authors. All rights reserved.
2
2
-- SPDX-License-Identifier: Apache-2.0
3
- {-# LANGUAGE NamedFieldPuns #-}
4
- {-# LANGUAGE OverloadedStrings #-}
3
+ {-# LANGUAGE LambdaCase #-}
4
+ {-# LANGUAGE NamedFieldPuns #-}
5
+ {-# LANGUAGE OverloadedStrings #-}
6
+ {-# LANGUAGE ScopedTypeVariables #-}
5
7
module Main (main ) where
6
8
7
9
import Control.Arrow ((&&&) )
@@ -10,13 +12,14 @@ import Data.Function ((&))
10
12
import Data.Text (Text )
11
13
import qualified Development.IDE.Main as GhcideMain
12
14
import Development.IDE.Types.Logger (Doc , Priority (Error , Info ),
15
+ Recorder ,
13
16
WithPriority (WithPriority , priority ),
14
17
cfilter , cmapWithPrio ,
15
18
defaultLayoutOptions ,
16
- layoutPretty ,
19
+ layoutPretty , logWith ,
17
20
makeDefaultStderrRecorder ,
18
21
payload , renderStrict ,
19
- withDefaultRecorder )
22
+ withFileRecorder )
20
23
import qualified Development.IDE.Types.Logger as Logger
21
24
import qualified HlsPlugins as Plugins
22
25
import Ide.Arguments (Arguments (.. ),
@@ -30,7 +33,11 @@ import Ide.Types (PluginDescriptor (pluginNotificat
30
33
mkPluginNotificationHandler )
31
34
import Language.LSP.Server as LSP
32
35
import Language.LSP.Types as LSP
33
- import Prettyprinter (Pretty (pretty ), vsep )
36
+ import Prettyprinter (Pretty (pretty ), vcat , vsep )
37
+ import Control.Exception (displayException )
38
+ import Data.Bifunctor (first )
39
+ import Data.Functor ((<&>) )
40
+ import Data.Maybe (catMaybes )
34
41
35
42
data Log
36
43
= LogIdeMain IdeMain. Log
@@ -43,13 +50,27 @@ instance Pretty Log where
43
50
44
51
main :: IO ()
45
52
main = do
53
+ stderrRecorder <- makeDefaultStderrRecorder Nothing
46
54
-- plugin cli commands use stderr logger for now unless we change the args
47
55
-- parser to get logging arguments first or do more complicated things
48
- pluginCliRecorder <- cmapWithPrio pretty <$> makeDefaultStderrRecorder Nothing
56
+ let pluginCliRecorder = cmapWithPrio pretty stderrRecorder
49
57
args <- getArguments " haskell-language-server" (Plugins. idePlugins (cmapWithPrio LogPlugins pluginCliRecorder))
50
58
51
- (lspLogRecorder, cb1) <- Logger. withBacklog Logger. lspClientLogRecorder
52
- (lspMessageRecorder, cb2) <- Logger. withBacklog Logger. lspClientMessageRecorder
59
+ -- Recorder that logs to the LSP client with logMessage
60
+ (lspLogRecorder, cb1) <-
61
+ Logger. withBacklog Logger. lspClientLogRecorder
62
+ <&> first (cmapWithPrio renderDoc)
63
+ -- Recorder that logs to the LSP client with showMessage
64
+ (lspMessageRecorder, cb2) <-
65
+ Logger. withBacklog Logger. lspClientMessageRecorder
66
+ <&> first (cmapWithPrio renderDoc)
67
+ -- Recorder that logs Error severity logs to the client with showMessage and some extra text
68
+ let lspErrorMessageRecorder = lspMessageRecorder
69
+ & cfilter (\ WithPriority { priority } -> priority >= Error )
70
+ & cmapWithPrio (\ msg -> vsep
71
+ [" Error condition, please check your setup and/or the [issue tracker](" <> issueTrackerUrl <> " ): "
72
+ , msg
73
+ ])
53
74
-- This plugin just installs a handler for the `initialized` notification, which then
54
75
-- picks up the LSP environment and feeds it to our recorders
55
76
let lspRecorderPlugin = (defaultPluginDescriptor " LSPRecorderCallback" )
@@ -58,28 +79,35 @@ main = do
58
79
liftIO $ (cb1 <> cb2) env
59
80
}
60
81
61
- let (argsTesting, minPriority, logFilePath) =
82
+ let (minPriority, logFilePath, logStderr, logClient ) =
62
83
case args of
63
- Ghcide GhcideArguments { argsTesting, argsLogLevel, argsLogFile} ->
64
- (argsTesting, argsLogLevel, argsLogFile)
65
- _ -> (False , Info , Nothing )
84
+ Ghcide GhcideArguments { argsLogLevel, argsLogFile, argsLogStderr, argsLogClient } ->
85
+ (argsLogLevel, argsLogFile, argsLogStderr, argsLogClient )
86
+ _ -> (Info , Nothing , True , False )
66
87
67
- withDefaultRecorder logFilePath Nothing $ \ textWithPriorityRecorder -> do
88
+ -- Adapter for withFileRecorder to handle the case where we don't want to log to a file
89
+ let withLogFileRecorder action = case logFilePath of
90
+ Just p -> withFileRecorder p Nothing $ \ case
91
+ Left e -> do
92
+ let exceptionMessage = pretty $ displayException e
93
+ let message = vcat [exceptionMessage, " Couldn't open log file; not logging to it." ]
94
+ logWith stderrRecorder Error message
95
+ action Nothing
96
+ Right r -> action (Just r)
97
+ Nothing -> action Nothing
98
+
99
+ withLogFileRecorder $ \ logFileRecorder -> do
68
100
let
69
- recorder = cmapWithPrio (pretty &&& id ) $ mconcat
70
- [textWithPriorityRecorder
71
- & cfilter (\ WithPriority { priority } -> priority >= minPriority)
72
- & cmapWithPrio fst
73
- , lspMessageRecorder
74
- & cfilter (\ WithPriority { priority } -> priority >= Error )
75
- & cmapWithPrio (renderDoc . fst )
76
- , lspLogRecorder
77
- & cfilter (\ WithPriority { priority } -> priority >= minPriority)
78
- & cmapWithPrio (renderStrict . layoutPretty defaultLayoutOptions . fst )
79
- -- do not log heap stats to the LSP log as they interfere with the
80
- -- ability of lsp-test to detect a stuck server in tests and benchmarks
81
- & if argsTesting then cfilter (not . heapStats . snd . payload) else id
82
- ]
101
+ lfr = logFileRecorder
102
+ ser = if logStderr then Just stderrRecorder else Nothing
103
+ lemr = Just lspErrorMessageRecorder
104
+ llr = if logClient then Just lspLogRecorder else Nothing
105
+ recorder :: Recorder (WithPriority Log ) =
106
+ [lfr, ser, lemr, llr]
107
+ & catMaybes
108
+ & mconcat
109
+ & cmapWithPrio pretty
110
+ & cfilter (\ WithPriority { priority } -> priority >= minPriority)
83
111
plugins = Plugins. idePlugins (cmapWithPrio LogPlugins recorder)
84
112
85
113
defaultMain
@@ -88,14 +116,7 @@ main = do
88
116
(plugins <> pluginDescToIdePlugins [lspRecorderPlugin])
89
117
90
118
renderDoc :: Doc a -> Text
91
- renderDoc d = renderStrict $ layoutPretty defaultLayoutOptions $ vsep
92
- [" Error condition, please check your setup and/or the [issue tracker](" <> issueTrackerUrl <> " ): "
93
- ,d
94
- ]
119
+ renderDoc d = renderStrict $ layoutPretty defaultLayoutOptions d
95
120
96
121
issueTrackerUrl :: Doc a
97
122
issueTrackerUrl = " https://github.com/haskell/haskell-language-server/issues"
98
-
99
- heapStats :: Log -> Bool
100
- heapStats (LogIdeMain (IdeMain. LogIDEMain (GhcideMain. LogHeapStats _))) = True
101
- heapStats _ = False
0 commit comments