Skip to content

Commit 22787ff

Browse files
committed
Implement GoToDefinition
1 parent 8334f2c commit 22787ff

File tree

7 files changed

+86
-13
lines changed

7 files changed

+86
-13
lines changed

unison-cli/src/Unison/LSP.hs

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import Unison.LSP.Configuration qualified as Config
4040
import Unison.LSP.FileAnalysis qualified as Analysis
4141
import Unison.LSP.FoldingRange (foldingRangeRequest)
4242
import Unison.LSP.Formatting (formatDocRequest, formatRangeRequest)
43+
import Unison.LSP.GoToDefinition (goToDeclarationHandler, goToDefinitionHandler, goToImplementationHandler)
4344
import Unison.LSP.HandlerUtils qualified as Handlers
4445
import Unison.LSP.Hover (hoverHandler)
4546
import Unison.LSP.NotificationHandlers qualified as Notifications
@@ -181,6 +182,9 @@ lspRequestHandlers lspFormattingConfig =
181182
& SMM.insert Msg.SMethod_TextDocumentFoldingRange (mkHandler foldingRangeRequest)
182183
& SMM.insert Msg.SMethod_TextDocumentCompletion (mkHandler completionHandler)
183184
& SMM.insert Msg.SMethod_CompletionItemResolve (mkHandler completionItemResolveHandler)
185+
& SMM.insert Msg.SMethod_TextDocumentDeclaration (mkHandler goToDeclarationHandler)
186+
& SMM.insert Msg.SMethod_TextDocumentDefinition (mkHandler goToDefinitionHandler)
187+
& SMM.insert Msg.SMethod_TextDocumentImplementation (mkHandler goToImplementationHandler)
184188
& addFormattingHandlers
185189
where
186190
addFormattingHandlers handlers =

unison-cli/src/Unison/LSP/Conversions.hs

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ rangeToInterval :: Range -> Interval.Interval Position
1313
rangeToInterval (Range start end) =
1414
Interval.ClosedInterval start end
1515

16+
intervalToRange :: Interval.Interval Position -> Range
17+
intervalToRange = \case
18+
(Interval.ClosedInterval start end) -> Range start end
19+
(Interval.OpenInterval start end) -> Range start end
20+
(Interval.IntervalCO start end) -> Range start end
21+
(Interval.IntervalOC start end) -> Range start end
22+
1623
annToInterval :: Ann -> Maybe (Interval.Interval Position)
1724
annToInterval ann = annToRange ann <&> rangeToInterval
1825

unison-cli/src/Unison/LSP/FileAnalysis.hs

+14-10
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ checkFileContents fileUri sourceName fileVersion contents = do
114114
maybeNamespace = Nothing,
115115
localNamespacePrefixedTypesAndConstructors = mempty
116116
}
117-
(localBindingTypes, notes, parsedFile, typecheckedFile) <- do
117+
(localBindingInfo, notes, parsedFile, typecheckedFile) <- do
118118
liftIO do
119119
Codebase.runTransaction cb do
120120
parseResult <- Parsers.parseFile (Text.unpack sourceName) (Text.unpack srcText) parsingEnv
@@ -124,29 +124,33 @@ checkFileContents fileUri sourceName fileVersion contents = do
124124
typecheckingEnv <- computeTypecheckingEnvironment (ShouldUseTndr'Yes parsingEnv) cb ambientAbilities parsedFile
125125
let Result.Result typecheckingNotes maybeTypecheckedFile = FileParsers.synthesizeFile typecheckingEnv parsedFile
126126

127-
symbolTypes <-
127+
symbolInfo <-
128128
typecheckingNotes
129129
& Foldable.toList
130130
& reverse -- Type notes that come later in typechecking have more information filled in.
131131
& foldMap \case
132-
Result.TypeInfo (Context.VarBinding v _loc typ) -> Map.singleton v typ
132+
Result.TypeInfo (Context.VarBinding v loc typ) ->
133+
annToRange loc
134+
& foldMap \definitionSite -> Map.singleton v (typ, definitionSite)
133135
_ -> mempty
134136
& pure
135137

136-
let localBindings :: (IntervalMap Position (Context.Type Symbol Ann)) =
138+
let localBindingInfo :: (IntervalMap Position (Context.Type Symbol Ann, Range)) =
137139
typecheckingNotes
138140
& Foldable.toList
139141
& reverse -- Type notes that come later in typechecking have more information filled in.
140142
& foldMap \case
141143
Result.TypeInfo (Context.VarBinding _v loc typ) -> do
142-
((annToInterval loc) & foldMap \interval -> (IM.singleton interval typ))
144+
( (liftA2 (,) (annToInterval loc) (annToRange loc))
145+
& foldMap \(interval, definitionSite) -> (IM.singleton interval (typ, definitionSite))
146+
)
143147
Result.TypeInfo (Context.VarMention v loc) -> do
144-
case Map.lookup v symbolTypes of
145-
Just typ ->
146-
((annToInterval loc) & foldMap \interval -> (IM.singleton interval typ))
148+
case Map.lookup v symbolInfo of
149+
Just (typ, definitionSite) ->
150+
((annToInterval loc) & foldMap \interval -> (IM.singleton interval (typ, definitionSite)))
147151
_ -> mempty
148152
_ -> mempty
149-
pure (localBindings, typecheckingNotes, Just parsedFile, maybeTypecheckedFile)
153+
pure (localBindingInfo, typecheckingNotes, Just parsedFile, maybeTypecheckedFile)
150154

151155
filePPED <- ppedForFileHelper parsedFile typecheckedFile
152156
(errDiagnostics, codeActions) <- analyseFile fileUri srcText filePPED notes
@@ -178,7 +182,7 @@ checkFileContents fileUri sourceName fileVersion contents = do
178182
parsedFile,
179183
typecheckedFile,
180184
notes,
181-
localBindingTypes
185+
localBindingInfo
182186
}
183187
pure fileAnalysis
184188

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
-- | goToDeclaration, goToDefinition, and goToImplementation are equivalent except for the input/return wrappers
2+
module Unison.LSP.GoToDefinition
3+
( goToDefinitionHandler,
4+
goToDeclarationHandler,
5+
goToImplementationHandler,
6+
)
7+
where
8+
9+
import Control.Lens hiding (List)
10+
import Data.IntervalMap.Lazy qualified as IM
11+
import Language.LSP.Protocol.Lens
12+
import Language.LSP.Protocol.Message qualified as Msg
13+
import Language.LSP.Protocol.Types
14+
import Unison.LSP.FileAnalysis qualified as FileAnalysis
15+
import Unison.LSP.Types
16+
import Unison.Prelude
17+
18+
-- | Go to Definition handler
19+
goToDefinitionHandler :: Msg.TRequestMessage 'Msg.Method_TextDocumentDefinition -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentDefinition) -> Lsp ()) -> Lsp ()
20+
goToDefinitionHandler m respond = do
21+
respond . Right . maybe (InR . InL $ []) (InR . InL) =<< runMaybeT do
22+
let pos = (m ^. params . position)
23+
targetRange <- locationInfo (m ^. params . textDocument . uri) pos
24+
let originLoc = Nothing -- Just use default
25+
let targetUri = m ^. params . textDocument . uri
26+
pure $
27+
[DefinitionLink (LocationLink originLoc targetUri targetRange targetRange)]
28+
29+
-- | Go to Declaration handler
30+
goToDeclarationHandler :: Msg.TRequestMessage 'Msg.Method_TextDocumentDeclaration -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentDeclaration) -> Lsp ()) -> Lsp ()
31+
goToDeclarationHandler m respond = do
32+
respond . Right . maybe (InR . InL $ []) (InR . InL) =<< runMaybeT do
33+
let pos = (m ^. params . position)
34+
targetRange <- locationInfo (m ^. params . textDocument . uri) pos
35+
let originLoc = Nothing -- Just use default
36+
let targetUri = m ^. params . textDocument . uri
37+
pure $
38+
[DeclarationLink (LocationLink originLoc targetUri targetRange targetRange)]
39+
40+
goToImplementationHandler :: Msg.TRequestMessage 'Msg.Method_TextDocumentImplementation -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentImplementation) -> Lsp ()) -> Lsp ()
41+
goToImplementationHandler m respond = do
42+
respond . Right . maybe (InR . InL $ []) (InR . InL) =<< runMaybeT do
43+
let pos = (m ^. params . position)
44+
targetRange <- locationInfo (m ^. params . textDocument . uri) pos
45+
let originLoc = Nothing -- Just use default
46+
let targetUri = m ^. params . textDocument . uri
47+
pure $
48+
[DefinitionLink (LocationLink originLoc targetUri targetRange targetRange)]
49+
50+
locationInfo :: Uri -> Position -> MaybeT Lsp Range
51+
locationInfo uri pos = do
52+
FileAnalysis {localBindingInfo} <- FileAnalysis.getFileAnalysis uri
53+
(_interval, (_typ, range)) <- hoistMaybe $ IM.lookupMin $ IM.intersecting localBindingInfo (IM.ClosedInterval pos pos)
54+
pure range
55+
where
56+
hoistMaybe :: Maybe a -> MaybeT Lsp a
57+
hoistMaybe = MaybeT . pure

unison-cli/src/Unison/LSP/Hover.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ hoverInfo uri pos =
130130
(Term.Var' v) -> pure v
131131
(ABT.Abs'' v _body) -> pure v
132132
_ -> empty
133-
FileAnalysis {localBindingTypes} <- FileAnalysis.getFileAnalysis uri
134-
(_range, typ) <- hoistMaybe $ IM.lookupMin $ IM.intersecting localBindingTypes (IM.ClosedInterval pos pos)
133+
FileAnalysis {localBindingInfo} <- FileAnalysis.getFileAnalysis uri
134+
(_range, (typ, _definitionSite)) <- hoistMaybe $ IM.lookupMin $ IM.intersecting localBindingInfo (IM.ClosedInterval pos pos)
135135

136136
pped <- lift $ ppedForFile uri
137137
let varName = case localVar of

unison-cli/src/Unison/LSP/Types.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ data FileAnalysis = FileAnalysis
131131
diagnostics :: IntervalMap Position [Diagnostic],
132132
codeActions :: IntervalMap Position [CodeAction],
133133
-- | The types of local variable bindings keyed by the mention's location.
134-
localBindingTypes :: IntervalMap Position (Context.Type Symbol Ann),
134+
localBindingInfo :: IntervalMap Position (Context.Type Symbol Ann {- type of binding -}, Range {- binding definition site -}),
135135
typeSignatureHints :: Map Symbol TypeSignatureHint,
136136
fileSummary :: Maybe FileSummary
137137
}

unison-cli/unison-cli.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ library
140140
Unison.LSP.FileAnalysis.UnusedBindings
141141
Unison.LSP.FoldingRange
142142
Unison.LSP.Formatting
143+
Unison.LSP.GoToDefinition
143144
Unison.LSP.HandlerUtils
144145
Unison.LSP.Hover
145146
Unison.LSP.NotificationHandlers

0 commit comments

Comments
 (0)