@@ -12,21 +12,27 @@ module Development.IDE.Plugin.Completions
12
12
import Control.Concurrent.Async (concurrently )
13
13
import Control.Concurrent.STM.Stats (readTVarIO )
14
14
import Control.Monad.IO.Class
15
+ import Control.Lens ((&) , (.~) )
15
16
import qualified Data.HashMap.Strict as Map
16
17
import qualified Data.HashSet as Set
18
+ import Data.Aeson
17
19
import Data.Maybe
18
20
import qualified Data.Text as T
19
21
import Development.IDE.Core.PositionMapping
22
+ import Development.IDE.Core.Compile
20
23
import Development.IDE.Core.RuleTypes
21
24
import Development.IDE.Core.Service hiding (Log , LogShake )
22
25
import Development.IDE.Core.Shake hiding (Log )
23
26
import qualified Development.IDE.Core.Shake as Shake
24
27
import Development.IDE.GHC.Compat
28
+ import Development.IDE.GHC.Util
25
29
import Development.IDE.Graph
30
+ import Development.IDE.Spans.Common
31
+ import Development.IDE.Spans.Documentation
26
32
import Development.IDE.Plugin.Completions.Logic
27
33
import Development.IDE.Plugin.Completions.Types
28
34
import Development.IDE.Types.Exports
29
- import Development.IDE.Types.HscEnvEq (HscEnvEq (envPackageExports ),
35
+ import Development.IDE.Types.HscEnvEq (HscEnvEq (envPackageExports , envVisibleModuleNames ),
30
36
hscEnv )
31
37
import qualified Development.IDE.Types.KnownTargets as KT
32
38
import Development.IDE.Types.Location
@@ -37,6 +43,8 @@ import Development.IDE.Types.Logger (Pretty (pretty),
37
43
import Ide.Types
38
44
import qualified Language.LSP.Server as LSP
39
45
import Language.LSP.Types
46
+ import qualified Language.LSP.Types.Lens as J
47
+ import qualified Language.LSP.VFS as VFS
40
48
import Numeric.Natural
41
49
import Text.Fuzzy.Parallel (Scored (.. ))
42
50
@@ -57,10 +65,12 @@ descriptor :: Recorder (WithPriority Log) -> PluginId -> PluginDescriptor IdeSta
57
65
descriptor recorder plId = (defaultPluginDescriptor plId)
58
66
{ pluginRules = produceCompletions recorder
59
67
, pluginHandlers = mkPluginHandler STextDocumentCompletion getCompletionsLSP
68
+ <> mkPluginHandler SCompletionItemResolve resolveCompletion
60
69
, pluginConfigDescriptor = defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}
61
70
, pluginPriority = ghcideCompletionsPluginPriority
62
71
}
63
72
73
+
64
74
produceCompletions :: Recorder (WithPriority Log ) -> Rules ()
65
75
produceCompletions recorder = do
66
76
define (cmapWithPrio LogShake recorder) $ \ LocalCompletions file -> do
@@ -85,8 +95,9 @@ produceCompletions recorder = do
85
95
(global, inScope) <- liftIO $ tcRnImportDecls env (dropListFromImportDecl <$> msrImports) `concurrently` tcRnImportDecls env msrImports
86
96
case (global, inScope) of
87
97
((_, Just globalEnv), (_, Just inScopeEnv)) -> do
98
+ visibleMods <- liftIO $ fmap (fromMaybe [] ) $ envVisibleModuleNames sess
88
99
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
90
101
return ([] , Just cdata)
91
102
(_diag, _) ->
92
103
return ([] , Nothing )
@@ -102,6 +113,49 @@ dropListFromImportDecl iDecl = let
102
113
f x = x
103
114
in f <$> iDecl
104
115
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
+
105
159
-- | Generate code actions.
106
160
getCompletionsLSP
107
161
:: IdeState
@@ -160,7 +214,7 @@ getCompletionsLSP ide plId
160
214
plugins = idePlugins $ shakeExtras ide
161
215
config <- liftIO $ runAction " " ide $ getCompletionsConfig plId
162
216
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
164
218
pure $ InL (List $ orderedCompletions allCompletions)
165
219
_ -> return (InL $ List [] )
166
220
_ -> return (InL $ List [] )
0 commit comments