diff options
Diffstat (limited to 'workhorse/internal/lsif_transformer/parser/ranges.go')
-rw-r--r-- | workhorse/internal/lsif_transformer/parser/ranges.go | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/workhorse/internal/lsif_transformer/parser/ranges.go b/workhorse/internal/lsif_transformer/parser/ranges.go new file mode 100644 index 00000000000..a11a66d70ca --- /dev/null +++ b/workhorse/internal/lsif_transformer/parser/ranges.go @@ -0,0 +1,214 @@ +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(config Config) (*Ranges, error) { + hovers, err := NewHovers(config) + if err != nil { + return nil, err + } + + references, err := NewReferences(config) + if err != nil { + return nil, err + } + + cache, err := newCache(config.TempPath, "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 { + return combineErrors( + r.Cache.Close(), + r.References.Close(), + r.Hovers.Close(), + ) +} + +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 +} |