@@ -16,8 +16,8 @@ module Ide.Plugin.ExplicitImports
16
16
) where
17
17
18
18
import Control.DeepSeq
19
- import Control.Lens (_Just , (&) , (?~) , (^?) )
20
- import Control.Monad ( guard )
19
+ import Control.Lens (_Just , (&) , (?~) , (^.) ,
20
+ (^?) )
21
21
import Control.Monad.Error.Class (MonadError (throwError ))
22
22
import Control.Monad.IO.Class
23
23
import Control.Monad.Trans.Class (lift )
@@ -26,16 +26,14 @@ import Control.Monad.Trans.Maybe
26
26
import qualified Data.Aeson as A (ToJSON (toJSON ))
27
27
import Data.Aeson.Types (FromJSON )
28
28
import Data.Char (isSpace )
29
- import Data.Either (lefts )
30
29
import Data.Functor ((<&>) )
31
30
import qualified Data.IntMap as IM (IntMap , elems ,
32
31
fromList , (!?) )
33
32
import Data.IORef (readIORef )
34
- import Data.List (singleton , sortBy )
35
- import Data.List.NonEmpty (groupBy , head )
33
+ import Data.List (singleton )
36
34
import qualified Data.Map.Strict as Map
37
- import Data.Maybe (isJust , isNothing ,
38
- listToMaybe , mapMaybe )
35
+ import Data.Maybe (catMaybes , isJust ,
36
+ isNothing , mapMaybe )
39
37
import qualified Data.Set as S
40
38
import Data.String (fromString )
41
39
import qualified Data.Text as T
@@ -49,11 +47,9 @@ import Development.IDE.Core.PluginUtils
49
47
import Development.IDE.Core.PositionMapping
50
48
import qualified Development.IDE.Core.Shake as Shake
51
49
import Development.IDE.GHC.Compat hiding ((<+>) )
52
- import Development.IDE.GHC.Compat.Util (mkFastString )
53
50
import Development.IDE.Graph.Classes
54
51
import GHC.Generics (Generic )
55
- import GHC.Num (integerFromInt )
56
- import GHC.Parser.Annotation (EpAnn (entry ),
52
+ import GHC.Parser.Annotation (EpAnn (anns ),
57
53
HasLoc (getHasLoc ),
58
54
realSrcSpan )
59
55
import GHC.Types.PkgQual (RawPkgQual (NoRawPkgQual ))
@@ -251,89 +247,66 @@ importPackageInlayHintProvider _ state _ InlayHintParams {_textDocument = TextDo
251
247
then do
252
248
nfp <- getNormalizedFilePathE _uri
253
249
(hscEnvEq, _) <- runActionE " ImportPackageInlayHint.GhcSessionDeps" state $ useWithStaleE GhcSessionDeps nfp
254
- (HAR {hieAst, hieModule}, pmap) <- runActionE " ImportPackageInlayHint.GetHieAst" state $ useWithStaleE GetHieAst nfp
255
- ast <- handleMaybe
256
- (PluginRuleFailed " GetHieAst" )
257
- (getAsts hieAst Map. !? (HiePath . mkFastString . fromNormalizedFilePath) nfp)
258
- parsedModule <- runActionE " GADT.GetParsedModuleWithComments" state $ useE GetParsedModule nfp
259
- let (L _ hsImports) = hsmodImports <$> pm_parsed_source parsedModule
250
+ (parsedModule, pmap) <- runActionE " ImportPackageInlayHint.GetParsedModuleWithComments" state $ useWithStaleE GetParsedModule nfp
260
251
261
- let isPackageImport :: ImportDecl GhcPs -> Bool
262
- isPackageImport ImportDecl {ideclPkgQual = NoRawPkgQual } = False
263
- isPackageImport _ = True
252
+ let moduleNamePositions = getModuleNamePositions parsedModule
253
+ env = hscEnv hscEnvEq
254
+
255
+ packagePositions <- fmap catMaybes $ for moduleNamePositions $ \ (pos, moduleName) -> do
256
+ packageName <- liftIO $ packageNameForModuleName moduleName env
257
+ case packageName of
258
+ Nothing -> pure Nothing
259
+ Just packageName -> pure $ Just (pos, packageName)
264
260
265
- annotationToLineNumber :: EpAnn a -> Integer
266
- annotationToLineNumber = integerFromInt . srcSpanEndLine . realSrcSpan . getHasLoc . entry
267
-
268
- packageImportLineNumbers :: S. Set Integer
269
- packageImportLineNumbers =
270
- S. fromList $
271
- hsImports
272
- & filter (\ (L _ importDecl) -> isPackageImport importDecl)
273
- & map (\ (L annotation _) -> annotationToLineNumber annotation)
274
-
275
- hintsInfo <- liftIO $ getAllImportedPackagesHints (hscEnv hscEnvEq) (moduleName hieModule) ast
276
- -- Sort the hints by position and group them by line
277
- -- Show only first hint in each line
278
- let selectedHintsInfo = hintsInfo
279
- & sortBy (\ (Range (Position l1 c1) _, _) (Range (Position l2 c2) _, _) ->
280
- compare l1 l2 <> compare c1 c2)
281
- & groupBy (\ (Range (Position l1 _) _, _) (Range (Position l2 _) _, _) -> l1 == l2)
282
- & map Data.List.NonEmpty. head
283
- -- adding 1 because RealSrcLoc begins with 1
284
- & filter (\ (Range (Position l _) _, _) -> S. notMember (toInteger l + 1 ) packageImportLineNumbers)
285
- let inlayHints = [ generateInlayHint newRange txt
286
- | (range, txt) <- selectedHintsInfo
287
- , Just newRange <- [toCurrentRange pmap range]
288
- , isSubrangeOf newRange visibleRange]
261
+ let inlayHints = [ generateInlayHint newPos txt
262
+ | (pos, txt) <- packagePositions
263
+ , Just newPos <- [toCurrentPosition pmap pos]
264
+ , positionInRange newPos visibleRange]
289
265
pure $ InL inlayHints
290
266
-- When the client does not support inlay hints, do not display anything
291
267
else pure $ InL []
292
268
where
293
- generateInlayHint :: Range -> T. Text -> InlayHint
294
- generateInlayHint ( Range start _) txt =
295
- InlayHint { _position = start
269
+ generateInlayHint :: Position -> T. Text -> InlayHint
270
+ generateInlayHint pos txt =
271
+ InlayHint { _position = pos
296
272
, _label = InL txt
297
273
, _kind = Nothing
298
274
, _textEdits = Nothing
299
275
, _tooltip = Nothing
300
- , _paddingLeft = Nothing
301
- , _paddingRight = Just True
276
+ , _paddingLeft = Just True
277
+ , _paddingRight = Nothing
302
278
, _data_ = Nothing
303
279
}
304
280
305
- -- | Get inlay hints information for all imported packages
306
- getAllImportedPackagesHints :: HscEnv -> ModuleName -> HieAST a -> IO [(Range , T. Text )]
307
- getAllImportedPackagesHints env currentModuleName = go
308
- where
309
- go :: HieAST a -> IO [(Range , T. Text )]
310
- go ast = do
311
- let range = realSrcSpanToRange $ nodeSpan ast
312
- childrenResults <- traverse go (nodeChildren ast)
313
- mbPackage <- getImportedPackage ast
314
- return $ case mbPackage of
315
- Nothing -> mconcat childrenResults
316
- Just package -> (range, package) : mconcat childrenResults
317
-
318
- getImportedPackage :: HieAST a -> IO (Maybe T. Text )
319
- getImportedPackage ast = runMaybeT $ do
320
- nodeInfo <- MaybeT $ return $ sourceNodeInfo ast
321
- moduleName <- MaybeT $ return $
322
- nodeIdentifiers nodeInfo
323
- & Map. keys
324
- & lefts
325
- & listToMaybe
326
- filteredModuleName <- MaybeT $ return $
327
- guard (moduleName /= currentModuleName) >> Just moduleName
328
- txt <- MaybeT $ packageNameForModuleName filteredModuleName
329
- return $ " \" " <> txt <> " \" "
330
-
331
- packageNameForModuleName :: ModuleName -> IO (Maybe T. Text )
332
- packageNameForModuleName modName = runMaybeT $ do
333
- mod <- MaybeT $ findImportedModule env modName
334
- let pid = moduleUnit mod
335
- conf <- MaybeT $ return $ lookupUnit env pid
336
- return $ T. pack $ unitPackageNameString conf
281
+ packageNameForModuleName :: ModuleName -> HscEnv -> IO (Maybe T. Text )
282
+ packageNameForModuleName modName env = runMaybeT $ do
283
+ mod <- MaybeT $ findImportedModule env modName
284
+ let pid = moduleUnit mod
285
+ conf <- MaybeT $ return $ lookupUnit env pid
286
+ let packageName = T. pack $ unitPackageNameString conf
287
+ return $ " \" " <> packageName <> " \" "
288
+
289
+ getModuleNamePositions :: ParsedModule -> [(Position , ModuleName )]
290
+ getModuleNamePositions parsedModule =
291
+ let isPackageImport :: ImportDecl GhcPs -> Bool
292
+ isPackageImport ImportDecl {ideclPkgQual = NoRawPkgQual } = False
293
+ isPackageImport _ = True
294
+
295
+ (L _ hsImports) = hsmodImports <$> pm_parsed_source parsedModule
296
+
297
+ srcSpanToPosition :: SrcSpan -> Position
298
+ srcSpanToPosition srcSpan = (realSrcSpanToRange . realSrcSpan $ srcSpan) ^. L. end
299
+
300
+ annToPosition :: EpAnnImportDecl -> Position
301
+ annToPosition ann = case importDeclAnnQualified ann of
302
+ Just loc -> (srcSpanToPosition $ getHasLoc loc)
303
+ _ -> (srcSpanToPosition $ getHasLoc $ importDeclAnnImport ann)
304
+
305
+ in hsImports
306
+ & filter (\ (L _ importDecl) -> not $ isPackageImport importDecl)
307
+ & map (\ (L _ importDecl) ->
308
+ (annToPosition $ anns $ ideclAnn $ ideclExt importDecl, unLoc $ ideclName importDecl))
309
+
337
310
338
311
339
312
-- | For explicit imports: If there are any implicit imports, provide both one
0 commit comments