d2/d2lsp/d2lsp.go

158 lines
3.4 KiB
Go
Raw Normal View History

2024-09-19 14:32:48 +00:00
// d2lsp contains functions useful for IDE clients
package d2lsp
import (
"fmt"
"strings"
2024-10-17 14:32:54 +00:00
"oss.terrastruct.com/d2/d2ast"
2024-09-19 14:32:48 +00:00
"oss.terrastruct.com/d2/d2ir"
"oss.terrastruct.com/d2/d2parser"
"oss.terrastruct.com/d2/lib/memfs"
)
2024-10-19 05:56:00 +00:00
func GetRefRanges(path string, fs map[string]string, boardPath []string, key string) (ranges []d2ast.Range, importRanges []d2ast.Range, _ error) {
2024-10-17 14:32:54 +00:00
m, err := getBoardMap(path, fs, boardPath)
2024-09-19 14:32:48 +00:00
if err != nil {
2024-10-19 05:56:00 +00:00
return nil, nil, err
2024-09-19 14:32:48 +00:00
}
mk, err := d2parser.ParseMapKey(key)
if err != nil {
2024-10-19 05:56:00 +00:00
return nil, nil, err
2024-09-19 14:32:48 +00:00
}
2024-10-12 19:35:32 +00:00
if mk.Key == nil && len(mk.Edges) == 0 {
2024-10-19 05:56:00 +00:00
return nil, nil, fmt.Errorf(`"%s" is invalid`, key)
2024-09-19 14:32:48 +00:00
}
var f *d2ir.Field
2024-10-12 19:35:32 +00:00
if mk.Key != nil {
for _, p := range mk.Key.Path {
2024-11-24 19:03:03 +00:00
f = m.GetField(p.Unbox())
2024-10-12 19:35:32 +00:00
if f == nil {
2024-10-19 05:56:00 +00:00
return nil, nil, nil
2024-10-12 19:35:32 +00:00
}
m = f.Map()
2024-09-19 14:32:48 +00:00
}
}
2024-10-12 19:35:32 +00:00
if len(mk.Edges) > 0 {
eids := d2ir.NewEdgeIDs(mk)
var edges []*d2ir.Edge
for _, eid := range eids {
edges = append(edges, m.GetEdges(eid, nil, nil)...)
}
if len(edges) == 0 {
2024-10-19 05:56:00 +00:00
return nil, nil, nil
2024-10-12 19:35:32 +00:00
}
for _, edge := range edges {
for _, ref := range edge.References {
2024-10-19 05:56:00 +00:00
ranges = append(ranges, ref.AST().GetRange())
}
if edge.ImportAST() != nil {
importRanges = append(importRanges, edge.ImportAST().GetRange())
2024-10-12 19:35:32 +00:00
}
}
} else {
for _, ref := range f.References {
2024-10-19 05:56:00 +00:00
ranges = append(ranges, ref.AST().GetRange())
2024-10-12 19:35:32 +00:00
}
2024-10-19 05:56:00 +00:00
if f.ImportAST() != nil {
importRanges = append(importRanges, f.ImportAST().GetRange())
2024-10-17 14:32:54 +00:00
}
2024-10-19 05:56:00 +00:00
}
return ranges, importRanges, nil
2024-10-17 14:32:54 +00:00
}
func getBoardMap(path string, fs map[string]string, boardPath []string) (*d2ir.Map, error) {
if _, ok := fs[path]; !ok {
return nil, fmt.Errorf(`"%s" not found`, path)
}
r := strings.NewReader(fs[path])
ast, err := d2parser.Parse(path, r, nil)
if err != nil {
return nil, err
}
mfs, err := memfs.New(fs)
if err != nil {
return nil, err
}
m, _, err := d2ir.Compile(ast, &d2ir.CompileOptions{
FS: mfs,
})
if err != nil {
return nil, err
}
m = m.FindBoardRoot(boardPath)
if m == nil {
return nil, fmt.Errorf(`board "%v" not found`, boardPath)
}
return m, nil
}
2024-11-13 05:38:21 +00:00
2024-11-13 05:55:17 +00:00
func GetBoardAtPosition(text string, pos d2ast.Position) ([]string, error) {
r := strings.NewReader(text)
ast, err := d2parser.Parse("", r, nil)
2024-11-13 05:38:21 +00:00
if err != nil {
return nil, err
}
pos.Byte = -1
return getBoardPathAtPosition(*ast, nil, pos), nil
}
func getBoardPathAtPosition(m d2ast.Map, currPath []string, pos d2ast.Position) []string {
inRange := func(r d2ast.Range) bool {
return !pos.Before(r.Start) && pos.Before(r.End)
}
if !inRange(m.Range) {
return nil
}
for _, n := range m.Nodes {
if n.MapKey == nil {
continue
}
mk := n.MapKey
if mk.Key == nil || len(mk.Key.Path) == 0 {
continue
}
if mk.Value.Map == nil {
continue
}
keyName := mk.Key.Path[0].Unbox().ScalarString()
if len(currPath)%2 == 0 {
isBoardType := keyName == "layers" || keyName == "scenarios" || keyName == "steps"
if !isBoardType {
continue
}
}
if inRange(mk.Value.Map.Range) {
newPath := append(currPath, keyName)
// Check deeper
if deeperPath := getBoardPathAtPosition(*mk.Value.Map, newPath, pos); deeperPath != nil {
return deeperPath
}
2024-11-13 18:15:28 +00:00
// We're in between boards, e.g. layers.x.scenarios
// Which means, there's no board at this position
if len(newPath)%2 == 1 {
return nil
}
2024-11-13 05:38:21 +00:00
// Nothing deeper matched but we're in this map's range, return current path
return newPath
}
}
return nil
}