summaryrefslogtreecommitdiff
path: root/workhorse/internal/lsif_transformer/parser/hovers.go
diff options
context:
space:
mode:
Diffstat (limited to 'workhorse/internal/lsif_transformer/parser/hovers.go')
-rw-r--r--workhorse/internal/lsif_transformer/parser/hovers.go162
1 files changed, 162 insertions, 0 deletions
diff --git a/workhorse/internal/lsif_transformer/parser/hovers.go b/workhorse/internal/lsif_transformer/parser/hovers.go
new file mode 100644
index 00000000000..e96d7e4fca3
--- /dev/null
+++ b/workhorse/internal/lsif_transformer/parser/hovers.go
@@ -0,0 +1,162 @@
+package parser
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "os"
+)
+
+type Offset struct {
+ At int32
+ Len int32
+}
+
+type Hovers struct {
+ File *os.File
+ Offsets *cache
+ CurrentOffset int
+}
+
+type RawResult struct {
+ Contents []json.RawMessage `json:"contents"`
+}
+
+type RawData struct {
+ Id Id `json:"id"`
+ Result RawResult `json:"result"`
+}
+
+type HoverRef struct {
+ ResultSetId Id `json:"outV"`
+ HoverId Id `json:"inV"`
+}
+
+type ResultSetRef struct {
+ ResultSetId Id `json:"outV"`
+ RefId Id `json:"inV"`
+}
+
+func NewHovers(config Config) (*Hovers, error) {
+ tempPath := config.TempPath
+
+ file, err := ioutil.TempFile(tempPath, "hovers")
+ if err != nil {
+ return nil, err
+ }
+
+ if err := os.Remove(file.Name()); err != nil {
+ return nil, err
+ }
+
+ offsets, err := newCache(tempPath, "hovers-indexes", Offset{})
+ if err != nil {
+ return nil, err
+ }
+
+ return &Hovers{
+ File: file,
+ Offsets: offsets,
+ CurrentOffset: 0,
+ }, nil
+}
+
+func (h *Hovers) Read(label string, line []byte) error {
+ switch label {
+ case "hoverResult":
+ if err := h.addData(line); err != nil {
+ return err
+ }
+ case "textDocument/hover":
+ if err := h.addHoverRef(line); err != nil {
+ return err
+ }
+ case "textDocument/references":
+ if err := h.addResultSetRef(line); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (h *Hovers) For(refId Id) json.RawMessage {
+ var offset Offset
+ if err := h.Offsets.Entry(refId, &offset); err != nil || offset.Len == 0 {
+ return nil
+ }
+
+ hover := make([]byte, offset.Len)
+ _, err := h.File.ReadAt(hover, int64(offset.At))
+ if err != nil {
+ return nil
+ }
+
+ return json.RawMessage(hover)
+}
+
+func (h *Hovers) Close() error {
+ return combineErrors(
+ h.File.Close(),
+ h.Offsets.Close(),
+ )
+}
+
+func (h *Hovers) addData(line []byte) error {
+ var rawData RawData
+ if err := json.Unmarshal(line, &rawData); err != nil {
+ return err
+ }
+
+ codeHovers := []*codeHover{}
+ for _, rawContent := range rawData.Result.Contents {
+ c, err := newCodeHover(rawContent)
+ if err != nil {
+ return err
+ }
+
+ codeHovers = append(codeHovers, c)
+ }
+
+ codeHoversData, err := json.Marshal(codeHovers)
+ if err != nil {
+ return err
+ }
+
+ n, err := h.File.Write(codeHoversData)
+ if err != nil {
+ return err
+ }
+
+ offset := Offset{At: int32(h.CurrentOffset), Len: int32(n)}
+ h.CurrentOffset += n
+
+ return h.Offsets.SetEntry(rawData.Id, &offset)
+}
+
+func (h *Hovers) addHoverRef(line []byte) error {
+ var hoverRef HoverRef
+ if err := json.Unmarshal(line, &hoverRef); err != nil {
+ return err
+ }
+
+ var offset Offset
+ if err := h.Offsets.Entry(hoverRef.HoverId, &offset); err != nil {
+ return err
+ }
+
+ return h.Offsets.SetEntry(hoverRef.ResultSetId, &offset)
+}
+
+func (h *Hovers) addResultSetRef(line []byte) error {
+ var ref ResultSetRef
+ if err := json.Unmarshal(line, &ref); err != nil {
+ return err
+ }
+
+ var offset Offset
+ if err := h.Offsets.Entry(ref.ResultSetId, &offset); err != nil {
+ return nil
+ }
+
+ return h.Offsets.SetEntry(ref.RefId, &offset)
+}