@@ -45,7 +45,6 @@ import Development.IDE.GHC.Util (printOutputable)
45
45
import Development.IDE.Spans.Common
46
46
import Development.IDE.Types.Options
47
47
48
- import Control.Applicative
49
48
import Control.Monad.Extra
50
49
import Control.Monad.IO.Class
51
50
import Control.Monad.Trans.Class
@@ -61,17 +60,25 @@ import Data.Either
61
60
import Data.List.Extra (dropEnd1 , nubOrd )
62
61
63
62
63
+ import Control.Lens ((^.) )
64
64
import Data.Either.Extra (eitherToMaybe )
65
65
import Data.List (isSuffixOf , sortOn )
66
+ import Data.Set (Set )
67
+ import qualified Data.Set as S
66
68
import Data.Tree
67
69
import qualified Data.Tree as T
68
70
import Data.Version (showVersion )
71
+ import Development.IDE.Core.LookupMod (LookupModule , lookupMod )
72
+ import Development.IDE.Core.Shake (ShakeExtras (.. ),
73
+ runIdeAction )
69
74
import Development.IDE.Types.Shake (WithHieDb )
70
75
import GHC.Iface.Ext.Types (EvVarSource (.. ),
71
76
HieAST (.. ),
72
77
HieASTs (.. ),
73
78
HieArgs (.. ),
74
- HieType (.. ), Identifier ,
79
+ HieType (.. ),
80
+ HieTypeFix (.. ),
81
+ Identifier ,
75
82
IdentifierDetails (.. ),
76
83
NodeInfo (.. ), Scope ,
77
84
Span )
@@ -86,12 +93,9 @@ import GHC.Iface.Ext.Utils (EvidenceInfo (..),
86
93
selectSmallestContaining )
87
94
import HieDb hiding (pointCommand ,
88
95
withHieDb )
96
+ import qualified Language.LSP.Protocol.Lens as L
89
97
import System.Directory (doesFileExist )
90
98
91
- -- | Gives a Uri for the module, given the .hie file location and the the module info
92
- -- The Bool denotes if it is a boot module
93
- type LookupModule m = FilePath -> ModuleName -> Unit -> Bool -> MaybeT m Uri
94
-
95
99
-- | HieFileResult for files of interest, along with the position mappings
96
100
newtype FOIReferences = FOIReferences (HM. HashMap NormalizedFilePath (HieAstResult , PositionMapping ))
97
101
@@ -251,31 +255,41 @@ gotoImplementation withHieDb getHieFile ideOpts srcSpans pos
251
255
-- | Synopsis for the name at a given position.
252
256
atPoint
253
257
:: IdeOptions
258
+ -> ShakeExtras
254
259
-> HieAstResult
255
260
-> DocAndTyThingMap
256
261
-> HscEnv
257
262
-> Position
258
263
-> IO (Maybe (Maybe Range , [T. Text ]))
259
- atPoint IdeOptions {} (HAR _ (hf :: HieASTs a ) rf _ (kind :: HieKind hietype )) (DKMap dm km _am) env pos =
264
+ atPoint opts @ IdeOptions {} shakeExtras @ ShakeExtras { withHieDb, hiedbWriter } har @ (HAR _ (hf :: HieASTs a ) rf _ (kind :: HieKind hietype )) (DKMap dm km _am) env pos =
260
265
listToMaybe <$> sequence (pointCommand hf pos hoverInfo)
261
266
where
262
267
-- Hover info for values/data
263
268
hoverInfo :: HieAST hietype -> IO (Maybe Range , [T. Text ])
264
269
hoverInfo ast = do
265
- prettyNames <- mapM prettyName names
266
- pure (Just range, prettyNames ++ pTypes)
270
+ locationsWithIdentifier <- runIdeAction " TypeCheck" shakeExtras $ do
271
+ runMaybeT $ gotoTypeDefinition withHieDb (lookupMod hiedbWriter) opts har pos
272
+
273
+ let locationsMap = M. fromList $ mapMaybe (\ (loc, identifier) -> case identifier of
274
+ Right typeName ->
275
+ -- Filter out type variables (polymorphic names like 'a', 'b', etc.)
276
+ if isTyVarName typeName
277
+ then Nothing
278
+ else Just (typeName, loc)
279
+ Left _moduleName -> Nothing ) $ fromMaybe [] locationsWithIdentifier
280
+
281
+ prettyNames <- mapM (prettyName locationsMap) names
282
+ pure (Just range, prettyNames ++ pTypes locationsMap)
267
283
where
268
- pTypes :: [T. Text ]
269
- pTypes
270
- | Prelude. length names == 1 = dropEnd1 $ map wrapHaskell prettyTypes
271
- | otherwise = map wrapHaskell prettyTypes
284
+ pTypes :: M. Map Name Location -> [T. Text ]
285
+ pTypes locationsMap =
286
+ case names of
287
+ [_singleName] -> dropEnd1 $ prettyTypes Nothing locationsMap
288
+ _ -> prettyTypes Nothing locationsMap
272
289
273
290
range :: Range
274
291
range = realSrcSpanToRange $ nodeSpan ast
275
292
276
- wrapHaskell :: T. Text -> T. Text
277
- wrapHaskell x = " \n ```haskell\n " <> x<> " \n ```\n "
278
-
279
293
info :: NodeInfo hietype
280
294
info = nodeInfoH kind ast
281
295
@@ -284,8 +298,8 @@ atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (D
284
298
names :: [(Identifier , IdentifierDetails hietype )]
285
299
names = sortOn (any isEvidenceUse . identInfo . snd ) $ M. assocs $ nodeIdentifiers info
286
300
287
- prettyName :: (Either ModuleName Name , IdentifierDetails hietype ) -> IO T. Text
288
- prettyName (Right n, dets)
301
+ prettyName :: M. Map Name Location -> (Either ModuleName Name , IdentifierDetails hietype ) -> IO T. Text
302
+ prettyName locationsMap (Right n, dets)
289
303
-- We want to print evidence variable using a readable tree structure.
290
304
-- Evidence variables contain information why a particular instance or
291
305
-- type equality was chosen, paired with location information.
@@ -299,20 +313,23 @@ atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (D
299
313
pure $ evidenceTree <> " \n "
300
314
-- Identifier details that are not evidence variables are used to display type information and
301
315
-- documentation of that name.
302
- | otherwise =
316
+ | otherwise = do
303
317
let
304
- typeSig = wrapHaskell (printOutputable n <> maybe " " (" :: " <> ) ((prettyType <$> identType dets) <|> maybeKind))
318
+ typeSig = case identType dets of
319
+ Just t -> prettyType (Just n) locationsMap t
320
+ Nothing -> case safeTyThingType =<< lookupNameEnv km n of
321
+ Just kind -> prettyTypeFromType (Just n) locationsMap kind
322
+ Nothing -> wrapHaskell (printOutputable n)
305
323
definitionLoc = maybeToList (pretty (definedAt n) (prettyPackageName n))
306
324
docs = maybeToList (T. unlines . spanDocToMarkdown <$> lookupNameEnv dm n)
307
- in
308
- pure $ T. unlines $
309
- [typeSig] ++ definitionLoc ++ docs
310
- where maybeKind = fmap printOutputable $ safeTyThingType =<< lookupNameEnv km n
325
+
326
+ pure $ T. unlines $ [typeSig] ++ definitionLoc ++ docs
327
+ where
311
328
pretty Nothing Nothing = Nothing
312
329
pretty (Just define) Nothing = Just $ define <> " \n "
313
330
pretty Nothing (Just pkgName) = Just $ pkgName <> " \n "
314
331
pretty (Just define) (Just pkgName) = Just $ define <> " " <> pkgName <> " \n "
315
- prettyName (Left m,_) = packageNameForImportStatement m
332
+ prettyName _locationsMap (Left m,_) = packageNameForImportStatement m
316
333
317
334
prettyPackageName :: Name -> Maybe T. Text
318
335
prettyPackageName n = do
@@ -345,11 +362,63 @@ atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (D
345
362
types :: [hietype ]
346
363
types = nodeType info
347
364
348
- prettyTypes :: [T. Text ]
349
- prettyTypes = map ((" _ :: " <> ) . prettyType) types
365
+ prettyTypes :: Maybe Name -> M. Map Name Location -> [T. Text ]
366
+ prettyTypes boundNameMay locationsMap =
367
+ map (prettyType boundNameMay locationsMap) types
368
+
369
+ prettyTypeFromType :: Maybe Name -> M. Map Name Location -> Type -> T. Text
370
+ prettyTypeFromType boundNameMay locationsMap ty =
371
+ prettyTypeCommon boundNameMay locationsMap (S. fromList $ namesInType ty) (printOutputable ty)
372
+
373
+ prettyType :: Maybe Name -> M. Map Name Location -> hietype -> T. Text
374
+ prettyType boundNameMay locationsMap t =
375
+ prettyTypeCommon boundNameMay locationsMap (typeNames t) (printOutputable . expandType $ t)
376
+
377
+ prettyTypeCommon :: Maybe Name -> M. Map Name Location -> Set Name -> T. Text -> T. Text
378
+ prettyTypeCommon boundNameMay locationsMap names expandedType =
379
+ let nameToUse = case boundNameMay of
380
+ Just n -> printOutputable n
381
+ Nothing -> " _"
382
+ expandedWithName = nameToUse <> " :: " <> expandedType
383
+ codeBlock = wrapHaskell expandedWithName
384
+ links = case boundNameMay of
385
+ Just _ -> generateLinksList locationsMap names
386
+ -- This is so we don't get flooded with links, e.g:
387
+ -- foo :: forall a. MyType a -> a
388
+ -- Go to MyType
389
+ -- _ :: forall a. MyType a -> a
390
+ -- Go to MyType -- <- we don't want this as it's already present
391
+ Nothing -> " "
392
+ in codeBlock <> links
393
+
394
+ generateLinksList :: M. Map Name Location -> Set Name -> T. Text
395
+ generateLinksList locationsMap (S. toList -> names) =
396
+ if null generated
397
+ then " "
398
+ else " \n " <> " Go to " <> T. intercalate " | " generated <> " \n "
399
+ where
400
+ generated = mapMaybe generateLink names
350
401
351
- prettyType :: hietype -> T. Text
352
- prettyType = printOutputable . expandType
402
+ generateLink name = do
403
+ case M. lookup name locationsMap of
404
+ Just (Location uri range) ->
405
+ let nameText = printOutputable name
406
+ link = " [" <> nameText <> " ](" <> getUriText uri <> " #L" <>
407
+ T. pack (show (range ^. L. start . L. line + 1 )) <> " )"
408
+ in Just link
409
+ Nothing -> Nothing
410
+
411
+ wrapHaskell :: T. Text -> T. Text
412
+ wrapHaskell x = " \n ```haskell\n " <> x<> " \n ```\n "
413
+
414
+ getUriText :: Uri -> T. Text
415
+ getUriText (Uri t) = t
416
+
417
+ typeNames :: a -> Set Name
418
+ typeNames t = S. fromList $ case kind of
419
+ HieFresh -> namesInType t
420
+ HieFromDisk full_file -> do
421
+ namesInHieTypeFix $ recoverFullType t (hie_types full_file)
353
422
354
423
expandType :: a -> SDoc
355
424
expandType t = case kind of
@@ -468,9 +537,24 @@ namesInType (CastTy t _) = namesInType t
468
537
namesInType (LitTy _) = []
469
538
namesInType _ = []
470
539
540
+
471
541
getTypes :: [Type ] -> [Name ]
472
542
getTypes = concatMap namesInType
473
543
544
+ namesInHieTypeFix :: HieTypeFix -> [Name ]
545
+ namesInHieTypeFix (Roll hieType) = namesInHieType hieType
546
+
547
+ namesInHieType :: HieType HieTypeFix -> [Name ]
548
+ namesInHieType (HTyVarTy n) = [n]
549
+ namesInHieType (HAppTy a (HieArgs args)) = namesInHieTypeFix a ++ concatMap (namesInHieTypeFix . snd ) args
550
+ namesInHieType (HTyConApp tc (HieArgs args)) = ifaceTyConName tc : concatMap (namesInHieTypeFix . snd ) args
551
+ namesInHieType (HForAllTy ((binder, constraint), _) body) = binder : namesInHieTypeFix constraint ++ namesInHieTypeFix body
552
+ namesInHieType (HFunTy mult arg res) = namesInHieTypeFix mult ++ namesInHieTypeFix arg ++ namesInHieTypeFix res
553
+ namesInHieType (HQualTy constraint body) = namesInHieTypeFix constraint ++ namesInHieTypeFix body
554
+ namesInHieType (HLitTy _) = []
555
+ namesInHieType (HCastTy a) = namesInHieTypeFix a
556
+ namesInHieType HCoercionTy = []
557
+
474
558
-- | Find 'Location's of definition at a specific point and return them along with their 'Identifier's.
475
559
locationsAtPoint
476
560
:: forall m
0 commit comments