[waspls] implement goto definition for declarations (#1310)

This commit is contained in:
Craig McIlwrath 2023-07-18 08:16:26 -04:00 committed by GitHub
parent 2df423006c
commit 8b1d6a96ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 2 deletions

View File

@ -15,6 +15,7 @@ module Wasp.Analyzer.Parser.CST.Traverse
-- * Traversal operations
-- | See the section on composition functions on how to compose these.
top,
bottom,
down,
up,
@ -137,6 +138,9 @@ pipe ops = foldl' (>=>) Just ops
(&?) :: Maybe Traversal -> (Traversal -> Maybe Traversal) -> Maybe Traversal
t &? op = t >>= op
top :: Traversal -> Traversal
top t = maybe t top $ t & up
-- | Move down the tree to the deepest left-most leaf
bottom :: Traversal -> Traversal
bottom t = maybe t bottom $ t & down

View File

@ -4,24 +4,29 @@ module Wasp.LSP.GotoDefinition
where
import Control.Lens ((^.))
import Control.Monad (msum)
import Control.Monad.Log.Class (logM)
import Control.Monad.Reader.Class (asks)
import Data.Foldable (find)
import qualified Language.LSP.Types as LSP
import qualified Language.LSP.Types.Lens as LSP
import qualified StrongPath as SP
import qualified Wasp.Analyzer.Parser.CST as S
import Wasp.Analyzer.Parser.CST.Traverse (Traversal, fromSyntaxForest)
import qualified Wasp.Analyzer.Parser.CST.Traverse as T
import Wasp.Analyzer.Parser.SourceRegion (sourceSpanToRegion)
import qualified Wasp.Analyzer.Type as Type
import qualified Wasp.LSP.ExtImport.ExportsCache as ExtImport
import qualified Wasp.LSP.ExtImport.Syntax as ExtImport
import Wasp.LSP.ServerMonads (HandlerM)
import qualified Wasp.LSP.ServerState as State
import Wasp.LSP.Syntax (locationAtOffset, lspPositionToOffset)
import Wasp.LSP.Syntax (lexemeAt, locationAtOffset, lspPositionToOffset)
import qualified Wasp.LSP.TypeInference as Inference
import Wasp.LSP.Util (waspSourceRegionToLspRange)
import qualified Wasp.TypeScript.Inspect.Exports as TS
definitionProviders :: [String -> Traversal -> HandlerM [LSP.LocationLink]]
definitionProviders = [extImportDefinitionProvider]
definitionProviders = [declDefinitionProvider, extImportDefinitionProvider]
gotoDefinitionOfSymbolAtPosition :: LSP.Position -> HandlerM (LSP.List LSP.LocationLink)
gotoDefinitionOfSymbolAtPosition position = do
@ -37,6 +42,41 @@ gotoDefinitionOfSymbolAtPosition position = do
logM $ "Got definitions at " ++ show position ++ ": " ++ show definitionLocations
return $ LSP.List definitionLocations
-- | If the provided location is at a place where an identifier with 'Decl' type
-- is expected, returns a link to the definition of the relevant declaration
-- in the wasp file, if any.
declDefinitionProvider :: String -> Traversal -> HandlerM [LSP.LocationLink]
declDefinitionProvider src location =
case (T.kindAt location, Inference.inferTypeAtLocation src location) of
(S.Var, Just (Type.DeclType _)) -> findDeclDefinitionLink (lexemeAt src location)
(S.DeclName, _) -> findDeclDefinitionLink (lexemeAt src location)
_ -> return [] -- @location@ does not point to a identifier refering to a decl.
where
-- @findDeclDefinitionLink name@ finds the link to a declaration with the
-- given name, if it exists.
findDeclDefinitionLink :: String -> HandlerM [LSP.LocationLink]
findDeclDefinitionLink name =
case findDeclDefinition name of
Nothing -> return [] -- No definition for a decl with the given name.
Just definition -> do
let linkRange = waspSourceRegionToLspRange $ sourceSpanToRegion src $ T.spanAt location
let definitionRange = waspSourceRegionToLspRange $ sourceSpanToRegion src $ T.spanAt definition
asks (^. State.waspFileUri) >>= \case
Nothing -> return [] -- Can't find wasp file URI, so can't provide a link.
Just waspFileUri ->
return [link linkRange $ LSP.Location waspFileUri definitionRange]
-- @findDeclDefinition name@ looks for a declaration node named @name@ and
-- returns it.
findDeclDefinition :: String -> Maybe Traversal
findDeclDefinition name = search $ T.top location
where
search t = case T.kindAt t of
S.Decl -> case find ((== S.DeclName) . T.kindAt) (T.children t) of
Just nameLoc | lexemeAt src nameLoc == name -> Just t
_ -> Nothing
_ -> msum $ map search $ T.children t
-- | If the provided location is within an ExtImport syntax node, returns the
-- location in the JS/TS file of the symbol that the ExtImport points to, if
-- that symbol is defined and the JS/TS file is in the cached export lists.