all repos

clerk @ 9d057cb160c6849c3dc3c5d0740cc4add015b3f0

missing tooling for ledger/hledger

clerk/internal/lsp/textdocument_document_symbol.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
lsp: implement textdocument/documentSymbol, 1 month ago
1
package lsp
2
3
import (
4
	"context"
5
6
	"go.lsp.dev/protocol"
7
8
	"olexsmir.xyz/clerk/journal/ast"
9
	"olexsmir.xyz/clerk/journal/token"
10
)
11
12
func (s *server) DocumentSymbol(_ context.Context, params *protocol.DocumentSymbolParams) (protocol.DocumentSymbolResult, error) {
13
	an := s.analysisFor(params.TextDocument.URI)
14
	if an == nil {
15
		return nil, nil
16
	}
17
	for _, pf := range an.Files {
18
		if pf.Path == params.TextDocument.URI.Path() {
19
			symbols := make([]protocol.DocumentSymbol, 0, len(pf.Ast.Entries)/2)
20
			for _, entry := range pf.Ast.Entries {
21
				if symbol, ok := entryDocumentSymbol(entry, pf.Src); ok {
22
					symbols = append(symbols, symbol)
23
				}
24
			}
25
			return protocol.DocumentSymbolSlice(symbols), nil
26
		}
27
	}
28
	return nil, nil
29
}
30
31
func entryDocumentSymbol(e ast.Entry, src []byte) (protocol.DocumentSymbol, bool) {
32
	var kind symbolKind
33
	var name string
34
	var sel, whole token.Span
35
	switch e := e.(type) {
36
	case *ast.Transaction:
37
		kind, name, sel, whole = symbolTransaction, transactionName(e), e.Date.Span, e.Span
38
	case *ast.PeriodicTransaction:
39
		kind, name, sel, whole = symbolTransaction, transactionName(e), e.Period.Span, e.Span
40
	case *ast.AutomatedTransaction:
41
		kind, name, sel, whole = symbolTransaction, transactionName(e), e.Expr.Span, e.Span
42
	case *ast.AccountDirective:
43
		kind, name, sel, whole = symbolAccount, e.Account.String(), e.Account.Span, e.Span
44
	case *ast.CommodityDirective:
45
		kind, name, sel, whole = symbolCommodity, e.Commodity, e.CommoditySpan, e.Span
46
	case *ast.PayeeDirective:
47
		if e.Name == nil {
48
			return protocol.DocumentSymbol{}, false
49
		}
50
		kind, name, sel, whole = symbolPayee, e.Name.Name, e.Name.Span, e.Span
51
	case *ast.TagDirective:
52
		sp, ok := tagDirectiveSpan(string(src), e)
53
		if !ok {
54
			return protocol.DocumentSymbol{}, false
55
		}
56
		kind, name, sel, whole = symbolTag, e.Name, sp, e.Span
57
	default:
58
		return protocol.DocumentSymbol{}, false
59
	}
60
	return protocol.DocumentSymbol{
61
		Name:           name,
62
		Kind:           kind.ToProtocol(),
63
		Range:          spanRangeFromSrc(src, whole),
64
		SelectionRange: spanRangeFromSrc(src, sel),
65
	}, true
66
}