Skip to content

Commit 98ffe94

Browse files
berbermanjneira
andauthored
Imporve vscode extension schema generation (haskell#1742)
Co-authored-by: Javier Neira <[email protected]>
1 parent dec47a3 commit 98ffe94

File tree

7 files changed

+73
-34
lines changed

7 files changed

+73
-34
lines changed

ghcide/src/Development/IDE/Plugin/Completions.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ descriptor plId = (defaultPluginDescriptor plId)
4747
{ pluginRules = produceCompletions
4848
, pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP
4949
, pluginCommands = [extendImportCommand]
50-
, pluginCustomConfig = mkCustomConfig properties
50+
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
5151
}
5252

5353
produceCompletions :: Rules ()

ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ descriptors =
3333
descriptor :: PluginId -> PluginDescriptor IdeState
3434
descriptor plId = (defaultPluginDescriptor plId)
3535
{ pluginHandlers = mkPluginHandler STextDocumentHover hover'
36-
<> mkPluginHandler STextDocumentDocumentSymbol symbolsProvider
36+
<> mkPluginHandler STextDocumentDocumentSymbol symbolsProvider,
37+
pluginConfigDescriptor = defaultConfigDescriptor {configEnableGenericConfig = False}
3738
}
3839

3940
-- ---------------------------------------------------------------------

ghcide/src/Development/IDE/Plugin/TypeLenses.hs

+6-4
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import Control.DeepSeq (rwhnf)
1717
import Control.Monad (mzero)
1818
import Control.Monad.Extra (whenMaybe)
1919
import Control.Monad.IO.Class (MonadIO (liftIO))
20-
import qualified Data.Aeson.Types as A
2120
import Data.Aeson.Types (Value (..), toJSON)
21+
import qualified Data.Aeson.Types as A
2222
import qualified Data.HashMap.Strict as Map
2323
import Data.List (find)
2424
import Data.Maybe (catMaybes, fromJust)
@@ -60,6 +60,8 @@ import Ide.Types (CommandFunction,
6060
PluginCommand (PluginCommand),
6161
PluginDescriptor (..),
6262
PluginId,
63+
configCustomConfig,
64+
defaultConfigDescriptor,
6365
defaultPluginDescriptor,
6466
mkCustomConfig,
6567
mkPluginHandler)
@@ -90,7 +92,7 @@ descriptor plId =
9092
{ pluginHandlers = mkPluginHandler STextDocumentCodeLens codeLensProvider
9193
, pluginCommands = [PluginCommand (CommandId typeLensCommandId) "adds a signature" commandHandler]
9294
, pluginRules = rules
93-
, pluginCustomConfig = mkCustomConfig properties
95+
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
9496
}
9597

9698
properties :: Properties '[ 'PropertyKey "mode" ('TEnum Mode)]
@@ -212,8 +214,8 @@ data Mode
212214
deriving (Eq, Ord, Show, Read, Enum)
213215

214216
instance A.ToJSON Mode where
215-
toJSON Always = "always"
216-
toJSON Exported = "exported"
217+
toJSON Always = "always"
218+
toJSON Exported = "exported"
217219
toJSON Diagnostics = "diagnostics"
218220

219221
instance A.FromJSON Mode where

hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs

+28-21
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
module Ide.Plugin.ConfigUtils where
77

8-
import qualified Data.Aeson as A
9-
import qualified Data.Aeson.Types as A
10-
import Data.Default (def)
11-
import qualified Data.Dependent.Map as DMap
12-
import qualified Data.Dependent.Sum as DSum
13-
import qualified Data.HashMap.Lazy as HMap
8+
import qualified Data.Aeson as A
9+
import qualified Data.Aeson.Types as A
10+
import Data.Containers.ListUtils (nubOrd)
11+
import Data.Default (def)
12+
import qualified Data.Dependent.Map as DMap
13+
import qualified Data.Dependent.Sum as DSum
14+
import qualified Data.HashMap.Lazy as HMap
1415
import Ide.Plugin.Config
15-
import Ide.Plugin.Properties (toDefaultJSON, toVSCodeExtensionSchema)
16+
import Ide.Plugin.Properties (toDefaultJSON,
17+
toVSCodeExtensionSchema)
1618
import Ide.Types
1719
import Language.LSP.Types
1820

@@ -49,7 +51,7 @@ pluginsToDefaultConfig IdePlugins {..} =
4951
-- }
5052
-- }
5153
-- }
52-
singlePlugin PluginDescriptor {..} =
54+
singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} =
5355
let x = genericDefaultConfig <> dedicatedDefaultConfig
5456
in [pId A..= A.object x | not $ null x]
5557
where
@@ -58,20 +60,17 @@ pluginsToDefaultConfig IdePlugins {..} =
5860
-- Example:
5961
--
6062
-- {
61-
-- "globalOn": true,
6263
-- "codeActionsOn": true,
6364
-- "codeLensOn": true
6465
-- }
6566
--
66-
-- we don't generate the config section if the plugin doesn't register any of the following six methods,
67-
-- which avoids producing trivial configuration for formatters:
68-
--
69-
-- "stylish-haskell": {
70-
-- "globalOn": true
71-
-- }
7267
genericDefaultConfig =
73-
let x = mconcat (handlersToGenericDefaultConfig <$> handlers)
74-
in ["globalOn" A..= True | not $ null x] <> x
68+
let x = ["diagnosticsOn" A..= True | configHasDiagnostics] <> nubOrd (mconcat (handlersToGenericDefaultConfig <$> handlers))
69+
in case x of
70+
-- if the plugin has only one capability, we produce globalOn instead of the specific one;
71+
-- otherwise we don't produce globalOn at all
72+
[_] -> ["globalOn" A..= True]
73+
_ -> x
7574
-- Example:
7675
--
7776
-- {
@@ -80,7 +79,7 @@ pluginsToDefaultConfig IdePlugins {..} =
8079
-- }
8180
--}
8281
dedicatedDefaultConfig =
83-
let x = customConfigToDedicatedDefaultConfig pluginCustomConfig
82+
let x = customConfigToDedicatedDefaultConfig configCustomConfig
8483
in ["config" A..= A.object x | not $ null x]
8584

8685
(PluginId pId) = pluginId
@@ -101,13 +100,21 @@ pluginsToDefaultConfig IdePlugins {..} =
101100
pluginsToVSCodeExtensionSchema :: IdePlugins a -> A.Value
102101
pluginsToVSCodeExtensionSchema IdePlugins {..} = A.object $ mconcat $ singlePlugin <$> map snd ipMap
103102
where
104-
singlePlugin PluginDescriptor {..} = genericSchema <> dedicatedSchema
103+
singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} = genericSchema <> dedicatedSchema
105104
where
106105
(PluginHandlers (DMap.toList -> handlers)) = pluginHandlers
107106
customConfigToDedicatedSchema (CustomConfig p) = toVSCodeExtensionSchema (withIdPrefix "config.") p
108107
(PluginId pId) = pluginId
109-
genericSchema = withIdPrefix "globalOn" A..= schemaEntry "plugin" : mconcat (handlersToGenericSchema <$> handlers)
110-
dedicatedSchema = customConfigToDedicatedSchema pluginCustomConfig
108+
genericSchema =
109+
let x =
110+
[withIdPrefix "diagnosticsOn" A..= schemaEntry "diagnostics" | configHasDiagnostics]
111+
<> nubOrd (mconcat (handlersToGenericSchema <$> handlers))
112+
in case x of
113+
-- If the plugin has only one capability, we produce globalOn instead of the specific one;
114+
-- otherwise we don't produce globalOn at all
115+
[_] -> [withIdPrefix "globalOn" A..= schemaEntry "plugin"]
116+
_ -> x
117+
dedicatedSchema = customConfigToDedicatedSchema configCustomConfig
111118
handlersToGenericSchema (IdeMethod m DSum.:=> _) = case m of
112119
STextDocumentCodeAction -> [withIdPrefix "codeActionsOn" A..= schemaEntry "code actions"]
113120
STextDocumentCodeLens -> [withIdPrefix "codeLensOn" A..= schemaEntry "code lenses"]

hls-plugin-api/src/Ide/Types.hs

+33-5
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,47 @@ data PluginDescriptor ideState =
6363
, pluginRules :: !(Rules ())
6464
, pluginCommands :: ![PluginCommand ideState]
6565
, pluginHandlers :: PluginHandlers ideState
66-
, pluginCustomConfig :: CustomConfig
66+
, pluginConfigDescriptor :: ConfigDescriptor
6767
, pluginNotificationHandlers :: PluginNotificationHandlers ideState
6868
}
6969

70-
-- | An existential wrapper of 'Properties', used only for documenting and generating config templates
70+
-- | An existential wrapper of 'Properties'
7171
data CustomConfig = forall r. CustomConfig (Properties r)
7272

73-
emptyCustomConfig :: CustomConfig
74-
emptyCustomConfig = CustomConfig emptyProperties
73+
-- | Describes the configuration a plugin.
74+
-- A plugin may be configurable in such form:
75+
-- @
76+
-- {
77+
-- "plugin-id": {
78+
-- "globalOn": true,
79+
-- "codeActionsOn": true,
80+
-- "codeLensOn": true,
81+
-- "config": {
82+
-- "property1": "foo"
83+
-- }
84+
-- }
85+
-- }
86+
-- @
87+
-- @globalOn@, @codeActionsOn@, and @codeLensOn@ etc. are called generic configs,
88+
-- which can be inferred from handlers registered by the plugin.
89+
-- @config@ is called custom config, which is defined using 'Properties'.
90+
data ConfigDescriptor = ConfigDescriptor {
91+
-- | Whether or not to generate generic configs.
92+
configEnableGenericConfig :: Bool,
93+
-- | Whether or not to generate @diagnosticsOn@ config.
94+
-- Diagnostics emit in arbitrary shake rules,
95+
-- so we can't know statically if the plugin produces diagnostics
96+
configHasDiagnostics :: Bool,
97+
-- | Custom config.
98+
configCustomConfig :: CustomConfig
99+
}
75100

76101
mkCustomConfig :: Properties r -> CustomConfig
77102
mkCustomConfig = CustomConfig
78103

104+
defaultConfigDescriptor :: ConfigDescriptor
105+
defaultConfigDescriptor = ConfigDescriptor True False (mkCustomConfig emptyProperties)
106+
79107
-- | Methods that can be handled by plugins.
80108
-- 'ExtraParams' captures any extra data the IDE passes to the handlers for this method
81109
-- Only methods for which we know how to combine responses can be instances of 'PluginMethod'
@@ -267,7 +295,7 @@ defaultPluginDescriptor plId =
267295
mempty
268296
mempty
269297
mempty
270-
emptyCustomConfig
298+
defaultConfigDescriptor
271299
mempty
272300

273301
newtype CommandId = CommandId T.Text

plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ descriptor plId = (defaultPluginDescriptor plId)
9696
, PluginCommand "applyAll" "Apply all hints to the file" applyAllCmd
9797
]
9898
, pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider
99+
, pluginConfigDescriptor = defaultConfigDescriptor {configHasDiagnostics = True}
99100
}
100101

101102
-- This rule only exists for generating file diagnostics

plugins/hls-tactics-plugin/src/Wingman/Plugin.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ descriptor plId = (defaultPluginDescriptor plId)
6060
, mkPluginHandler STextDocumentCodeLens codeLensProvider
6161
]
6262
, pluginRules = wingmanRules plId
63-
, pluginCustomConfig =
64-
mkCustomConfig properties
63+
, pluginConfigDescriptor =
64+
defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
6565
}
6666

6767

0 commit comments

Comments
 (0)