78 lines
1.7 KiB
Go
78 lines
1.7 KiB
Go
package codeintel
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
ts "github.com/tree-sitter/go-tree-sitter"
|
|
)
|
|
|
|
type Symbol struct {
|
|
Name, Kind, Path string
|
|
Line int
|
|
Depth int
|
|
}
|
|
|
|
func Symbols(d *Document) []Symbol {
|
|
var out []Symbol
|
|
kinds := SymbolKinds()
|
|
var visit func(*ts.Node, int)
|
|
visit = func(n *ts.Node, depth int) {
|
|
kind := n.Kind()
|
|
if kinds[kind] {
|
|
name := symbolName(n, d.Source)
|
|
if name != "" {
|
|
out = append(out, Symbol{Name: name, Kind: kind, Path: d.Path, Line: Line(n), Depth: depth})
|
|
}
|
|
}
|
|
for i := uint(0); i < n.NamedChildCount(); i++ {
|
|
visit(n.NamedChild(i), depth+1)
|
|
}
|
|
}
|
|
visit(d.Root, 0)
|
|
return out
|
|
}
|
|
|
|
func symbolName(n *ts.Node, source []byte) string {
|
|
for _, field := range []string{"name", "declarator", "left"} {
|
|
child := n.ChildByFieldName(field)
|
|
if child != nil {
|
|
name := strings.TrimSpace(Text(child, source))
|
|
if name != "" && !strings.ContainsAny(name, "{}();") {
|
|
return name
|
|
}
|
|
}
|
|
}
|
|
for i := uint(0); i < n.NamedChildCount(); i++ {
|
|
child := n.NamedChild(i)
|
|
kind := child.Kind()
|
|
if kind == "identifier" || strings.HasSuffix(kind, "_name") || kind == "property_identifier" || kind == "type_identifier" {
|
|
return strings.TrimSpace(Text(child, source))
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func MatchSymbols(root string, query string) ([]Symbol, error) {
|
|
files, err := Files(root)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var out []Symbol
|
|
for _, file := range files {
|
|
d, err := Parse(file.Path, file.Language)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
syms := Symbols(d)
|
|
d.Close()
|
|
for _, s := range syms {
|
|
if query == "" || strings.Contains(strings.ToLower(s.Name), strings.ToLower(query)) {
|
|
s.Path, _ = filepath.Rel(root, s.Path)
|
|
out = append(out, s)
|
|
}
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|