Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Regularize custom config of plugins (#1576)
* Support declarative custom config, add --vscode-extension-schema * Add globalOn * Add --generate-default-config * Port tactic plugin * Fix build of tactic plugin test * Fix tactic plugin test * Revert format changes in tactics plugin * Change the descriptor of tactics plugin to "tactics" * Update plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs Co-authored-by: Sandy Maguire <sandy@sandymaguire.me> * Apply a bunch of @isovector's suggestions * Document Ide.Plugin.ConfigUtils * Add TInteger * Fix build Co-authored-by: Sandy Maguire <sandy@sandymaguire.me> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Loading branch information
1 parent
982c4ee
commit f135edb
Showing
18 changed files
with
738 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
{-# LANGUAGE GADTs #-} | ||
{-# LANGUAGE OverloadedStrings #-} | ||
{-# LANGUAGE RecordWildCards #-} | ||
{-# LANGUAGE ViewPatterns #-} | ||
|
||
module Ide.Plugin.ConfigUtils where | ||
|
||
import qualified Data.Aeson as A | ||
import qualified Data.Aeson.Types as A | ||
import Data.Default (def) | ||
import qualified Data.Dependent.Map as DMap | ||
import qualified Data.Dependent.Sum as DSum | ||
import qualified Data.HashMap.Lazy as HMap | ||
import qualified Data.Map as Map | ||
import Ide.Plugin.Config | ||
import Ide.Plugin.Properties (toDefaultJSON, toVSCodeExtensionSchema) | ||
import Ide.Types | ||
import Language.LSP.Types | ||
|
||
-- Attention: | ||
-- 'diagnosticsOn' will never be added into the default config or the schema, | ||
-- since diagnostics emit in arbitrary shake rules -- we don't know | ||
-- whether a plugin is capable of producing diagnostics. | ||
|
||
-- | Generates a defalut 'Config', but remains only effective items | ||
pluginsToDefaultConfig :: IdePlugins a -> A.Value | ||
pluginsToDefaultConfig IdePlugins {..} = | ||
A.Object $ | ||
HMap.adjust | ||
( \(unsafeValueToObject -> o) -> | ||
A.Object $ HMap.insert "plugin" elems o -- inplace the "plugin" section with our 'elems', leaving others unchanged | ||
) | ||
"haskell" | ||
(unsafeValueToObject (A.toJSON defaultConfig)) | ||
where | ||
defaultConfig@Config {} = def | ||
unsafeValueToObject (A.Object o) = o | ||
unsafeValueToObject _ = error "impossible" | ||
elems = A.object $ mconcat $ singlePlugin <$> Map.elems ipMap | ||
-- Splice genericDefaultConfig and dedicatedDefaultConfig | ||
-- Example: | ||
-- | ||
-- { | ||
-- "plugin-id": { | ||
-- "globalOn": true, | ||
-- "codeActionsOn": true, | ||
-- "codeLensOn": true, | ||
-- "config": { | ||
-- "property1": "foo" | ||
-- } | ||
-- } | ||
-- } | ||
singlePlugin PluginDescriptor {..} = | ||
let x = genericDefaultConfig <> dedicatedDefaultConfig | ||
in [pId A..= A.object x | not $ null x] | ||
where | ||
(PluginHandlers (DMap.toList -> handlers)) = pluginHandlers | ||
customConfigToDedicatedDefaultConfig (CustomConfig p) = toDefaultJSON p | ||
-- Example: | ||
-- | ||
-- { | ||
-- "globalOn": true, | ||
-- "codeActionsOn": true, | ||
-- "codeLensOn": true | ||
-- } | ||
-- | ||
-- we don't generate the config section if the plugin doesn't register any of the following six methods, | ||
-- which avoids producing trivial configuration for formatters: | ||
-- | ||
-- "stylish-haskell": { | ||
-- "globalOn": true | ||
-- } | ||
genericDefaultConfig = | ||
let x = mconcat (handlersToGenericDefaultConfig <$> handlers) | ||
in ["globalOn" A..= True | not $ null x] <> x | ||
-- Example: | ||
-- | ||
-- { | ||
-- "config": { | ||
-- "property1": "foo" | ||
-- } | ||
--} | ||
dedicatedDefaultConfig = | ||
let x = customConfigToDedicatedDefaultConfig pluginCustomConfig | ||
in ["config" A..= A.object x | not $ null x] | ||
|
||
(PluginId pId) = pluginId | ||
|
||
-- This function captures ide methods registered by the plugin, and then converts it to kv pairs | ||
handlersToGenericDefaultConfig :: DSum.DSum IdeMethod f -> [A.Pair] | ||
handlersToGenericDefaultConfig (IdeMethod m DSum.:=> _) = case m of | ||
STextDocumentCodeAction -> ["codeActionsOn" A..= True] | ||
STextDocumentCodeLens -> ["codeLensOn" A..= True] | ||
STextDocumentRename -> ["renameOn" A..= True] | ||
STextDocumentHover -> ["hoverOn" A..= True] | ||
STextDocumentDocumentSymbol -> ["symbolsOn" A..= True] | ||
STextDocumentCompletion -> ["completionOn" A..= True] | ||
_ -> [] | ||
|
||
-- | Generates json schema used in haskell vscode extension | ||
-- Similar to 'pluginsToDefaultConfig' but simpler, since schema has a flatten structure | ||
pluginsToVSCodeExtensionSchema :: IdePlugins a -> A.Value | ||
pluginsToVSCodeExtensionSchema IdePlugins {..} = A.object $ mconcat $ singlePlugin <$> Map.elems ipMap | ||
where | ||
singlePlugin PluginDescriptor {..} = genericSchema <> dedicatedSchema | ||
where | ||
(PluginHandlers (DMap.toList -> handlers)) = pluginHandlers | ||
customConfigToDedicatedSchema (CustomConfig p) = toVSCodeExtensionSchema (withIdPrefix "config.") p | ||
(PluginId pId) = pluginId | ||
genericSchema = withIdPrefix "globalOn" A..= schemaEntry "plugin" : mconcat (handlersToGenericSchema <$> handlers) | ||
dedicatedSchema = customConfigToDedicatedSchema pluginCustomConfig | ||
handlersToGenericSchema (IdeMethod m DSum.:=> _) = case m of | ||
STextDocumentCodeAction -> [withIdPrefix "codeActionsOn" A..= schemaEntry "code actions"] | ||
STextDocumentCodeLens -> [withIdPrefix "codeLensOn" A..= schemaEntry "code lenses"] | ||
STextDocumentRename -> [withIdPrefix "renameOn" A..= schemaEntry "rename"] | ||
STextDocumentHover -> [withIdPrefix "hoverOn" A..= schemaEntry "hover"] | ||
STextDocumentDocumentSymbol -> [withIdPrefix "symbolsOn" A..= schemaEntry "symbols"] | ||
STextDocumentCompletion -> [withIdPrefix "completionOn" A..= schemaEntry "completions"] | ||
_ -> [] | ||
schemaEntry desc = | ||
A.object | ||
[ "scope" A..= A.String "resource", | ||
"type" A..= A.String "boolean", | ||
"default" A..= True, | ||
"description" A..= A.String ("Enables " <> pId <> " " <> desc) | ||
] | ||
withIdPrefix x = "haskell.plugin." <> pId <> "." <> x |
Oops, something went wrong.