diff --git a/exe/Plugins.hs b/exe/Plugins.hs index 8dafaa3495..cba0c73658 100644 --- a/exe/Plugins.hs +++ b/exe/Plugins.hs @@ -211,12 +211,8 @@ idePlugins recorder includeExamples = pluginDescToIdePlugins allPlugins #if hls_gadt GADT.descriptor "gadt" : #endif - -- The ghcide descriptors should come last so that the notification handlers - -- (which restart the Shake build) run after everything else GhcIde.descriptors pluginRecorder #if explicitFixity - -- Make this plugin has a lower priority than ghcide's plugin to ensure - -- type info display first. ++ [ExplicitFixity.descriptor pluginRecorder] #endif examplePlugins = diff --git a/ghcide/ghcide.cabal b/ghcide/ghcide.cabal index c1a62f679b..8db4b73e50 100644 --- a/ghcide/ghcide.cabal +++ b/ghcide/ghcide.cabal @@ -192,6 +192,7 @@ library Development.IDE.Monitoring.EKG Development.IDE.LSP.HoverDefinition Development.IDE.LSP.LanguageServer + Development.IDE.LSP.Notifications Development.IDE.LSP.Outline Development.IDE.LSP.Server Development.IDE.Session @@ -225,7 +226,6 @@ library Development.IDE.Core.FileExists Development.IDE.GHC.CPP Development.IDE.GHC.Warnings - Development.IDE.LSP.Notifications Development.IDE.Plugin.CodeAction.PositionIndexed Development.IDE.Plugin.CodeAction.Args Development.IDE.Plugin.Completions.Logic diff --git a/ghcide/src/Development/IDE/LSP/Notifications.hs b/ghcide/src/Development/IDE/LSP/Notifications.hs index fbdd35489d..3830358af8 100644 --- a/ghcide/src/Development/IDE/LSP/Notifications.hs +++ b/ghcide/src/Development/IDE/LSP/Notifications.hs @@ -10,6 +10,7 @@ module Development.IDE.LSP.Notifications ( whenUriFile , descriptor , Log(..) + , ghcideNotificationsPluginPriority ) where import Language.LSP.Types @@ -38,6 +39,7 @@ import Development.IDE.Types.Location import Development.IDE.Types.Logger import Development.IDE.Types.Shake (toKey) import Ide.Types +import Numeric.Natural data Log = LogShake Shake.Log @@ -138,5 +140,12 @@ descriptor recorder plId = (defaultPluginDescriptor plId) { pluginNotificationHa success <- registerFileWatches globs unless success $ liftIO $ logDebug (ideLogger ide) "Warning: Client does not support watched files. Falling back to OS polling" - ] + ], + + -- The ghcide descriptors should come last'ish so that the notification handlers + -- (which restart the Shake build) run after everything else + pluginPriority = ghcideNotificationsPluginPriority } + +ghcideNotificationsPluginPriority :: Natural +ghcideNotificationsPluginPriority = defaultPluginPriority - 900 diff --git a/ghcide/src/Development/IDE/Main.hs b/ghcide/src/Development/IDE/Main.hs index 7ce2ac47d5..d5e19856a7 100644 --- a/ghcide/src/Development/IDE/Main.hs +++ b/ghcide/src/Development/IDE/Main.hs @@ -21,6 +21,7 @@ import Control.Exception.Safe (SomeException, import Control.Monad.Extra (concatMapM, unless, when) import qualified Data.Aeson.Encode.Pretty as A +import Data.Coerce (coerce) import Data.Default (Default (def)) import Data.Foldable (traverse_) import Data.Hashable (hashed) @@ -92,7 +93,8 @@ import Development.IDE.Types.Logger (Logger, Recorder, WithPriority, cmapWithPrio, - logWith, vsep, (<+>)) + logWith, nest, vsep, + (<+>)) import Development.IDE.Types.Monitoring (Monitoring) import Development.IDE.Types.Options (IdeGhcSession, IdeOptions (optCheckParents, optCheckProject, optReportProgress, optRunSubset), @@ -122,7 +124,7 @@ import Ide.Types (IdeCommand (IdeComman IdePlugins, PluginDescriptor (PluginDescriptor, pluginCli), PluginId (PluginId), - ipMap) + ipMap, pluginId) import qualified Language.LSP.Server as LSP import qualified "list-t" ListT import Numeric.Natural (Natural) @@ -146,7 +148,7 @@ import Text.Printf (printf) data Log = LogHeapStats !HeapStats.Log - | LogLspStart + | LogLspStart [PluginId] | LogLspStartDuration !Seconds | LogShouldRunSubset !Bool | LogOnlyPartialGhc92Support @@ -163,10 +165,12 @@ data Log instance Pretty Log where pretty = \case LogHeapStats log -> pretty log - LogLspStart -> - vsep - [ "Staring LSP server..." - , "If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!"] + LogLspStart pluginIds -> + nest 2 $ vsep + [ "Starting LSP server..." + , "If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!" + , "PluginIds:" <+> pretty (coerce @_ @[T.Text] pluginIds) + ] LogLspStartDuration duration -> "Started LSP server in" <+> pretty (showDuration duration) LogShouldRunSubset shouldRunSubset -> @@ -224,7 +228,7 @@ commandP plugins = pluginCommands = mconcat [ command (T.unpack pId) (Custom <$> p) - | (PluginId pId, PluginDescriptor{pluginCli = Just p}) <- ipMap plugins + | PluginDescriptor{pluginCli = Just p, pluginId = PluginId pId} <- ipMap plugins ] @@ -336,7 +340,7 @@ defaultMain recorder Arguments{..} = withHeapStats (cmapWithPrio LogHeapStats re LT.putStrLn $ decodeUtf8 $ A.encodePretty $ pluginsToDefaultConfig argsHlsPlugins LSP -> withNumCapabilities (maybe (numProcessors `div` 2) fromIntegral argsThreads) $ do t <- offsetTime - log Info LogLspStart + log Info $ LogLspStart (pluginId <$> ipMap argsHlsPlugins) let getIdeState :: LSP.LanguageContextEnv Config -> Maybe FilePath -> WithHieDb -> IndexQueue -> IO IdeState getIdeState env rootPath withHieDb hieChan = do diff --git a/ghcide/src/Development/IDE/Plugin/Completions.hs b/ghcide/src/Development/IDE/Plugin/Completions.hs index c0a76bc360..4e5e96a3bd 100644 --- a/ghcide/src/Development/IDE/Plugin/Completions.hs +++ b/ghcide/src/Development/IDE/Plugin/Completions.hs @@ -5,6 +5,7 @@ module Development.IDE.Plugin.Completions ( descriptor , Log(..) + , ghcideCompletionsPluginPriority ) where import Control.Concurrent.Async (concurrently) @@ -49,6 +50,7 @@ import Ide.Types import qualified Language.LSP.Server as LSP import Language.LSP.Types import qualified Language.LSP.VFS as VFS +import Numeric.Natural import Text.Fuzzy.Parallel (Scored (..)) data Log = LogShake Shake.Log deriving Show @@ -57,12 +59,16 @@ instance Pretty Log where pretty = \case LogShake log -> pretty log +ghcideCompletionsPluginPriority :: Natural +ghcideCompletionsPluginPriority = defaultPluginPriority + descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeState descriptor recorder plId = (defaultPluginDescriptor plId) { pluginRules = produceCompletions recorder , pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP , pluginCommands = [extendImportCommand] , pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties} + , pluginPriority = ghcideCompletionsPluginPriority } produceCompletions :: Recorder (WithPriority Log) -> Rules () diff --git a/ghcide/src/Development/IDE/Plugin/HLS.hs b/ghcide/src/Development/IDE/Plugin/HLS.hs index bd192f18e8..447e516771 100644 --- a/ghcide/src/Development/IDE/Plugin/HLS.hs +++ b/ghcide/src/Development/IDE/Plugin/HLS.hs @@ -13,7 +13,6 @@ import Control.Exception (SomeException) import Control.Lens ((^.)) import Control.Monad import qualified Data.Aeson as J -import Data.Bifunctor import Data.Dependent.Map (DMap) import qualified Data.Dependent.Map as DMap import Data.Dependent.Sum @@ -96,7 +95,7 @@ asGhcIdePlugin recorder (IdePlugins ls) = mkPlugin :: ([(PluginId, b)] -> Plugin Config) -> (PluginDescriptor IdeState -> b) -> Plugin Config mkPlugin maker selector = - case map (second selector) ls of + case map (\p -> (pluginId p, selector p)) ls of -- If there are no plugins that provide a descriptor, use mempty to -- create the plugin – otherwise we we end up declaring handlers for -- capabilities that there are no plugins for diff --git a/ghcide/test/exe/Main.hs b/ghcide/test/exe/Main.hs index c4a4b082a7..73caa02437 100644 --- a/ghcide/test/exe/Main.hs +++ b/ghcide/test/exe/Main.hs @@ -290,7 +290,8 @@ initializeResponseTests = withResource acquire release tests where doTest = do ir <- getInitializeResponse let Just ExecuteCommandOptions {_commands = List commands} = getActual $ innerCaps ir - zipWithM_ (\e o -> T.isSuffixOf e o @? show (e,o)) expected commands + commandNames = (!! 2) . T.splitOn ":" <$> commands + zipWithM_ (\e o -> T.isSuffixOf e o @? show (e,o)) (sort expected) (sort commandNames) innerCaps :: ResponseMessage Initialize -> ServerCapabilities innerCaps (ResponseMessage _ _ (Right (InitializeResult c _))) = c @@ -6750,24 +6751,26 @@ unitTests recorder logger = do let expected = "1:2-3:4" assertBool (unwords ["expected to find range", expected, "in diagnostic", shown]) $ expected `isInfixOf` shown - , testCase "notification handlers run sequentially" $ do + , testCase "notification handlers run in priority order" $ do orderRef <- newIORef [] let plugins = pluginDescToIdePlugins $ - [ (defaultPluginDescriptor $ fromString $ show i) + [ (priorityPluginDescriptor i) { pluginNotificationHandlers = mconcat [ mkPluginNotificationHandler LSP.STextDocumentDidOpen $ \_ _ _ _ -> liftIO $ atomicModifyIORef_ orderRef (i:) ] } - | i <- [(1::Int)..20] + | i <- [1..20] ] ++ Ghcide.descriptors (cmapWithPrio LogGhcIde recorder) + priorityPluginDescriptor i = (defaultPluginDescriptor $ fromString $ show i){pluginPriority = i} testIde recorder (IDE.testing (cmapWithPrio LogIDEMain recorder) logger){IDE.argsHlsPlugins = plugins} $ do _ <- createDoc "A.hs" "haskell" "module A where" waitForProgressDone - actualOrder <- liftIO $ readIORef orderRef + actualOrder <- liftIO $ reverse <$> readIORef orderRef - liftIO $ actualOrder @?= reverse [(1::Int)..20] + -- Handlers are run in priority descending order + liftIO $ actualOrder @?= [20, 19 .. 1] , ignoreTestBecause "The test fails sometimes showing 10000us" $ testCase "timestamps have millisecond resolution" $ do resolution_us <- findResolution_us 1 diff --git a/hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs b/hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs index cea719a995..8e07af801d 100644 --- a/hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs +++ b/hls-plugin-api/src/Ide/Plugin/ConfigUtils.hs @@ -34,7 +34,7 @@ pluginsToDefaultConfig IdePlugins {..} = A.toJSON defaultConfig & ix "haskell" . _Object . at "plugin" ?~ elems where defaultConfig@Config {} = def - elems = A.object $ mconcat $ singlePlugin <$> map snd ipMap + elems = A.object $ mconcat $ singlePlugin <$> ipMap -- Splice genericDefaultConfig and dedicatedDefaultConfig -- Example: -- @@ -96,7 +96,7 @@ pluginsToDefaultConfig IdePlugins {..} = -- | 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 snd ipMap +pluginsToVSCodeExtensionSchema IdePlugins {..} = A.object $ mconcat $ singlePlugin <$> ipMap where singlePlugin PluginDescriptor {pluginConfigDescriptor = ConfigDescriptor {..}, ..} = genericSchema <> dedicatedSchema where diff --git a/hls-plugin-api/src/Ide/PluginUtils.hs b/hls-plugin-api/src/Ide/PluginUtils.hs index 1f10b1cc70..b194c429c9 100644 --- a/hls-plugin-api/src/Ide/PluginUtils.hs +++ b/hls-plugin-api/src/Ide/PluginUtils.hs @@ -36,13 +36,13 @@ module Ide.PluginUtils where +import Control.Arrow ((&&&)) 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 @@ -159,11 +159,10 @@ clientSupportsDocumentChanges caps = -- --------------------------------------------------------------------- pluginDescToIdePlugins :: [PluginDescriptor ideState] -> IdePlugins ideState -pluginDescToIdePlugins plugins = - IdePlugins $ map (\p -> (pluginId p, p)) $ nubOrdOn pluginId plugins +pluginDescToIdePlugins = IdePlugins idePluginsToPluginDesc :: IdePlugins ideState -> [PluginDescriptor ideState] -idePluginsToPluginDesc (IdePlugins pp) = map snd pp +idePluginsToPluginDesc (IdePlugins pp) = pp -- --------------------------------------------------------------------- -- | Returns the current client configuration. It is not wise to permanently @@ -226,15 +225,8 @@ positionInRange p (Range sp ep) = sp <= p && p < ep -- Range's end position is e -- --------------------------------------------------------------------- allLspCmdIds' :: T.Text -> IdePlugins ideState -> [T.Text] -allLspCmdIds' pid (IdePlugins ls) = mkPlugin (allLspCmdIds pid) (Just . pluginCommands) - where - justs (p, Just x) = [(p, x)] - justs (_, Nothing) = [] - - - mkPlugin maker selector - = maker $ concatMap (\(pid, p) -> justs (pid, selector p)) ls - +allLspCmdIds' pid (IdePlugins ls) = + allLspCmdIds pid $ map (pluginId &&& pluginCommands) ls allLspCmdIds :: T.Text -> [(PluginId, [PluginCommand ideState])] -> [T.Text] allLspCmdIds pid commands = concatMap go commands diff --git a/hls-plugin-api/src/Ide/Types.hs b/hls-plugin-api/src/Ide/Types.hs index a9f2bb3050..95c04f24c5 100644 --- a/hls-plugin-api/src/Ide/Types.hs +++ b/hls-plugin-api/src/Ide/Types.hs @@ -12,6 +12,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -20,6 +21,31 @@ {-# LANGUAGE ViewPatterns #-} module Ide.Types +( PluginDescriptor(..), defaultPluginDescriptor, defaultCabalPluginDescriptor +, defaultPluginPriority +, IdeCommand(..) +, IdeMethod(..) +, IdeNotification(..) +, IdePlugins(IdePlugins, ipMap) +, DynFlagsModifications(..) +, ConfigDescriptor(..), defaultConfigDescriptor, configForPlugin, pluginEnabledConfig +, CustomConfig(..), mkCustomConfig +, FallbackCodeActionParams(..) +, FormattingType(..), FormattingMethod, FormattingHandler, mkFormattingHandlers +, HasTracing(..) +, PluginCommand(..), CommandId(..), CommandFunction, mkLspCommand, mkLspCmdId +, PluginId(..) +, PluginHandler(..), mkPluginHandler +, PluginHandlers(..) +, PluginMethod(..) +, PluginMethodHandler +, PluginNotificationHandler(..), mkPluginNotificationHandler +, PluginNotificationHandlers(..) +, PluginRequestMethod(..) +, getProcessID, getPid +, installSigUsr1Handler +, responseError +) where #ifdef mingw32_HOST_OS @@ -29,6 +55,7 @@ import Control.Monad (void) import qualified System.Posix.Process as P (getProcessID) import System.Posix.Signals #endif +import Control.Arrow ((&&&)) import Control.Lens ((^.)) import Data.Aeson hiding (defaultOptions) import qualified Data.Default @@ -36,9 +63,14 @@ import Data.Dependent.Map (DMap) import qualified Data.Dependent.Map as DMap import qualified Data.DList as DList import Data.GADT.Compare +import Data.Hashable (Hashable) +import Data.HashMap.Strict (HashMap) +import qualified Data.HashMap.Strict as HashMap +import Data.List.Extra (sortOn) import Data.List.NonEmpty (NonEmpty (..), toList) import qualified Data.Map as Map import Data.Maybe +import Data.Ord import Data.Semigroup import Data.String import qualified Data.Text as T @@ -68,6 +100,7 @@ import Language.LSP.Types.Lens as J (HasChildren (children), HasTitle (title), HasUri (..)) import Language.LSP.VFS +import Numeric.Natural import OpenTelemetry.Eventlog import Options.Applicative (ParserInfo) import System.FilePath @@ -76,9 +109,15 @@ import Text.Regex.TDFA.Text () -- --------------------------------------------------------------------- -newtype IdePlugins ideState = IdePlugins - { ipMap :: [(PluginId, PluginDescriptor ideState)]} - deriving newtype (Monoid, Semigroup) +newtype IdePlugins ideState = IdePlugins_ { ipMap_ :: HashMap PluginId (PluginDescriptor ideState)} + deriving newtype (Semigroup, Monoid) + +-- | Smart constructor that deduplicates plugins +pattern IdePlugins :: [PluginDescriptor ideState] -> IdePlugins ideState +pattern IdePlugins{ipMap} <- IdePlugins_ (sortOn (Down . pluginPriority) . HashMap.elems -> ipMap) + where + IdePlugins ipMap = IdePlugins_{ipMap_ = HashMap.fromList $ (pluginId &&& id) <$> ipMap} +{-# COMPLETE IdePlugins #-} -- | Hooks for modifying the 'DynFlags' at different times of the compilation -- process. Plugins can install a 'DynFlagsModifications' via @@ -113,6 +152,8 @@ instance Show (IdeCommand st) where show _ = "" data PluginDescriptor (ideState :: *) = PluginDescriptor { pluginId :: !PluginId -- ^ Unique identifier of the plugin. + , pluginPriority :: Natural + -- ^ Plugin handlers are called in priority order, higher priority first , pluginRules :: !(Rules ()) , pluginCommands :: ![PluginCommand ideState] , pluginHandlers :: PluginHandlers ideState @@ -595,6 +636,9 @@ mkPluginNotificationHandler m f where f' pid ide vfs = f ide vfs pid +defaultPluginPriority :: Natural +defaultPluginPriority = 1000 + -- | Set up a plugin descriptor, initialized with default values. -- This is plugin descriptor is prepared for @haskell@ files, such as -- @@ -608,6 +652,7 @@ defaultPluginDescriptor :: PluginId -> PluginDescriptor ideState defaultPluginDescriptor plId = PluginDescriptor plId + defaultPluginPriority mempty mempty mempty @@ -627,6 +672,7 @@ defaultCabalPluginDescriptor :: PluginId -> PluginDescriptor ideState defaultCabalPluginDescriptor plId = PluginDescriptor plId + defaultPluginPriority mempty mempty mempty @@ -658,6 +704,7 @@ type CommandFunction ideState a newtype PluginId = PluginId T.Text deriving (Show, Read, Eq, Ord) + deriving newtype Hashable instance IsString PluginId where fromString = PluginId . T.pack diff --git a/plugins/hls-explicit-fixity-plugin/src/Ide/Plugin/ExplicitFixity.hs b/plugins/hls-explicit-fixity-plugin/src/Ide/Plugin/ExplicitFixity.hs index fb4e1c1d06..fa0985b17b 100644 --- a/plugins/hls-explicit-fixity-plugin/src/Ide/Plugin/ExplicitFixity.hs +++ b/plugins/hls-explicit-fixity-plugin/src/Ide/Plugin/ExplicitFixity.hs @@ -28,6 +28,7 @@ import qualified Development.IDE.Core.Shake as Shake import Development.IDE.GHC.Compat import Development.IDE.GHC.Compat.Util (FastString) import qualified Development.IDE.GHC.Compat.Util as Util +import Development.IDE.LSP.Notifications (ghcideNotificationsPluginPriority) import GHC.Generics (Generic) import Ide.PluginUtils (getNormalizedFilePath, handleMaybeM, @@ -42,6 +43,9 @@ descriptor :: Recorder (WithPriority Log) -> PluginDescriptor IdeState descriptor recorder = (defaultPluginDescriptor pluginId) { pluginRules = fixityRule recorder , pluginHandlers = mkPluginHandler STextDocumentHover hover + -- Make this plugin has a lower priority than ghcide's plugin to ensure + -- type info display first. + , pluginPriority = ghcideNotificationsPluginPriority - 1 } hover :: PluginMethodHandler IdeState TextDocumentHover diff --git a/plugins/hls-pragmas-plugin/src/Ide/Plugin/Pragmas.hs b/plugins/hls-pragmas-plugin/src/Ide/Plugin/Pragmas.hs index 75f53e26a5..c26d9cbc79 100644 --- a/plugins/hls-pragmas-plugin/src/Ide/Plugin/Pragmas.hs +++ b/plugins/hls-pragmas-plugin/src/Ide/Plugin/Pragmas.hs @@ -14,21 +14,22 @@ module Ide.Plugin.Pragmas , validPragmas ) where -import Control.Lens hiding (List) -import Control.Monad.IO.Class (MonadIO (liftIO)) -import qualified Data.HashMap.Strict as H -import Data.List.Extra (nubOrdOn) -import Data.Maybe (catMaybes) -import qualified Data.Text as T +import Control.Lens hiding (List) +import Control.Monad.IO.Class (MonadIO (liftIO)) +import qualified Data.HashMap.Strict as H +import Data.List.Extra (nubOrdOn) +import Data.Maybe (catMaybes) +import qualified Data.Text as T import Development.IDE import Development.IDE.GHC.Compat -import qualified Development.IDE.Spans.Pragmas as Pragmas +import Development.IDE.Plugin.Completions (ghcideCompletionsPluginPriority) +import qualified Development.IDE.Spans.Pragmas as Pragmas import Ide.Types -import qualified Language.LSP.Server as LSP -import qualified Language.LSP.Types as J -import qualified Language.LSP.Types.Lens as J -import qualified Language.LSP.VFS as VFS -import qualified Text.Fuzzy as Fuzzy +import qualified Language.LSP.Server as LSP +import qualified Language.LSP.Types as J +import qualified Language.LSP.Types.Lens as J +import qualified Language.LSP.VFS as VFS +import qualified Text.Fuzzy as Fuzzy -- --------------------------------------------------------------------- @@ -36,6 +37,7 @@ descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId) { pluginHandlers = mkPluginHandler J.STextDocumentCodeAction codeActionProvider <> mkPluginHandler J.STextDocumentCompletion completion + , pluginPriority = ghcideCompletionsPluginPriority + 1 } -- --------------------------------------------------------------------- diff --git a/src/Ide/Main.hs b/src/Ide/Main.hs index d8d1df432f..a5a5acd594 100644 --- a/src/Ide/Main.hs +++ b/src/Ide/Main.hs @@ -32,7 +32,7 @@ import Ide.Arguments import Ide.Plugin.ConfigUtils (pluginsToDefaultConfig, pluginsToVSCodeExtensionSchema) import Ide.Types (IdePlugins, PluginId (PluginId), - ipMap) + ipMap, pluginId) import Ide.Version import System.Directory import qualified System.Directory.Extra as IO @@ -80,7 +80,7 @@ defaultMain recorder args idePlugins = do ListPluginsMode -> do let pluginNames = sort - $ map ((\(PluginId t) -> T.unpack t) . fst) + $ map ((\(PluginId t) -> T.unpack t) . pluginId) $ ipMap idePlugins mapM_ putStrLn pluginNames @@ -118,7 +118,7 @@ runLspMode recorder ghcideArgs@GhcideArguments{..} idePlugins = withTelemetryLog log Info $ LogDirectory dir when (isLSP argsCommand) $ do - log Info $ LogLspStart ghcideArgs (map fst $ ipMap idePlugins) + log Info $ LogLspStart ghcideArgs (map pluginId $ ipMap idePlugins) -- exists so old-style logging works. intended to be phased out let logger = Logger $ \p m -> logger_ recorder (WithPriority p emptyCallStack $ LogOther m) diff --git a/test/functional/Format.hs b/test/functional/Format.hs index af90fc7a9c..9b853d527e 100644 --- a/test/functional/Format.hs +++ b/test/functional/Format.hs @@ -47,7 +47,10 @@ providerTests = testGroup "formatting provider" [ testCase "respects none" $ runSessionWithConfig (formatConfig "none") hlsCommand fullCaps "test/testdata/format" $ do doc <- openDoc "Format.hs" "haskell" resp <- request STextDocumentFormatting $ DocumentFormattingParams Nothing doc (FormattingOptions 2 True Nothing Nothing Nothing) - liftIO $ resp ^. LSP.result @?= Left (ResponseError InvalidRequest "No plugin enabled for STextDocumentFormatting, available:\nPluginId \"floskell\"\nPluginId \"fourmolu\"\nPluginId \"ormolu\"\nPluginId \"stylish-haskell\"\nPluginId \"brittany\"\n" Nothing) + liftIO $ resp ^. LSP.result @?= Left (ResponseError InvalidRequest + ("No plugin enabled for STextDocumentFormatting, available:\n" + <> "PluginId \"floskell\"\nPluginId \"fourmolu\"\nPluginId \"stylish-haskell\"\nPluginId \"brittany\"\nPluginId \"ormolu\"\n") + Nothing) , requiresOrmoluPlugin . requiresFloskellPlugin $ testCase "can change on the fly" $ runSession hlsCommand fullCaps "test/testdata/format" $ do formattedOrmolu <- liftIO $ T.readFile "test/testdata/format/Format.ormolu.formatted.hs"