forked from haskell/haskell-language-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConfig.hs
178 lines (164 loc) · 7.44 KB
/
Config.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module Ide.Plugin.Config
( getConfigFromNotification
, Config(..)
, parseConfig
, PluginConfig(..)
, CheckParents(..)
) where
import Control.Applicative
import Data.Aeson hiding (Error)
import qualified Data.Aeson as A
import qualified Data.Aeson.Types as A
import Data.Default
import qualified Data.Map as Map
import qualified Data.Text as T
import GHC.Generics (Generic)
-- ---------------------------------------------------------------------
-- | Given a DidChangeConfigurationNotification message, this function returns the parsed
-- Config object if possible.
getConfigFromNotification :: Config -> A.Value -> Either T.Text Config
getConfigFromNotification defaultValue p =
case A.parse (parseConfig defaultValue) p of
A.Success c -> Right c
A.Error err -> Left $ T.pack err
-- ---------------------------------------------------------------------
data CheckParents
-- Note that ordering of constructors is meaningful and must be monotonically
-- increasing in the scenarios where parents are checked
= NeverCheck
| CheckOnClose
| CheckOnSaveAndClose
| AlwaysCheck
deriving stock (Eq, Ord, Show, Generic)
deriving anyclass (FromJSON, ToJSON)
-- | We (initially anyway) mirror the hie configuration, so that existing
-- clients can simply switch executable and not have any nasty surprises. There
-- will be surprises relating to config options being ignored, initially though.
data Config =
Config
{ checkParents :: CheckParents
, checkProject :: !Bool
, hlintOn :: !Bool
, diagnosticsOnChange :: !Bool
, diagnosticsDebounceDuration :: !Int
, liquidOn :: !Bool
, completionSnippetsOn :: !Bool
, formatOnImportOn :: !Bool
, formattingProvider :: !T.Text
, maxCompletions :: !Int
, plugins :: !(Map.Map T.Text PluginConfig)
} deriving (Show,Eq)
instance Default Config where
def = Config
{ checkParents = CheckOnSaveAndClose
, checkProject = True
, hlintOn = True
, diagnosticsOnChange = True
, diagnosticsDebounceDuration = 350000
, liquidOn = False
, completionSnippetsOn = True
, formatOnImportOn = True
-- , formattingProvider = "brittany"
, formattingProvider = "ormolu"
-- , formattingProvider = "floskell"
-- , formattingProvider = "stylish-haskell"
, maxCompletions = 40
, plugins = Map.empty
}
-- TODO: Add API for plugins to expose their own LSP config options
parseConfig :: Config -> Value -> A.Parser Config
parseConfig defValue = A.withObject "Config" $ \v -> do
-- Officially, we use "haskell" as the section name but for
-- backwards compatibility we also accept "languageServerHaskell"
c <- v .: "haskell" <|> v .:? "languageServerHaskell"
case c of
Nothing -> return defValue
Just s -> flip (A.withObject "Config.settings") s $ \o -> Config
<$> (o .:? "checkParents" <|> v .:? "checkParents") .!= checkParents defValue
<*> (o .:? "checkProject" <|> v .:? "checkProject") .!= checkProject defValue
<*> o .:? "hlintOn" .!= hlintOn defValue
<*> o .:? "diagnosticsOnChange" .!= diagnosticsOnChange defValue
<*> o .:? "diagnosticsDebounceDuration" .!= diagnosticsDebounceDuration defValue
<*> o .:? "liquidOn" .!= liquidOn defValue
<*> o .:? "completionSnippetsOn" .!= completionSnippetsOn defValue
<*> o .:? "formatOnImportOn" .!= formatOnImportOn defValue
<*> o .:? "formattingProvider" .!= formattingProvider defValue
<*> o .:? "maxCompletions" .!= maxCompletions defValue
<*> o .:? "plugin" .!= plugins defValue
instance A.ToJSON Config where
toJSON Config{..} =
object [ "haskell" .= r ]
where
r = object [ "checkParents" .= checkParents
, "checkProject" .= checkProject
, "hlintOn" .= hlintOn
, "diagnosticsOnChange" .= diagnosticsOnChange
, "diagnosticsDebounceDuration" .= diagnosticsDebounceDuration
, "liquidOn" .= liquidOn
, "completionSnippetsOn" .= completionSnippetsOn
, "formatOnImportOn" .= formatOnImportOn
, "formattingProvider" .= formattingProvider
, "maxCompletions" .= maxCompletions
, "plugin" .= plugins
]
-- ---------------------------------------------------------------------
-- | A PluginConfig is a generic configuration for a given HLS plugin. It
-- provides a "big switch" to turn it on or off as a whole, as well as small
-- switches per feature, and a slot for custom config.
-- This provides a regular naming scheme for all plugin config.
data PluginConfig =
PluginConfig
{ plcGlobalOn :: !Bool
, plcCodeActionsOn :: !Bool
, plcCodeLensOn :: !Bool
, plcDiagnosticsOn :: !Bool
, plcHoverOn :: !Bool
, plcSymbolsOn :: !Bool
, plcCompletionOn :: !Bool
, plcRenameOn :: !Bool
, plcConfig :: !A.Object
} deriving (Show,Eq)
instance Default PluginConfig where
def = PluginConfig
{ plcGlobalOn = True
, plcCodeActionsOn = True
, plcCodeLensOn = True
, plcDiagnosticsOn = True
, plcHoverOn = True
, plcSymbolsOn = True
, plcCompletionOn = True
, plcRenameOn = True
, plcConfig = mempty
}
instance A.ToJSON PluginConfig where
toJSON (PluginConfig g ca cl d h s c rn cfg) = r
where
r = object [ "globalOn" .= g
, "codeActionsOn" .= ca
, "codeLensOn" .= cl
, "diagnosticsOn" .= d
, "hoverOn" .= h
, "symbolsOn" .= s
, "completionOn" .= c
, "renameOn" .= rn
, "config" .= cfg
]
instance A.FromJSON PluginConfig where
parseJSON = A.withObject "PluginConfig" $ \o -> PluginConfig
<$> o .:? "globalOn" .!= plcGlobalOn def
<*> o .:? "codeActionsOn" .!= plcCodeActionsOn def
<*> o .:? "codeLensOn" .!= plcCodeLensOn def
<*> o .:? "diagnosticsOn" .!= plcDiagnosticsOn def -- AZ
<*> o .:? "hoverOn" .!= plcHoverOn def
<*> o .:? "symbolsOn" .!= plcSymbolsOn def
<*> o .:? "completionOn" .!= plcCompletionOn def
<*> o .:? "renameOn" .!= plcRenameOn def
<*> o .:? "config" .!= plcConfig def
-- ---------------------------------------------------------------------