Skip to content

Commit 238a1c7

Browse files
committed
preliminary document symbol handler
1 parent 9da03a8 commit 238a1c7

File tree

6 files changed

+111
-4
lines changed

6 files changed

+111
-4
lines changed

agda-language-server.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ library
7878
Server
7979
Server.CommandController
8080
Server.Handler
81+
Server.Handler.TextDocument.DocumentSymbol
8182
Server.Model
8283
Server.Model.AgdaFile
8384
Server.Model.AgdaLib
@@ -221,6 +222,7 @@ test-suite als-test
221222
Server
222223
Server.CommandController
223224
Server.Handler
225+
Server.Handler.TextDocument.DocumentSymbol
224226
Server.Model
225227
Server.Model.AgdaFile
226228
Server.Model.AgdaLib

src/Indexer/Monad.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ tellSymbolInfo nameLike symbolKindLike typeLike = do
127127
symbolKind = toSymbolKind symbolKindLike
128128
type' <- lift $ toTypeString typeLike
129129
parent <- asks envParent
130-
let symbolInfo = SymbolInfo symbolKind type' parent
130+
let symbolInfo = SymbolInfo name symbolKind type' parent
131131
tellSymbolInfo' name symbolInfo
132132

133133
tellRef' :: A.AmbiguousQName -> Ref -> IndexerM ()

src/Server.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import Options
2828
import qualified Server.Handler as Handler
2929
import Switchboard (Switchboard, agdaCustomMethod)
3030
import qualified Switchboard
31+
import Server.Handler.TextDocument.DocumentSymbol (documentSymbolHandler)
3132

3233
#if defined(wasm32_HOST_ARCH)
3334
import Agda.Utils.IO (catchIO)
@@ -117,6 +118,7 @@ handlers =
117118
let TRequestMessage _ _ _ (HoverParams (TextDocumentIdentifier uri) pos _workDone) = req
118119
result <- Handler.onHover uri pos
119120
responder $ Right result,
121+
documentSymbolHandler,
120122
-- -- syntax highlighting
121123
-- , requestHandler STextDocumentSemanticTokensFull $ \req responder -> do
122124
-- result <- Handler.onHighlight (req ^. (params . textDocument . uri))
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module Server.Handler.TextDocument.DocumentSymbol (documentSymbolHandler) where
2+
3+
import qualified Agda.Syntax.Abstract as A
4+
import Agda.Syntax.Common.Pretty (prettyShow)
5+
import Agda.Utils.Maybe (fromMaybe, mapMaybe)
6+
import Control.Monad (forM)
7+
import Control.Monad.Trans (lift)
8+
import Data.Map (Map)
9+
import qualified Data.Map as Map
10+
import qualified Data.Text as Text
11+
import qualified Language.LSP.Protocol.Message as LSP
12+
import qualified Language.LSP.Protocol.Types as LSP
13+
import qualified Language.LSP.Server as LSP
14+
import Monad (ServerM)
15+
import Server.Model.AgdaFile (AgdaFile, agdaFileSymbols, defNameRange, symbolByName, symbolsByParent)
16+
import Server.Model.Monad (MonadAgdaFile (askAgdaFile), useAgdaFile, withAgdaFile)
17+
import Server.Model.Symbol (SymbolInfo (symbolName), lspSymbolKind, symbolShortName, symbolType)
18+
19+
documentSymbolHandler :: LSP.Handlers ServerM
20+
documentSymbolHandler = withAgdaFile LSP.SMethod_TextDocumentDocumentSymbol $ \req responder -> do
21+
file <- askAgdaFile
22+
let symbols = symbolsByParent file
23+
let topLevelNames = fromMaybe [] $ Map.lookup Nothing symbols
24+
let topLevelSymbols = mapMaybe (symbolByName file) topLevelNames
25+
topLevelDocumentSymbols <- lift $ forM topLevelSymbols $ symbolToDocumentSymbol file symbols
26+
responder $ Right $ LSP.InR $ LSP.InL topLevelDocumentSymbols
27+
28+
symbolToDocumentSymbol :: AgdaFile -> Map (Maybe A.QName) [A.QName] -> SymbolInfo -> ServerM LSP.DocumentSymbol
29+
symbolToDocumentSymbol file symbolsByParent symbol = do
30+
let name = symbolName symbol
31+
let range = defNameRange file name
32+
let childrenNames = fromMaybe [] $ Map.lookup (Just name) symbolsByParent
33+
let childrenSymbols = mapMaybe (symbolByName file) childrenNames
34+
childrenDocumentSymbols <-
35+
forM childrenSymbols $
36+
symbolToDocumentSymbol file symbolsByParent
37+
return $
38+
LSP.DocumentSymbol
39+
(symbolShortName symbol)
40+
(Text.pack <$> symbolType symbol)
41+
(lspSymbolKind symbol)
42+
Nothing
43+
Nothing
44+
range
45+
range
46+
(Just childrenDocumentSymbols)

src/Server/Model/AgdaFile.hs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@ module Server.Model.AgdaFile
66
insertSymbolInfo,
77
insertRef,
88
mergeSymbols,
9+
symbolByName,
10+
symbolsByParent,
11+
defNameRange,
912
)
1013
where
1114

15+
import Agda.Position (toLspRange)
1216
import qualified Agda.Syntax.Abstract as A
1317
import Agda.Syntax.Common.Pretty (Pretty, pretty, prettyAssign, prettyMap, text, vcat)
18+
import Agda.Syntax.Position (getRange)
1419
import Agda.Utils.Lens (Lens', over, (<&>), (^.))
20+
import Data.Foldable (find)
1521
import Data.Function ((&))
1622
import Data.Map (Map)
1723
import qualified Data.Map as Map
1824
import Data.Monoid (Endo (Endo, appEndo))
19-
import Server.Model.Symbol (Ref, SymbolInfo)
25+
import qualified Language.LSP.Protocol.Types as LSP
26+
import Server.Model.Symbol (Ref, SymbolInfo, refIsDef, refRange, symbolParent)
2027

2128
data AgdaFile = AgdaFile
2229
{ _agdaFileSymbols :: !(Map A.QName SymbolInfo),
@@ -70,3 +77,19 @@ mergeSymbols old new file =
7077
Map.updateLookupWithKey (\_ _ -> Nothing) old refs
7178
in Map.alter (<> oldRefs) new refs'
7279
)
80+
81+
symbolByName :: AgdaFile -> A.QName -> Maybe SymbolInfo
82+
symbolByName agdaFile symbolName = Map.lookup symbolName $ agdaFile ^. agdaFileSymbols
83+
84+
symbolsByParent :: AgdaFile -> Map (Maybe A.QName) [A.QName]
85+
symbolsByParent agdaFile =
86+
let symbols = Map.toList $ agdaFile ^. agdaFileSymbols
87+
in Map.fromListWith (++) $ (\(symbolName, symbol) -> (symbolParent symbol, [symbolName])) <$> symbols
88+
89+
refsByName :: AgdaFile -> A.QName -> [Ref]
90+
refsByName agdaFile name = Map.findWithDefault [] name $ agdaFile ^. agdaFileRefs
91+
92+
defNameRange :: AgdaFile -> A.QName -> LSP.Range
93+
defNameRange agdaFile name =
94+
let defs = find refIsDef $ refsByName agdaFile name
95+
in maybe (toLspRange $ getRange name) refRange defs

src/Server/Model/Symbol.hs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
module Server.Model.Symbol
22
( SymbolKind (..),
33
SymbolInfo (..),
4+
symbolShortName,
5+
lspSymbolKind,
46
RefKind (..),
57
Ref (..),
8+
refIsDef,
69
)
710
where
811

912
import qualified Agda.Syntax.Abstract as A
10-
import Agda.Syntax.Common.Pretty (Doc, Pretty, comma, parensNonEmpty, pretty, pshow, text, (<+>))
13+
import Agda.Syntax.Common.Pretty (Doc, Pretty, comma, parensNonEmpty, pretty, prettyShow, pshow, text, (<+>))
1114
import Control.Applicative ((<|>))
15+
import Data.Text (Text)
16+
import qualified Data.Text as Text
1217
import qualified Language.LSP.Protocol.Types as LSP
1318
import Language.LSP.Protocol.Types.More ()
1419

@@ -37,8 +42,27 @@ instance Semigroup SymbolKind where
3742
Unknown <> k = k
3843
k <> _k = k
3944

45+
toLspSymbolKind :: SymbolKind -> LSP.SymbolKind
46+
toLspSymbolKind = \case
47+
Con -> LSP.SymbolKind_Constructor
48+
CoCon -> LSP.SymbolKind_Constructor
49+
Field -> LSP.SymbolKind_Field
50+
PatternSyn -> LSP.SymbolKind_Function
51+
GeneralizeVar -> LSP.SymbolKind_Variable
52+
Macro -> LSP.SymbolKind_Function
53+
Data -> LSP.SymbolKind_Enum
54+
Record -> LSP.SymbolKind_Struct
55+
Fun -> LSP.SymbolKind_Function
56+
Axiom -> LSP.SymbolKind_Constant
57+
Prim -> LSP.SymbolKind_Constant
58+
Module -> LSP.SymbolKind_Module
59+
Param -> LSP.SymbolKind_Variable
60+
Local -> LSP.SymbolKind_Variable
61+
Unknown -> LSP.SymbolKind_Variable
62+
4063
data SymbolInfo = SymbolInfo
41-
{ symbolKind :: !SymbolKind,
64+
{ symbolName :: !A.QName,
65+
symbolKind :: !SymbolKind,
4266
symbolType :: !(Maybe String),
4367
symbolParent :: !(Maybe A.QName)
4468
}
@@ -51,10 +75,17 @@ instance Pretty SymbolInfo where
5175
instance Semigroup SymbolInfo where
5276
new <> old =
5377
SymbolInfo
78+
(symbolName new)
5479
(symbolKind old <> symbolKind new)
5580
(symbolType old <|> symbolType new)
5681
(symbolParent old <|> symbolParent new)
5782

83+
symbolShortName :: SymbolInfo -> Text
84+
symbolShortName = Text.pack . prettyShow . symbolName
85+
86+
lspSymbolKind :: SymbolInfo -> LSP.SymbolKind
87+
lspSymbolKind = toLspSymbolKind . symbolKind
88+
5889
data RefKind
5990
= -- | The symbol is being declared. There should be at most one declaration
6091
-- for any given symbol (in correct Agda code). Roughly speaking, this is
@@ -95,3 +126,6 @@ instance Pretty Ref where
95126
pretty ref =
96127
((prettyAmbiguity ref <+> pretty (refKind ref)) <> comma)
97128
<+> pretty (refRange ref)
129+
130+
refIsDef :: Ref -> Bool
131+
refIsDef ref = refKind ref == Def

0 commit comments

Comments
 (0)