@@ -12,21 +12,27 @@ module Development.IDE.Plugin.Completions
1212import Control.Concurrent.Async (concurrently )
1313import Control.Concurrent.STM.Stats (readTVarIO )
1414import Control.Monad.IO.Class
15+ import Control.Lens ((&) , (.~) )
1516import qualified Data.HashMap.Strict as Map
1617import qualified Data.HashSet as Set
18+ import Data.Aeson
1719import Data.Maybe
1820import qualified Data.Text as T
1921import Development.IDE.Core.PositionMapping
22+ import Development.IDE.Core.Compile
2023import Development.IDE.Core.RuleTypes
2124import Development.IDE.Core.Service hiding (Log , LogShake )
2225import Development.IDE.Core.Shake hiding (Log )
2326import qualified Development.IDE.Core.Shake as Shake
2427import Development.IDE.GHC.Compat
28+ import Development.IDE.GHC.Util
2529import Development.IDE.Graph
30+ import Development.IDE.Spans.Common
31+ import Development.IDE.Spans.Documentation
2632import Development.IDE.Plugin.Completions.Logic
2733import Development.IDE.Plugin.Completions.Types
2834import Development.IDE.Types.Exports
29- import Development.IDE.Types.HscEnvEq (HscEnvEq (envPackageExports ),
35+ import Development.IDE.Types.HscEnvEq (HscEnvEq (envPackageExports , envVisibleModuleNames ),
3036 hscEnv )
3137import qualified Development.IDE.Types.KnownTargets as KT
3238import Development.IDE.Types.Location
@@ -37,6 +43,8 @@ import Development.IDE.Types.Logger (Pretty (pretty),
3743import Ide.Types
3844import qualified Language.LSP.Server as LSP
3945import Language.LSP.Types
46+ import qualified Language.LSP.Types.Lens as J
47+ import qualified Language.LSP.VFS as VFS
4048import Numeric.Natural
4149import Text.Fuzzy.Parallel (Scored (.. ))
4250
@@ -57,10 +65,12 @@ descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeSta
5765descriptor recorder plId = (defaultPluginDescriptor plId)
5866 { pluginRules = produceCompletions recorder
5967 , pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP
68+ <> mkPluginHandler SCompletionItemResolve resolveCompletion
6069 , pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
6170 , pluginPriority = ghcideCompletionsPluginPriority
6271 }
6372
73+
6474produceCompletions :: Recorder (WithPriority Log ) -> Rules ()
6575produceCompletions recorder = do
6676 define (cmapWithPrio LogShake recorder) $ \ LocalCompletions file -> do
@@ -85,8 +95,9 @@ produceCompletions recorder = do
8595 (global, inScope) <- liftIO $ tcRnImportDecls env (dropListFromImportDecl <$> msrImports) `concurrently` tcRnImportDecls env msrImports
8696 case (global, inScope) of
8797 ((_, Just globalEnv), (_, Just inScopeEnv)) -> do
98+ visibleMods <- liftIO $ fmap (fromMaybe [] ) $ envVisibleModuleNames sess
8899 let uri = fromNormalizedUri $ normalizedFilePathToUri file
89- cdata <- liftIO $ cacheDataProducer uri sess (ms_mod msrModSummary) globalEnv inScopeEnv msrImports
100+ let cdata = cacheDataProducer uri visibleMods (ms_mod msrModSummary) globalEnv inScopeEnv msrImports
90101 return ([] , Just cdata)
91102 (_diag, _) ->
92103 return ([] , Nothing )
@@ -102,6 +113,49 @@ dropListFromImportDecl iDecl = let
102113 f x = x
103114 in f <$> iDecl
104115
116+ resolveCompletion :: IdeState -> PluginId -> CompletionItem -> LSP. LspM Config (Either ResponseError CompletionItem )
117+ resolveCompletion ide _ comp@ CompletionItem {_detail,_documentation,_xdata}
118+ | Just resolveData <- _xdata
119+ , Success (CompletionResolveData uri needType (NameDetails mod occ)) <- fromJSON resolveData
120+ , Just file <- uriToNormalizedFilePath $ toNormalizedUri uri
121+ = liftIO $ runIdeAction " Completion resolve" (shakeExtras ide) $ do
122+ msess <- useWithStaleFast GhcSessionDeps file
123+ case msess of
124+ Nothing -> pure (Right comp) -- File doesn't compile, return original completion item
125+ Just (sess,_) -> do
126+ let nc = ideNc $ shakeExtras ide
127+ #if MIN_VERSION_ghc(9,3,0)
128+ name <- liftIO $ lookupNameCache nc mod occ
129+ #else
130+ name <- liftIO $ upNameCache nc (lookupNameCache mod occ)
131+ #endif
132+ mdkm <- useWithStaleFast GetDocMap file
133+ let (dm,km) = case mdkm of
134+ Just (DKMap dm km, _) -> (dm,km)
135+ Nothing -> (mempty , mempty )
136+ doc <- case lookupNameEnv dm name of
137+ Just doc -> pure $ spanDocToMarkdown doc
138+ Nothing -> liftIO $ spanDocToMarkdown <$> getDocumentationTryGhc (hscEnv sess) name
139+ typ <- case lookupNameEnv km name of
140+ _ | not needType -> pure Nothing
141+ Just ty -> pure (safeTyThingType ty)
142+ Nothing -> do
143+ (safeTyThingType =<< ) <$> liftIO (lookupName (hscEnv sess) name)
144+ let det1 = case typ of
145+ Just ty -> Just (" :: " <> printOutputable (stripForall ty) <> " \n " )
146+ Nothing -> Nothing
147+ doc1 = case _documentation of
148+ Just (CompletionDocMarkup (MarkupContent MkMarkdown old)) ->
149+ CompletionDocMarkup $ MarkupContent MkMarkdown $ T. intercalate sectionSeparator (old: doc)
150+ _ -> CompletionDocMarkup $ MarkupContent MkMarkdown $ T. intercalate sectionSeparator doc
151+ pure (Right $ comp & J. detail .~ (det1 <> _detail)
152+ & J. documentation .~ Just doc1
153+ )
154+ where
155+ stripForall ty = case splitForAllTyCoVars ty of
156+ (_,res) -> res
157+ resolveCompletion _ _ comp = pure (Right comp)
158+
105159-- | Generate code actions.
106160getCompletionsLSP
107161 :: IdeState
@@ -160,7 +214,7 @@ getCompletionsLSP ide plId
160214 plugins = idePlugins $ shakeExtras ide
161215 config <- liftIO $ runAction " " ide $ getCompletionsConfig plId
162216
163- allCompletions <- liftIO $ getCompletions plugins ideOpts cci' parsedMod astres bindMap pfix clientCaps config moduleExports
217+ allCompletions <- liftIO $ getCompletions plugins ideOpts cci' parsedMod astres bindMap pfix clientCaps config moduleExports uri
164218 pure $ InL (List $ orderedCompletions allCompletions)
165219 _ -> return (InL $ List [] )
166220 _ -> return (InL $ List [] )
0 commit comments