Skip to content

Commit b773ab2

Browse files
committed
Add pretty link for source location to hover
1 parent 697b0f4 commit b773ab2

File tree

2 files changed

+59
-12
lines changed

2 files changed

+59
-12
lines changed

ghcide/src/Development/IDE/Spans/AtPoint.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import Development.IDE.Types.Shake (WithHieDb)
6969
import HieDb hiding (pointCommand,
7070
withHieDb)
7171
import System.Directory (doesFileExist)
72+
import Debug.Trace
7273

7374
-- | Gives a Uri for the module, given the .hie file location and the the module info
7475
-- The Bool denotes if it is a boot module
@@ -335,7 +336,7 @@ atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (D
335336
-- We want to render the root constraint even if it is a let,
336337
-- but we don't want to render any subsequent lets
337338
renderEvidenceTree :: Tree (EvidenceInfo a) -> SDoc
338-
-- However, if the root constraint is simply an indirection (via let) to a single other constraint,
339+
-- However, if the root constraint is simply a<n indirection (via let) to a single other constraint,
339340
-- we can still skip rendering it
340341
renderEvidenceTree (T.Node (EvidenceInfo{evidenceDetails=Just (EvLetBind _,_,_)}) [x])
341342
= renderEvidenceTree x
@@ -351,13 +352,15 @@ atPoint IdeOptions{} (HAR _ (hf :: HieASTs a) rf _ (kind :: HieKind hietype)) (D
351352
= vcat (map renderEvidenceTree' xs)
352353
renderEvidenceTree' (T.Node (EvidenceInfo{..}) _)
353354
= hang (text "- `" O.<> expandType evidenceType O.<> "`") 2 $
354-
vcat $ printDets evidenceSpan evidenceDetails : map (text . T.unpack) (maybeToList $ definedAt evidenceVar)
355+
vcat $
356+
printDets evidenceSpan evidenceDetails : map (text . T.unpack) (maybeToList $ definedAt evidenceVar)
355357

356358
printDets :: RealSrcSpan -> Maybe (EvVarSource, Scope, Maybe Span) -> SDoc
357359
printDets _ Nothing = text "using an external instance"
358360
printDets ospn (Just (src,_,mspn)) = pprSrc
359-
$$ text "at" <+> ppr spn
361+
$$ text "at" <+> text (T.unpack $ srcSpanToMdLink location)
360362
where
363+
location = realSrcSpanToLocation $ traceShowId spn
361364
-- Use the bind span if we have one, else use the occurrence span
362365
spn = fromMaybe ospn mspn
363366
pprSrc = case src of

ghcide/src/Development/IDE/Spans/Common.hs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,28 @@ module Development.IDE.Spans.Common (
1313
, spanDocToMarkdownForTest
1414
, DocMap
1515
, TyThingMap
16+
, srcSpanToMdLink
1617
) where
1718

1819
import Control.DeepSeq
20+
import Data.Bifunctor (second)
1921
import Data.List.Extra
2022
import Data.Maybe
21-
import qualified Data.Text as T
22-
import GHC.Generics
23-
23+
import qualified Data.Text as T
24+
import Development.IDE.GHC.Util
25+
import qualified Documentation.Haddock.Parser as H
26+
import qualified Documentation.Haddock.Types as H
2427
import GHC
28+
import GHC.Generics
29+
import System.FilePath
2530

26-
import Data.Bifunctor (second)
2731
import Development.IDE.GHC.Compat
28-
import Development.IDE.GHC.Orphans ()
29-
import Development.IDE.GHC.Util
30-
import qualified Documentation.Haddock.Parser as H
31-
import qualified Documentation.Haddock.Types as H
32+
import qualified Development.IDE.GHC.Compat.Util as Util
33+
import Development.IDE.GHC.Orphans ()
34+
import Language.LSP.Protocol.Types
35+
import qualified Language.LSP.Protocol.Lens as JL
36+
import Control.Lens
37+
import Language.LSP.Protocol.Lens (HasUri(uri))
3238

3339
type DocMap = NameEnv SpanDoc
3440
type TyThingMap = NameEnv TyThing
@@ -109,7 +115,13 @@ spanDocUrisToMarkdown (SpanDocUris mdoc msrc) = catMaybes
109115
[ linkify "Documentation" <$> mdoc
110116
, linkify "Source" <$> msrc
111117
]
112-
where linkify title uri = "[" <> title <> "](" <> uri <> ")"
118+
119+
-- | Generate a markdown link.
120+
--
121+
-- >>> linkify "Title" "uri"
122+
-- "[Title](Uri)"
123+
linkify :: T.Text -> T.Text -> T.Text
124+
linkify title uri = "[" <> title <> "](" <> uri <> ")"
113125

114126
spanDocToMarkdownForTest :: String -> String
115127
spanDocToMarkdownForTest
@@ -215,3 +227,35 @@ splitForList s
215227
= case lines s of
216228
[] -> ""
217229
(first:rest) -> unlines $ first : map ((" " ++) . trimStart) rest
230+
231+
-- | Generate a source link for the 'Location' according to VSCode's supported form:
232+
-- https://github.com/microsoft/vscode/blob/b3ec8181fc49f5462b5128f38e0723ae85e295c2/src/vs/platform/opener/common/opener.ts#L151-L160
233+
--
234+
srcSpanToMdLink :: Location -> T.Text
235+
srcSpanToMdLink location =
236+
let
237+
uri = location ^. JL.uri
238+
range = location ^. JL.range
239+
-- LSP 'Range' starts at '0', but link locations start at '1'.
240+
intText n = T.pack $ show (n + 1)
241+
srcRangeText =
242+
T.concat
243+
[ "L"
244+
, intText (range ^. JL.start . JL.line)
245+
, ","
246+
, intText (range ^. JL.start . JL.character)
247+
, "-L"
248+
, intText (range ^. JL.end . JL.line)
249+
, ","
250+
, intText (range ^. JL.end . JL.character)
251+
]
252+
253+
-- If the 'Location' is a 'FilePath', display it in shortened form.
254+
-- This avoids some redundancy and better readability for the user.
255+
title = case uriToFilePath uri of
256+
Just fp -> T.pack (takeFileName fp) <> ":" <> intText (range ^. JL.start . JL.line)
257+
Nothing -> getUri uri
258+
259+
srcLink = getUri uri <> "#" <> srcRangeText
260+
in
261+
linkify title srcLink

0 commit comments

Comments
 (0)