Skip to content

Commit

Permalink
Drop protocol.Position in favour of storing protocol.Range for Variab…
Browse files Browse the repository at this point in the history
…les and Functions.

Include (WIP) return type for functions.
Refactored indexed structure to have scope information, this allows to disambiguate between symbols with same names, and discard symbols that should be hidden in some contexts.
Hover feature is improved.
Index simple enums.
  • Loading branch information
pherrymason committed Jan 10, 2024
1 parent 976a0a7 commit 9f70f16
Show file tree
Hide file tree
Showing 15 changed files with 850 additions and 217 deletions.
40 changes: 40 additions & 0 deletions server/lsp/document.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package lsp

import (
"errors"
sitter "github.com/smacker/go-tree-sitter"
protocol "github.com/tliron/glsp/protocol_3_16"
"os"
"unicode"
)

type Document struct {
Expand Down Expand Up @@ -69,4 +71,42 @@ func (d *Document) ApplyChanges(changes []interface{}) {
}

d.lines = nil
// TODO This next line can be optimized by reparsing only what changed.
d.parsedTree = GetParsedTreeFromString(d.Content)
}

func (d *Document) WordInPosition(position protocol.Position) (string, error) {
index := position.IndexIn(d.Content)
return d.WordInIndex(index)
}

func (d *Document) WordInIndex(index int) (string, error) {
text := d.Content

wordStart := 0
for i := index; i >= 0; i-- {
if !(unicode.IsLetter(rune(text[i])) || unicode.IsDigit(rune(text[i])) || text[i] == '_') {
wordStart = i + 1
break
}
}

wordEnd := len(text) - 1
for i := index; i < len(text); i++ {
if !(unicode.IsLetter(rune(text[i])) || unicode.IsDigit(rune(text[i])) || text[i] == '_') {
wordEnd = i - 1
break
}
}

if wordStart > len(text) {
return "", errors.New("wordStart out of bounds")
} else if wordEnd > len(text) {
return "", errors.New("wordEnd out of bounds")
} else if wordStart > wordEnd {
return "", errors.New("wordStart > wordEnd!")
}

word := text[wordStart : wordEnd+1]
return word, nil
}
28 changes: 28 additions & 0 deletions server/lsp/document_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lsp

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestWordInIndex(t *testing.T) {
cases := []struct {
name string
expected string
position int
}{
{"start of doc", "hello", 1},
{"word", "expected", 14},
{"word with underscore", "bye_bye", 24},
}

source := "hello this is expected bye_bye"
doc := NewDocumentFromString("x", source)
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
word, _ := doc.WordInIndex(tt.position)

assert.Equal(t, tt.expected, word)
})
}
}
64 changes: 64 additions & 0 deletions server/lsp/indexables/enum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package indexables

import protocol "github.com/tliron/glsp/protocol_3_16"

type Enumerator struct {
name string
value string
BaseIndexable
}

func NewEnumerator(name string, value string, identifierPosition protocol.Range) Enumerator {
return Enumerator{
name: name,
value: value,
BaseIndexable: BaseIndexable{
identifierRange: identifierPosition,
Kind: protocol.CompletionItemKindEnumMember,
},
}
}

type Enum struct {
name string
baseType string
enumerators []Enumerator
BaseIndexable
}

func NewEnum(name string, baseType string, enumerators []Enumerator, identifierRangePosition protocol.Range, documentRangePosition protocol.Range) Enum {
return Enum{
name: name,
baseType: baseType,
enumerators: enumerators,
BaseIndexable: BaseIndexable{
identifierRange: identifierRangePosition,
documentRange: documentRangePosition,
Kind: protocol.CompletionItemKindEnum,
},
}
}

func (e Enum) GetName() string {
return e.name
}

func (e Enum) GetKind() protocol.CompletionItemKind {
return e.Kind
}

func (e Enum) GetDocumentURI() protocol.DocumentUri {
return e.documentURI
}

func (e Enum) GetDeclarationRange() protocol.Range {
return e.documentRange
}

func (e Enum) GetDocumentRange() protocol.Range {
return e.identifierRange
}

func (e *Enum) AddEnumerators(enumerators []Enumerator) {
e.enumerators = enumerators
}
79 changes: 66 additions & 13 deletions server/lsp/indexables/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,52 @@ package indexables

import protocol "github.com/tliron/glsp/protocol_3_16"

type FunctionType int

const (
Anonymous = iota
UserDefined
)

type Function struct {
Name string
ReturnType string
DocumentURI protocol.DocumentUri
DeclarationPosition protocol.Position
Kind protocol.CompletionItemKind
_type FunctionType
Name string
ReturnType string
DocumentURI protocol.DocumentUri
identifierRange protocol.Range
documentRange protocol.Range
Kind protocol.CompletionItemKind

Variables map[string]Variable
Enums map[string]*Enum
ChildrenFunctions map[string]*Function
}

func NewFunction(name string, uri protocol.DocumentUri, position protocol.Position, kind protocol.CompletionItemKind) Function {
func NewAnonymousScopeFunction(name string, uri protocol.DocumentUri, docRange protocol.Range, kind protocol.CompletionItemKind) Function {
return Function{
Name: name,
ReturnType: "??",
DocumentURI: uri,
DeclarationPosition: position,
Kind: kind,
_type: Anonymous,
Name: name,
ReturnType: "??",
DocumentURI: uri,
documentRange: docRange,
Kind: kind,
Variables: make(map[string]Variable),
Enums: make(map[string]*Enum),
ChildrenFunctions: make(map[string]*Function),
}
}

func NewFunction(name string, uri protocol.DocumentUri, identifierRangePosition protocol.Range, docRange protocol.Range, kind protocol.CompletionItemKind) Function {
return Function{
_type: UserDefined,
Name: name,
ReturnType: "??",
DocumentURI: uri,
identifierRange: identifierRangePosition,
documentRange: docRange,
Kind: kind,
Variables: make(map[string]Variable),
ChildrenFunctions: make(map[string]*Function),
}
}

Expand All @@ -32,6 +63,28 @@ func (f Function) GetDocumentURI() protocol.DocumentUri {
return f.DocumentURI
}

func (f Function) GetDeclarationPosition() protocol.Position {
return f.DeclarationPosition
func (f Function) GetDeclarationRange() protocol.Range {
return f.identifierRange
}

func (f Function) GetDocumentRange() protocol.Range {
return f.documentRange
}

func (f *Function) SetEndRange(endPosition protocol.Position) {
f.documentRange.End = endPosition
}

func (f *Function) AddVariables(variables []Variable) {
for _, variable := range variables {
f.Variables[variable.Name] = variable
}
}

func (f *Function) AddEnum(enum *Enum) {
f.Enums[enum.name] = enum
}

func (f Function) AddFunction(f2 *Function) {
f.ChildrenFunctions[f2.Name] = f2
}
20 changes: 20 additions & 0 deletions server/lsp/indexables/indexable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package indexables

import "github.com/tliron/glsp/protocol_3_16"

type Indexable interface {
GetName() string
GetKind() protocol.CompletionItemKind
GetDocumentURI() protocol.DocumentUri
GetDeclarationRange() protocol.Range
GetDocumentRange() protocol.Range
}

type IndexableCollection []Indexable

type BaseIndexable struct {
documentURI protocol.DocumentUri
identifierRange protocol.Range
documentRange protocol.Range
Kind protocol.CompletionItemKind
}
18 changes: 11 additions & 7 deletions server/lsp/indexables/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package indexables
import protocol "github.com/tliron/glsp/protocol_3_16"

type Struct struct {
Name string
Members []string
DocumentURI protocol.URI
DocumentPositionRange protocol.Position
Kind protocol.CompletionItemKind
Name string
Members []string
DocumentURI protocol.URI
identifierRange protocol.Range
documentRange protocol.Range
Kind protocol.CompletionItemKind
}

func (s Struct) GetName() string {
Expand All @@ -22,6 +23,9 @@ func (s Struct) GetDocumentURI() protocol.DocumentUri {
return s.DocumentURI
}

func (s Struct) GetDeclarationPosition() protocol.Position {
return s.DocumentPositionRange
func (s Struct) GetDeclarationRange() protocol.Range {
return s.identifierRange
}
func (s Struct) GetDocumentRange() protocol.Range {
return s.documentRange
}
32 changes: 18 additions & 14 deletions server/lsp/indexables/variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ package indexables
import protocol "github.com/tliron/glsp/protocol_3_16"

type Variable struct {
Name string
Type string
DocumentURI protocol.DocumentUri
DeclarationPosition protocol.Position
Kind protocol.CompletionItemKind
Name string
Type string
BaseIndexable
}

func NewVariable(name string, variableType string, uri protocol.DocumentUri, position protocol.Position, kind protocol.CompletionItemKind) Variable {
func NewVariable(name string, variableType string, uri protocol.DocumentUri, identifierRangePosition protocol.Range, documentRangePosition protocol.Range, kind protocol.CompletionItemKind) Variable {
return Variable{
Name: name,
Type: variableType,
DocumentURI: uri,
DeclarationPosition: position,
Kind: kind,
Name: name,
Type: variableType,
BaseIndexable: BaseIndexable{
documentURI: uri,
identifierRange: identifierRangePosition,
documentRange: documentRangePosition,
Kind: kind,
},
}
}

Expand All @@ -33,9 +34,12 @@ func (v Variable) GetKind() protocol.CompletionItemKind {
}

func (v Variable) GetDocumentURI() protocol.DocumentUri {
return v.DocumentURI
return v.documentURI
}

func (v Variable) GetDeclarationPosition() protocol.Position {
return v.DeclarationPosition
func (v Variable) GetDeclarationRange() protocol.Range {
return v.identifierRange
}
func (v Variable) GetDocumentRange() protocol.Range {
return v.documentRange
}
Loading

0 comments on commit 9f70f16

Please sign in to comment.