hls-plugin-api 1.2.0.2 → 1.3.0.0
raw patch · 8 files changed
+186/−125 lines, 8 filesdep +extradep +hls-plugin-apidep +lens-aesondep ~basedep ~hls-graphdep ~lspPVP ok
version bump matches the API change (PVP)
Dependencies added: extra, hls-plugin-api, lens-aeson, lsp-types, tasty, tasty-hunit, tasty-rerun, transformers
Dependency ranges changed: base, hls-graph, lsp
API changes (from Hackage documentation)
- Ide.Plugin.Config: [diagnosticsOnChange] :: Config -> !Bool
- Ide.Plugin.Config: [formatOnImportOn] :: Config -> !Bool
- Ide.Plugin.Config: [hlintOn] :: Config -> !Bool
- Ide.Plugin.Config: [liquidOn] :: Config -> !Bool
+ Ide.Plugin.Config: [plcSelectionRangeOn] :: PluginConfig -> !Bool
+ Ide.PluginUtils: handleMaybe :: Monad m => e -> Maybe b -> ExceptT e m b
+ Ide.PluginUtils: handleMaybeM :: Monad m => e -> m (Maybe b) -> ExceptT e m b
+ Ide.PluginUtils: positionInRange :: Position -> Range -> Bool
+ Ide.PluginUtils: response :: Monad m => ExceptT String m a -> m (Either ResponseError a)
+ Ide.Types: instance Ide.Types.PluginMethod 'Language.LSP.Types.Method.TextDocumentSelectionRange
- Ide.Plugin.Config: Config :: CheckParents -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Text -> !Int -> !Map Text PluginConfig -> Config
+ Ide.Plugin.Config: Config :: CheckParents -> !Bool -> !Text -> !Int -> !Map Text PluginConfig -> Config
- Ide.Plugin.Config: PluginConfig :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Object -> PluginConfig
+ Ide.Plugin.Config: PluginConfig :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Object -> PluginConfig
Files
- hls-plugin-api.cabal +21/−3
- src/Ide/Plugin/Config.hs +50/−62
- src/Ide/Plugin/ConfigUtils.hs +19/−20
- src/Ide/Plugin/Properties.hs +14/−15
- src/Ide/PluginUtils.hs +33/−16
- src/Ide/Types.hs +9/−9
- test/Ide/PluginUtilsTest.hs +27/−0
- test/Main.hs +13/−0
hls-plugin-api.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: hls-plugin-api-version: 1.2.0.2+version: 1.3.0.0 synopsis: Haskell Language Server API for plugin communication description: Please see the README on GitHub at <https://github.com/haskell/haskell-language-server#readme>@@ -43,17 +43,20 @@ , dependent-sum , Diff ^>=0.4.0 , dlist+ , extra , ghc , hashable- , hls-graph >=1.4 && < 1.6+ , hls-graph ^>= 1.6 , hslogger , lens- , lsp ^>=1.2.0.1+ , lens-aeson+ , lsp ^>=1.4.0.0 , opentelemetry , optparse-applicative , process , regex-tdfa >=1.3.1.0 , text+ , transformers , unordered-containers if os(windows)@@ -74,3 +77,18 @@ DataKinds KindSignatures TypeOperators++test-suite tests+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ hs-source-dirs: test+ main-is: Main.hs+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ other-modules: Ide.PluginUtilsTest+ build-depends:+ base+ , hls-plugin-api+ , tasty+ , tasty-hunit+ , tasty-rerun+ , lsp-types
src/Ide/Plugin/Config.hs view
@@ -47,25 +47,17 @@ -- will be surprises relating to config options being ignored, initially though. data Config = Config- { checkParents :: CheckParents- , checkProject :: !Bool- , hlintOn :: !Bool- , diagnosticsOnChange :: !Bool- , liquidOn :: !Bool- , formatOnImportOn :: !Bool- , formattingProvider :: !T.Text- , maxCompletions :: !Int- , plugins :: !(Map.Map T.Text PluginConfig)+ { checkParents :: CheckParents+ , checkProject :: !Bool+ , formattingProvider :: !T.Text+ , maxCompletions :: !Int+ , plugins :: !(Map.Map T.Text PluginConfig) } deriving (Show,Eq) instance Default Config where def = Config { checkParents = CheckOnSave , checkProject = True- , hlintOn = True- , diagnosticsOnChange = True- , liquidOn = False- , formatOnImportOn = True -- , formattingProvider = "brittany" , formattingProvider = "ormolu" -- , formattingProvider = "floskell"@@ -85,10 +77,6 @@ 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 .:? "liquidOn" .!= liquidOn defValue- <*> o .:? "formatOnImportOn" .!= formatOnImportOn defValue <*> o .:? "formattingProvider" .!= formattingProvider defValue <*> o .:? "maxCompletions" .!= maxCompletions defValue <*> o .:? "plugin" .!= plugins defValue@@ -99,10 +87,6 @@ where r = object [ "checkParents" .= checkParents , "checkProject" .= checkProject- , "hlintOn" .= hlintOn- , "diagnosticsOnChange" .= diagnosticsOnChange- , "liquidOn" .= liquidOn- , "formatOnImportOn" .= formatOnImportOn , "formattingProvider" .= formattingProvider , "maxCompletions" .= maxCompletions , "plugin" .= plugins@@ -116,58 +100,62 @@ -- This provides a regular naming scheme for all plugin config. data PluginConfig = PluginConfig- { plcGlobalOn :: !Bool- , plcCallHierarchyOn :: !Bool- , plcCodeActionsOn :: !Bool- , plcCodeLensOn :: !Bool- , plcDiagnosticsOn :: !Bool- , plcHoverOn :: !Bool- , plcSymbolsOn :: !Bool- , plcCompletionOn :: !Bool- , plcRenameOn :: !Bool- , plcConfig :: !A.Object+ { plcGlobalOn :: !Bool+ , plcCallHierarchyOn :: !Bool+ , plcCodeActionsOn :: !Bool+ , plcCodeLensOn :: !Bool+ , plcDiagnosticsOn :: !Bool+ , plcHoverOn :: !Bool+ , plcSymbolsOn :: !Bool+ , plcCompletionOn :: !Bool+ , plcRenameOn :: !Bool+ , plcSelectionRangeOn :: !Bool+ , plcConfig :: !A.Object } deriving (Show,Eq) instance Default PluginConfig where def = PluginConfig- { plcGlobalOn = True- , plcCallHierarchyOn = True- , plcCodeActionsOn = True- , plcCodeLensOn = True- , plcDiagnosticsOn = True- , plcHoverOn = True- , plcSymbolsOn = True- , plcCompletionOn = True- , plcRenameOn = True- , plcConfig = mempty+ { plcGlobalOn = True+ , plcCallHierarchyOn = True+ , plcCodeActionsOn = True+ , plcCodeLensOn = True+ , plcDiagnosticsOn = True+ , plcHoverOn = True+ , plcSymbolsOn = True+ , plcCompletionOn = True+ , plcRenameOn = True+ , plcSelectionRangeOn = True+ , plcConfig = mempty } instance A.ToJSON PluginConfig where- toJSON (PluginConfig g ch ca cl d h s c rn cfg) = r+ toJSON (PluginConfig g ch ca cl d h s c rn sr cfg) = r where- r = object [ "globalOn" .= g- , "callHierarchyOn" .= ch- , "codeActionsOn" .= ca- , "codeLensOn" .= cl- , "diagnosticsOn" .= d- , "hoverOn" .= h- , "symbolsOn" .= s- , "completionOn" .= c- , "renameOn" .= rn- , "config" .= cfg+ r = object [ "globalOn" .= g+ , "callHierarchyOn" .= ch+ , "codeActionsOn" .= ca+ , "codeLensOn" .= cl+ , "diagnosticsOn" .= d+ , "hoverOn" .= h+ , "symbolsOn" .= s+ , "completionOn" .= c+ , "renameOn" .= rn+ , "selectionRangeOn" .= sr+ , "config" .= cfg ] instance A.FromJSON PluginConfig where parseJSON = A.withObject "PluginConfig" $ \o -> PluginConfig- <$> o .:? "globalOn" .!= plcGlobalOn def- <*> o .:? "callHierarchyOn" .!= plcCallHierarchyOn 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+ <$> o .:? "globalOn" .!= plcGlobalOn def+ <*> o .:? "callHierarchyOn" .!= plcCallHierarchyOn 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 .:? "selectionRangeOn" .!= plcSelectionRangeOn def+ <*> o .:? "config" .!= plcConfig def -- ---------------------------------------------------------------------
src/Ide/Plugin/ConfigUtils.hs view
@@ -5,13 +5,16 @@ module Ide.Plugin.ConfigUtils where +import Control.Lens (at, ix, (&), (?~)) import qualified Data.Aeson as A+import Data.Aeson.Lens (_Object) 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 Data.List (nub)+import Data.String (IsString (fromString))+import qualified Data.Text as T import Ide.Plugin.Config import Ide.Plugin.Properties (toDefaultJSON, toVSCodeExtensionSchema) import Ide.Types@@ -25,17 +28,12 @@ -- | Generates a default '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))+ -- Use 'ix' to look at all the "haskell" keys in the outer value (since we're not+ -- setting it if missing), then we use '_Object' and 'at' to get at the "plugin" key+ -- and actually set it.+ A.toJSON defaultConfig & ix "haskell" . _Object . at "plugin" ?~ elems where defaultConfig@Config {} = def- unsafeValueToObject (A.Object o) = o- unsafeValueToObject _ = error "impossible" elems = A.object $ mconcat $ singlePlugin <$> map snd ipMap -- Splice genericDefaultConfig and dedicatedDefaultConfig -- Example:@@ -52,7 +50,7 @@ -- } singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} = let x = genericDefaultConfig <> dedicatedDefaultConfig- in [pId A..= A.object x | not $ null x]+ in [fromString (T.unpack pId) A..= A.object x | not $ null x] where (PluginHandlers (DMap.toList -> handlers)) = pluginHandlers customConfigToDedicatedDefaultConfig (CustomConfig p) = toDefaultJSON p@@ -107,22 +105,22 @@ (PluginId pId) = pluginId genericSchema = let x =- [withIdPrefix "diagnosticsOn" A..= schemaEntry "diagnostics" | configHasDiagnostics]+ [toKey' "diagnosticsOn" A..= schemaEntry "diagnostics" | configHasDiagnostics] <> nub (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"]+ [_] -> [toKey' "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"]- STextDocumentRename -> [withIdPrefix "renameOn" A..= schemaEntry "rename"]- STextDocumentHover -> [withIdPrefix "hoverOn" A..= schemaEntry "hover"]- STextDocumentDocumentSymbol -> [withIdPrefix "symbolsOn" A..= schemaEntry "symbols"]- STextDocumentCompletion -> [withIdPrefix "completionOn" A..= schemaEntry "completions"]- STextDocumentPrepareCallHierarchy -> [withIdPrefix "callHierarchyOn" A..= schemaEntry "call hierarchy"]+ STextDocumentCodeAction -> [toKey' "codeActionsOn" A..= schemaEntry "code actions"]+ STextDocumentCodeLens -> [toKey' "codeLensOn" A..= schemaEntry "code lenses"]+ STextDocumentRename -> [toKey' "renameOn" A..= schemaEntry "rename"]+ STextDocumentHover -> [toKey' "hoverOn" A..= schemaEntry "hover"]+ STextDocumentDocumentSymbol -> [toKey' "symbolsOn" A..= schemaEntry "symbols"]+ STextDocumentCompletion -> [toKey' "completionOn" A..= schemaEntry "completions"]+ STextDocumentPrepareCallHierarchy -> [toKey' "callHierarchyOn" A..= schemaEntry "call hierarchy"] _ -> [] schemaEntry desc = A.object@@ -132,3 +130,4 @@ "description" A..= A.String ("Enables " <> pId <> " " <> desc) ] withIdPrefix x = "haskell.plugin." <> pId <> "." <> x+ toKey' = fromString . T.unpack . withIdPrefix
src/Ide/Plugin/Properties.hs view
@@ -3,17 +3,14 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ViewPatterns #-} -- See Note [Constraints] {-# OPTIONS_GHC -Wno-redundant-constraints #-} @@ -49,6 +46,7 @@ import Data.Kind (Constraint, Type) import qualified Data.Map.Strict as Map import Data.Proxy (Proxy (..))+import Data.String (IsString (fromString)) import qualified Data.Text as T import GHC.OverloadedLabels (IsLabel (..)) import GHC.TypeLits@@ -164,6 +162,7 @@ -- "Description of exampleNumber" -- 233 -- @+ emptyProperties :: Properties '[] emptyProperties = Properties Map.empty @@ -237,7 +236,7 @@ (SEnum _, EnumMetaData {..}) -> A.parseEither ( \o -> do- txt <- o A..: keyName+ txt <- o A..: key if txt `elem` enumValues then pure txt else@@ -249,9 +248,9 @@ ) x where- keyName = T.pack $ symbolVal kn+ key = fromString $ symbolVal kn parseEither :: forall a. A.FromJSON a => Either String a- parseEither = A.parseEither (A..: keyName) x+ parseEither = A.parseEither (A..: key) x -- --------------------------------------------------------------------- @@ -354,26 +353,26 @@ toDefaultJSON (Properties p) = [toEntry s v | (s, v) <- Map.toList p] where toEntry :: String -> SomePropertyKeyWithMetaData -> A.Pair- toEntry (T.pack -> s) = \case+ toEntry s = \case (SomePropertyKeyWithMetaData SNumber MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData SInteger MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData SString MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData SBoolean MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData (SObject _) MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData (SArray _) MetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue (SomePropertyKeyWithMetaData (SEnum _) EnumMetaData {..}) ->- s A..= defaultValue+ fromString s A..= defaultValue -- | Converts a properties definition into kv pairs as vscode schema toVSCodeExtensionSchema :: T.Text -> Properties r -> [A.Pair] toVSCodeExtensionSchema prefix (Properties p) =- [(prefix <> T.pack k) A..= toEntry v | (k, v) <- Map.toList p]+ [fromString (T.unpack prefix <> k) A..= toEntry v | (k, v) <- Map.toList p] where toEntry :: SomePropertyKeyWithMetaData -> A.Value toEntry = \case
src/Ide/PluginUtils.hs view
@@ -25,15 +25,24 @@ allLspCmdIds', installSigUsr1Handler, subRange,+ positionInRange, usePropertyLsp,+ response,+ handleMaybe,+ handleMaybeM, ) where +import Control.Monad.Extra (maybeM)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Except (ExceptT, runExceptT, throwE) import Data.Algorithm.Diff import Data.Algorithm.DiffOutput+import Data.Bifunctor (Bifunctor (first)) import Data.Containers.ListUtils (nubOrdOn) import qualified Data.HashMap.Strict as H+import Data.String (IsString (fromString)) import qualified Data.Text as T import Ide.Plugin.Config import Ide.Plugin.Properties@@ -99,15 +108,15 @@ -} diffOperationToTextEdit (Deletion (LineRange (sl, el) _) _) = J.TextEdit range "" where- range = J.Range (J.Position (sl - 1) 0)- (J.Position el 0)+ range = J.Range (J.Position (fromIntegral $ sl - 1) 0)+ (J.Position (fromIntegral el) 0) diffOperationToTextEdit (Addition fm l) = J.TextEdit range nt -- fm has a range wrt to the changed file, which starts in the current file at l + 1 -- So the range has to be shifted to start at l + 1 where- range = J.Range (J.Position l 0)- (J.Position l 0)+ range = J.Range (J.Position (fromIntegral l) 0)+ (J.Position (fromIntegral l) 0) nt = T.pack $ unlines $ lrContents fm @@ -115,10 +124,10 @@ where sl = fst $ lrNumbers fm sc = 0- s = J.Position (sl - 1) sc -- Note: zero-based lines+ s = J.Position (fromIntegral $ sl - 1) sc -- Note: zero-based lines el = snd $ lrNumbers fm- ec = length $ last $ lrContents fm- e = J.Position (el - 1) ec -- Note: zero-based lines+ ec = fromIntegral $ length $ last $ lrContents fm+ e = J.Position (fromIntegral $ el - 1) ec -- Note: zero-based lines -- | A pure version of 'diffText' for testing@@ -137,7 +146,7 @@ clientSupportsDocumentChanges :: ClientCapabilities -> Bool clientSupportsDocumentChanges caps =- let ClientCapabilities mwCaps _ _ _ = caps+ let ClientCapabilities mwCaps _ _ _ _ = caps supports = do wCaps <- mwCaps WorkspaceEditClientCapabilities mDc _ _ _ _ <- _workspaceEdit wCaps@@ -170,7 +179,7 @@ getPluginConfig :: MonadLsp Config m => PluginId -> m PluginConfig getPluginConfig plugin = do config <- getClientConfig- return $ flip configForPlugin plugin config+ return $ configForPlugin config plugin -- --------------------------------------------------------------------- @@ -189,7 +198,7 @@ extractRange :: Range -> T.Text -> T.Text extractRange (Range (Position sl _) (Position el _)) s = newS- where focusLines = take (el-sl+1) $ drop sl $ T.lines s+ where focusLines = take (fromIntegral $ el-sl+1) $ drop (fromIntegral sl) $ T.lines s newS = T.unlines focusLines -- | Gets the range that covers the entire text@@ -204,7 +213,7 @@ the line ending character(s) then use an end position denoting the start of the next line" -}- lastLine = length $ T.lines s+ lastLine = fromIntegral $ length $ T.lines s subRange :: Range -> Range -> Bool subRange smallRange range =@@ -212,11 +221,7 @@ && positionInRange (_end smallRange) range positionInRange :: Position -> Range -> Bool-positionInRange (Position pl po) (Range (Position sl so) (Position el eo)) =- pl > sl && pl < el- || pl == sl && pl == el && po >= so && po <= eo- || pl == sl && po >= so- || pl == el && po <= eo+positionInRange p (Range sp ep) = sp <= p && p <= ep -- --------------------------------------------------------------------- @@ -236,3 +241,15 @@ where go (plid, cmds) = map (mkLspCmdId pid plid . commandId) cmds +-- ---------------------------------------------------------------------++handleMaybe :: Monad m => e -> Maybe b -> ExceptT e m b+handleMaybe msg = maybe (throwE msg) return++handleMaybeM :: Monad m => e -> m (Maybe b) -> ExceptT e m b+handleMaybeM msg act = maybeM (throwE msg) return $ lift act++response :: Monad m => ExceptT String m a -> m (Either ResponseError a)+response =+ fmap (first (\msg -> ResponseError InternalError (fromString msg) Nothing))+ . runExceptT
src/Ide/Types.hs view
@@ -24,11 +24,11 @@ #ifdef mingw32_HOST_OS import qualified System.Win32.Process as P (getCurrentProcessId) #else+import Control.Monad (void) import qualified System.Posix.Process as P (getProcessID) import System.Posix.Signals #endif import Control.Lens ((^.))-import Control.Monad import Data.Aeson hiding (defaultOptions) import qualified Data.DList as DList import qualified Data.Default@@ -178,7 +178,7 @@ instance PluginMethod TextDocumentCodeAction where pluginEnabled _ = pluginEnabledConfig plcCodeActionsOn- combineResponses _method _config (ClientCapabilities _ textDocCaps _ _) (CodeActionParams _ _ _ _ context) resps =+ combineResponses _method _config (ClientCapabilities _ textDocCaps _ _ _) (CodeActionParams _ _ _ _ context) resps = fmap compat $ List $ filter wasRequested $ (\(List x) -> x) $ sconcat resps where @@ -202,11 +202,7 @@ -- should check whether the requested kind is a *prefix* of the action kind. -- That means, for example, we will return actions with kinds `quickfix.import` and -- `quickfix.somethingElse` if the requested kind is `quickfix`.- -- TODO: add helpers in `lsp` for handling code action hierarchies- -- For now we abuse the fact that the JSON representation gives us the hierarchical string.- , Just caKind <- ca ^. kind- , String caKindStr <- toJSON caKind =- any (\k -> k `T.isPrefixOf` caKindStr) [kstr | k <- allowed, let String kstr = toJSON k ]+ , Just caKind <- ca ^. kind = any (\k -> k `codeActionKindSubsumes` caKind) allowed | otherwise = False instance PluginMethod TextDocumentCodeLens where@@ -224,7 +220,7 @@ instance PluginMethod TextDocumentDocumentSymbol where pluginEnabled _ = pluginEnabledConfig plcSymbolsOn- combineResponses _ _ (ClientCapabilities _ tdc _ _) params xs = res+ combineResponses _ _ (ClientCapabilities _ tdc _ _ _) params xs = res where uri' = params ^. textDocument . uri supportsHierarchy = Just True == (tdc >>= _documentSymbol >>= _hierarchicalDocumentSymbolSupport)@@ -249,7 +245,7 @@ combineResponses _ conf _ _ (toList -> xs) = snd $ consumeCompletionResponse limit $ combine xs where limit = maxCompletions conf- combine :: [List CompletionItem |? CompletionList] -> ((List CompletionItem) |? CompletionList)+ combine :: [List CompletionItem |? CompletionList] -> (List CompletionItem |? CompletionList) combine cs = go True mempty cs go !comp acc [] =@@ -283,6 +279,10 @@ instance PluginMethod TextDocumentPrepareCallHierarchy where pluginEnabled _ = pluginEnabledConfig plcCallHierarchyOn++instance PluginMethod TextDocumentSelectionRange where+ pluginEnabled _ = pluginEnabledConfig plcSelectionRangeOn+ combineResponses _ _ _ _ (x :| _) = x instance PluginMethod CallHierarchyIncomingCalls where pluginEnabled _ = pluginEnabledConfig plcCallHierarchyOn
+ test/Ide/PluginUtilsTest.hs view
@@ -0,0 +1,27 @@+module Ide.PluginUtilsTest+ ( tests+ ) where++import Ide.PluginUtils (positionInRange)+import Language.LSP.Types (Position (Position), Range (Range))+import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests = testGroup "PluginUtils"+ [ positionInRangeTest+ ]++positionInRangeTest :: TestTree+positionInRangeTest = testGroup "positionInRange"+ [ testCase "single line, after the end" $+ positionInRange (Position 1 10) (Range (Position 1 1) (Position 1 3)) @?= False+ , testCase "single line, before the begining" $+ positionInRange (Position 1 0) (Range (Position 1 1) (Position 1 6)) @?= False+ , testCase "single line, in range" $+ positionInRange (Position 1 5) (Range (Position 1 1) (Position 1 6)) @?= True+ , testCase "multiline, in range" $+ positionInRange (Position 3 5) (Range (Position 1 1) (Position 5 6)) @?= True+ , testCase "multiline, out of range" $+ positionInRange (Position 3 5) (Range (Position 3 6) (Position 4 10)) @?= False+ ]
+ test/Main.hs view
@@ -0,0 +1,13 @@+module Main where++import qualified Ide.PluginUtilsTest as PluginUtilsTest+import Test.Tasty+import Test.Tasty.Ingredients.Rerun++main :: IO ()+main = defaultMainWithRerun tests++tests :: TestTree+tests = testGroup "Main"+ [ PluginUtilsTest.tests+ ]