220 lines
4.0 KiB
Go
220 lines
4.0 KiB
Go
package parser
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
definitions = "definitions"
|
|
references = "references"
|
|
)
|
|
|
|
type Ranges struct {
|
|
DefRefs map[Id]Item
|
|
References *References
|
|
Hovers *Hovers
|
|
Cache *cache
|
|
}
|
|
|
|
type RawRange struct {
|
|
Id Id `json:"id"`
|
|
Data Range `json:"start"`
|
|
}
|
|
|
|
type Range struct {
|
|
Line int32 `json:"line"`
|
|
Character int32 `json:"character"`
|
|
RefId Id
|
|
}
|
|
|
|
type RawItem struct {
|
|
Property string `json:"property"`
|
|
RefId Id `json:"outV"`
|
|
RangeIds []Id `json:"inVs"`
|
|
DocId Id `json:"document"`
|
|
}
|
|
|
|
type Item struct {
|
|
Line int32
|
|
DocId Id
|
|
}
|
|
|
|
type SerializedRange struct {
|
|
StartLine int32 `json:"start_line"`
|
|
StartChar int32 `json:"start_char"`
|
|
DefinitionPath string `json:"definition_path,omitempty"`
|
|
Hover json.RawMessage `json:"hover"`
|
|
References []SerializedReference `json:"references,omitempty"`
|
|
}
|
|
|
|
func NewRanges() (*Ranges, error) {
|
|
hovers, err := NewHovers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
references, err := NewReferences()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cache, err := newCache("ranges", Range{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Ranges{
|
|
DefRefs: make(map[Id]Item),
|
|
References: references,
|
|
Hovers: hovers,
|
|
Cache: cache,
|
|
}, nil
|
|
}
|
|
|
|
func (r *Ranges) Read(label string, line []byte) error {
|
|
switch label {
|
|
case "range":
|
|
if err := r.addRange(line); err != nil {
|
|
return err
|
|
}
|
|
case "item":
|
|
if err := r.addItem(line); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return r.Hovers.Read(label, line)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Ranges) Serialize(f io.Writer, rangeIds []Id, docs map[Id]string) error {
|
|
encoder := json.NewEncoder(f)
|
|
n := len(rangeIds)
|
|
|
|
if _, err := f.Write([]byte("[")); err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, rangeId := range rangeIds {
|
|
entry, err := r.getRange(rangeId)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
serializedRange := SerializedRange{
|
|
StartLine: entry.Line,
|
|
StartChar: entry.Character,
|
|
DefinitionPath: r.definitionPathFor(docs, entry.RefId),
|
|
Hover: r.Hovers.For(entry.RefId),
|
|
References: r.References.For(docs, entry.RefId),
|
|
}
|
|
if err := encoder.Encode(serializedRange); err != nil {
|
|
return err
|
|
}
|
|
if i+1 < n {
|
|
if _, err := f.Write([]byte(",")); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
if _, err := f.Write([]byte("]")); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Ranges) Close() error {
|
|
for _, err := range []error{
|
|
r.Cache.Close(),
|
|
r.References.Close(),
|
|
r.Hovers.Close(),
|
|
} {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *Ranges) definitionPathFor(docs map[Id]string, refId Id) string {
|
|
defRef, ok := r.DefRefs[refId]
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
defPath := docs[defRef.DocId] + "#L" + strconv.Itoa(int(defRef.Line))
|
|
|
|
return defPath
|
|
}
|
|
|
|
func (r *Ranges) addRange(line []byte) error {
|
|
var rg RawRange
|
|
if err := json.Unmarshal(line, &rg); err != nil {
|
|
return err
|
|
}
|
|
|
|
return r.Cache.SetEntry(rg.Id, &rg.Data)
|
|
}
|
|
|
|
func (r *Ranges) addItem(line []byte) error {
|
|
var rawItem RawItem
|
|
if err := json.Unmarshal(line, &rawItem); err != nil {
|
|
return err
|
|
}
|
|
|
|
if rawItem.Property != definitions && rawItem.Property != references {
|
|
return nil
|
|
}
|
|
|
|
if len(rawItem.RangeIds) == 0 {
|
|
return errors.New("no range IDs")
|
|
}
|
|
|
|
var references []Item
|
|
|
|
for _, rangeId := range rawItem.RangeIds {
|
|
rg, err := r.getRange(rangeId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rg.RefId = rawItem.RefId
|
|
|
|
if err := r.Cache.SetEntry(rangeId, rg); err != nil {
|
|
return err
|
|
}
|
|
|
|
item := Item{
|
|
Line: rg.Line + 1,
|
|
DocId: rawItem.DocId,
|
|
}
|
|
|
|
if rawItem.Property == definitions {
|
|
r.DefRefs[rawItem.RefId] = item
|
|
} else {
|
|
references = append(references, item)
|
|
}
|
|
}
|
|
|
|
if err := r.References.Store(rawItem.RefId, references); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *Ranges) getRange(rangeId Id) (*Range, error) {
|
|
var rg Range
|
|
if err := r.Cache.Entry(rangeId, &rg); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &rg, nil
|
|
}
|