@@ -17,6 +17,7 @@ module Ide.Plugin.ExplicitImports
1717
1818import            Control.DeepSeq 
1919import            Control.Lens                          (_Just , (&) , (?~) , (^?) )
20+ import            Control.Monad                         (guard )
2021import            Control.Monad.Error.Class             (MonadError  (throwError ))
2122import            Control.Monad.IO.Class 
2223import            Control.Monad.Trans.Class             (lift )
@@ -25,14 +26,15 @@ import           Control.Monad.Trans.Maybe
2526import  qualified  Data.Aeson                            as  A  (ToJSON  (toJSON ))
2627import            Data.Aeson.Types                      (FromJSON )
2728import            Data.Char                             (isSpace )
29+ import            Data.Either                           (lefts )
2830import            Data.Functor                          ((<&>) )
2931import  qualified  Data.IntMap                           as  IM  (IntMap , elems ,
3032                                                             fromList , (!?) )
3133import            Data.IORef                            (readIORef )
3234import            Data.List                             (singleton )
3335import  qualified  Data.Map.Strict                       as  Map 
3436import            Data.Maybe                            (isJust , isNothing ,
35-                                                        mapMaybe )
37+                                                        mapMaybe ,  listToMaybe )
3638import  qualified  Data.Set                              as  S 
3739import            Data.String                           (fromString )
3840import  qualified  Data.Text                             as  T 
@@ -46,6 +48,7 @@ import           Development.IDE.Core.PluginUtils
4648import            Development.IDE.Core.PositionMapping 
4749import  qualified  Development.IDE.Core.Shake            as  Shake 
4850import            Development.IDE.GHC.Compat            hiding  ((<+>) )
51+ import            Development.IDE.GHC.Compat.Util       (mkFastString )
4952import            Development.IDE.Graph.Classes 
5053import            GHC.Generics                          (Generic )
5154import            Ide.Plugin.Error                      (PluginError  (.. ),
@@ -109,6 +112,7 @@ descriptorForModules recorder modFilter plId =
109112        <>  mkResolveHandler SMethod_CodeLensResolve  (lensResolveProvider recorder)
110113        --  This plugin provides inlay hints
111114        <>  mkPluginHandler SMethod_TextDocumentInlayHint  (inlayHintProvider recorder)
115+         <>  mkPluginHandler SMethod_TextDocumentInlayHint  (importPackageInlayHintProvider recorder)
112116        --  This plugin provides code actions
113117        <>  codeActionHandlers
114118    }
@@ -234,6 +238,73 @@ inlayHintProvider _ state _ InlayHintParams {_textDocument = TextDocumentIdentif
234238          title RefineImport    =  Nothing  --  does not provide imports statements that can be refined via inlay hints
235239      in  title ieResType
236240
241+ --  |  Provide inlay hints that show which package a module is imported from. 
242+ importPackageInlayHintProvider  ::  Recorder  (WithPriority  Log ) ->  PluginMethodHandler  IdeState  'Method_TextDocumentInlayHint
243+ importPackageInlayHintProvider _ state _ InlayHintParams  {_textDocument =  TextDocumentIdentifier  {_uri}, _range =  visibleRange} = 
244+     if  isInlayHintsSupported state
245+     then  do 
246+         nfp <-  getNormalizedFilePathE _uri
247+         (hscEnvEq, _) <-  runActionE " ImportPackageInlayHint.GhcSessionDeps" $  useWithStaleE GhcSessionDeps  nfp
248+         (HAR  {hieAst, hieModule}, pmap) <-  runActionE " ImportPackageInlayHint.GetHieAst" $  useWithStaleE GetHieAst  nfp
249+         ast <-  handleMaybe
250+                   (PluginRuleFailed  " GetHieAst" 
251+                   (getAsts hieAst Map. !?HiePath  .  mkFastString .  fromNormalizedFilePath) nfp)
252+         hintsInfo <-  liftIO $  getAllImportedPackagesHints (hscEnv hscEnvEq) (moduleName hieModule) ast
253+         --  Filter out empty package names
254+         let  selectedHintsInfo =  hintsInfo &  filter  (\ (_, mbPkg) ->  (not  .  T. null ) mbPkg)
255+         let  inlayHints =  [ generateInlayHint newRange txt
256+                          |  (range, txt) <-  selectedHintsInfo
257+                          , Just  newRange <-  [toCurrentRange pmap range]
258+                          , isSubrangeOf newRange visibleRange]
259+         pure  $  InL  inlayHints
260+     --  When the client does not support inlay hints, do not display anything
261+     else  pure  $  InL  [] 
262+   where 
263+     generateInlayHint  ::  Range  ->  T. Text->  InlayHint 
264+     generateInlayHint (Range  start _) txt = 
265+       InlayHint  { _position =  start
266+                 , _label =  InL  txt
267+                 , _kind =  Nothing 
268+                 , _textEdits =  Nothing 
269+                 , _tooltip =  Nothing 
270+                 , _paddingLeft =  Nothing 
271+                 , _paddingRight =  Just  True 
272+                 , _data_ =  Nothing 
273+                 }
274+ 
275+     --  |  Get inlay hints information for all imported packages 
276+     getAllImportedPackagesHints  ::  HscEnv  ->  ModuleName  ->  HieAST  a  ->  IO Range , T. Text
277+     getAllImportedPackagesHints env currentModuleName =  go
278+       where 
279+         go  ::  HieAST  a  ->  IO Range , T. Text
280+         go ast =  do 
281+           let  range =  realSrcSpanToRange $  nodeSpan ast
282+           childrenResults <-  traverse  go (nodeChildren ast)
283+           mbPackage <-  getImportedPackage ast
284+           return  $  case  mbPackage of 
285+             Nothing  ->  mconcat  childrenResults
286+             Just  package ->  (range, package) :  mconcat  childrenResults
287+ 
288+         getImportedPackage  ::  HieAST  a  ->  IO Maybe T. Text
289+         getImportedPackage ast =  runMaybeT $  do 
290+           nodeInfo <-  MaybeT  $  return  $  sourceNodeInfo ast
291+           moduleName <-  MaybeT  $  return  $ 
292+                             nodeIdentifiers nodeInfo
293+                                 &  Map. keys
294+                                 &  lefts
295+                                 &  listToMaybe
296+           filteredModuleName <-  MaybeT  $  return  $ 
297+                                   guard (moduleName /=  currentModuleName) >>  Just  moduleName
298+           txt <-  MaybeT  $  packageNameForModuleName filteredModuleName
299+           return  $  " \" " <>  txt <>  " \" " 
300+ 
301+         packageNameForModuleName  ::  ModuleName  ->  IO Maybe T. Text
302+         packageNameForModuleName modName =  runMaybeT $  do 
303+             mod  <-  MaybeT  $  findImportedModule env modName
304+             let  pid =  moduleUnit mod 
305+             conf <-  MaybeT  $  return  $  lookupUnit env pid
306+             return  $  T. pack $  unitPackageNameString conf
307+ 
237308
238309--  | For explicit imports: If there are any implicit imports, provide both one 
239310--  code action per import to make that specific import explicit, and one code 
0 commit comments