Skip to content

Improve vscode extension schema generation #1742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ghcide/src/Development/IDE/Plugin/Completions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ descriptor plId = (defaultPluginDescriptor plId)
{ pluginRules = produceCompletions
, pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP
, pluginCommands = [extendImportCommand]
, pluginCustomConfig = mkCustomConfig properties
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
}

produceCompletions :: Rules ()
Expand Down
3 changes: 2 additions & 1 deletion ghcide/src/Development/IDE/Plugin/HLS/GhcIde.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ descriptors =
descriptor :: PluginId -> PluginDescriptor IdeState
descriptor plId = (defaultPluginDescriptor plId)
{ pluginHandlers = mkPluginHandler STextDocumentHover hover'
<> mkPluginHandler STextDocumentDocumentSymbol symbolsProvider
<> mkPluginHandler STextDocumentDocumentSymbol symbolsProvider,
pluginConfigDescriptor = defaultConfigDescriptor {configEnableGenericConfig = False}
}

-- ---------------------------------------------------------------------
Expand Down
10 changes: 6 additions & 4 deletions ghcide/src/Development/IDE/Plugin/TypeLenses.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import Control.DeepSeq (rwhnf)
import Control.Monad (mzero)
import Control.Monad.Extra (whenMaybe)
import Control.Monad.IO.Class (MonadIO (liftIO))
import qualified Data.Aeson.Types as A
import Data.Aeson.Types (Value (..), toJSON)
import qualified Data.Aeson.Types as A
import qualified Data.HashMap.Strict as Map
import Data.List (find)
import Data.Maybe (catMaybes, fromJust)
Expand Down Expand Up @@ -60,6 +60,8 @@ import Ide.Types (CommandFunction,
PluginCommand (PluginCommand),
PluginDescriptor (..),
PluginId,
configCustomConfig,
defaultConfigDescriptor,
defaultPluginDescriptor,
mkCustomConfig,
mkPluginHandler)
Expand Down Expand Up @@ -90,7 +92,7 @@ descriptor plId =
{ pluginHandlers = mkPluginHandler STextDocumentCodeLens codeLensProvider
, pluginCommands = [PluginCommand (CommandId typeLensCommandId) "adds a signature" commandHandler]
, pluginRules = rules
, pluginCustomConfig = mkCustomConfig properties
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
}

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

instance A.ToJSON Mode where
toJSON Always = "always"
toJSON Exported = "exported"
toJSON Always = "always"
toJSON Exported = "exported"
toJSON Diagnostics = "diagnostics"

instance A.FromJSON Mode where
Expand Down
49 changes: 28 additions & 21 deletions hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@

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.Aeson as A
import qualified Data.Aeson.Types as A
import Data.Containers.ListUtils (nubOrd)
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 Ide.Plugin.Config
import Ide.Plugin.Properties (toDefaultJSON, toVSCodeExtensionSchema)
import Ide.Plugin.Properties (toDefaultJSON,
toVSCodeExtensionSchema)
import Ide.Types
import Language.LSP.Types

Expand Down Expand Up @@ -49,7 +51,7 @@ pluginsToDefaultConfig IdePlugins {..} =
-- }
-- }
-- }
singlePlugin PluginDescriptor {..} =
singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} =
let x = genericDefaultConfig <> dedicatedDefaultConfig
in [pId A..= A.object x | not $ null x]
where
Expand All @@ -58,20 +60,17 @@ pluginsToDefaultConfig IdePlugins {..} =
-- 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
let x = ["diagnosticsOn" A..= True | configHasDiagnostics] <> nubOrd (mconcat (handlersToGenericDefaultConfig <$> handlers))
in case x of
-- if the plugin has only one capability, we produce globalOn instead of the specific one;
-- otherwise we don't produce globalOn at all
[_] -> ["globalOn" A..= True]
_ -> x
-- Example:
--
-- {
Expand All @@ -80,7 +79,7 @@ pluginsToDefaultConfig IdePlugins {..} =
-- }
--}
dedicatedDefaultConfig =
let x = customConfigToDedicatedDefaultConfig pluginCustomConfig
let x = customConfigToDedicatedDefaultConfig configCustomConfig
in ["config" A..= A.object x | not $ null x]

(PluginId pId) = pluginId
Expand All @@ -101,13 +100,21 @@ pluginsToDefaultConfig IdePlugins {..} =
pluginsToVSCodeExtensionSchema :: IdePlugins a -> A.Value
pluginsToVSCodeExtensionSchema IdePlugins {..} = A.object $ mconcat $ singlePlugin <$> map snd ipMap
where
singlePlugin PluginDescriptor {..} = genericSchema <> dedicatedSchema
singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} = 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
genericSchema =
let x =
[withIdPrefix "diagnosticsOn" A..= schemaEntry "diagnostics" | configHasDiagnostics]
<> nubOrd (mconcat (handlersToGenericSchema <$> handlers))
in case x of
-- If the plugin has only one capability, we produce globalOn instead of the specific one;
-- otherwise we don't produce globalOn at all
[_] -> [withIdPrefix "globalOn" A..= schemaEntry "plugin"]
_ -> x
dedicatedSchema = customConfigToDedicatedSchema configCustomConfig
handlersToGenericSchema (IdeMethod m DSum.:=> _) = case m of
STextDocumentCodeAction -> [withIdPrefix "codeActionsOn" A..= schemaEntry "code actions"]
STextDocumentCodeLens -> [withIdPrefix "codeLensOn" A..= schemaEntry "code lenses"]
Expand Down
38 changes: 33 additions & 5 deletions hls-plugin-api/src/Ide/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,47 @@ data PluginDescriptor ideState =
, pluginRules :: !(Rules ())
, pluginCommands :: ![PluginCommand ideState]
, pluginHandlers :: PluginHandlers ideState
, pluginCustomConfig :: CustomConfig
, pluginConfigDescriptor :: ConfigDescriptor
, pluginNotificationHandlers :: PluginNotificationHandlers ideState
}

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

emptyCustomConfig :: CustomConfig
emptyCustomConfig = CustomConfig emptyProperties
-- | Describes the configuration a plugin.
-- A plugin may be configurable in such form:
-- @
-- {
-- "plugin-id": {
-- "globalOn": true,
-- "codeActionsOn": true,
-- "codeLensOn": true,
-- "config": {
-- "property1": "foo"
-- }
-- }
-- }
-- @
-- @globalOn@, @codeActionsOn@, and @codeLensOn@ etc. are called generic configs,
-- which can be inferred from handlers registered by the plugin.
-- @config@ is called custom config, which is defined using 'Properties'.
data ConfigDescriptor = ConfigDescriptor {
-- | Whether or not to generate generic configs.
configEnableGenericConfig :: Bool,
-- | Whether or not to generate @diagnosticsOn@ config.
-- Diagnostics emit in arbitrary shake rules,
-- so we can't know statically if the plugin produces diagnostics
configHasDiagnostics :: Bool,
-- | Custom config.
configCustomConfig :: CustomConfig
}

mkCustomConfig :: Properties r -> CustomConfig
mkCustomConfig = CustomConfig

defaultConfigDescriptor :: ConfigDescriptor
defaultConfigDescriptor = ConfigDescriptor True False (mkCustomConfig emptyProperties)

-- | Methods that can be handled by plugins.
-- 'ExtraParams' captures any extra data the IDE passes to the handlers for this method
-- Only methods for which we know how to combine responses can be instances of 'PluginMethod'
Expand Down Expand Up @@ -267,7 +295,7 @@ defaultPluginDescriptor plId =
mempty
mempty
mempty
emptyCustomConfig
defaultConfigDescriptor
mempty

newtype CommandId = CommandId T.Text
Expand Down
1 change: 1 addition & 0 deletions plugins/hls-hlint-plugin/src/Ide/Plugin/Hlint.hs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ descriptor plId = (defaultPluginDescriptor plId)
, PluginCommand "applyAll" "Apply all hints to the file" applyAllCmd
]
, pluginHandlers = mkPluginHandler STextDocumentCodeAction codeActionProvider
, pluginConfigDescriptor = defaultConfigDescriptor {configHasDiagnostics = True}
}

-- This rule only exists for generating file diagnostics
Expand Down
4 changes: 2 additions & 2 deletions plugins/hls-tactics-plugin/src/Wingman/Plugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ descriptor plId = (defaultPluginDescriptor plId)
, mkPluginHandler STextDocumentCodeLens codeLensProvider
]
, pluginRules = wingmanRules plId
, pluginCustomConfig =
mkCustomConfig properties
, pluginConfigDescriptor =
defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
}


Expand Down