Skip to content

Commit

Permalink
Add basic package name completion based on adjacent files and directo…
Browse files Browse the repository at this point in the history
…ry name; fix hover/definition for groups
  • Loading branch information
kralicky committed Jan 13, 2024
1 parent 7d778a2 commit 2800107
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 31 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Features in progress:
- [x] Automatic imports
- [x] Import paths
- [x] Message and field literals
- [ ] Package names
- [x] Package names
- [x] Inlay hints for message and field literal types
- [ ] Code generator tools
- [x] Built-in compiler with workspace context
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/bufbuild/protovalidate-go v0.3.4
github.com/google/cel-go v0.18.2
github.com/kralicky/gpkg v0.0.0-20231114180450-2f4bff8c5588
github.com/kralicky/protocompile v0.0.0-20240110195505-9e89056c92b0
github.com/kralicky/protocompile v0.0.0-20240113031314-24e69108897d
github.com/kralicky/tools-lite v0.0.0-20240104191314-c259ddd5a342
github.com/mattn/go-tty v0.0.5
github.com/spf13/cobra v1.8.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kralicky/gpkg v0.0.0-20231114180450-2f4bff8c5588 h1:chw4znRXk7AA+AlKcrUZzH1Vupl54KcS4W6wkXCX3lU=
github.com/kralicky/gpkg v0.0.0-20231114180450-2f4bff8c5588/go.mod h1:vOkwMjs49XmP/7Xfo9ZL6eg2ei51lmtD/4U/Az5GTq8=
github.com/kralicky/protocompile v0.0.0-20240110195505-9e89056c92b0 h1:kp99R1s33F62lurBYhXhheqsE+e7jmDyz611wDA7J6M=
github.com/kralicky/protocompile v0.0.0-20240110195505-9e89056c92b0/go.mod h1:QKlDXp/yojhlpqgJfUHWhqzvD9gCD/baEPFvq89cpgE=
github.com/kralicky/protocompile v0.0.0-20240113031314-24e69108897d h1:DdKNJNMQRs2MBIikDaqWm75w2Yud4xtjRCmmhs/d1qw=
github.com/kralicky/protocompile v0.0.0-20240113031314-24e69108897d/go.mod h1:QKlDXp/yojhlpqgJfUHWhqzvD9gCD/baEPFvq89cpgE=
github.com/kralicky/tools-lite v0.0.0-20240104191314-c259ddd5a342 h1:lZLWHXKHmOhTrs3oSZoCRtb8Y9a0mqUwCsaKut+Y1eU=
github.com/kralicky/tools-lite v0.0.0-20240104191314-c259ddd5a342/go.mod h1:NKsdxFI6awifvNvxDwtCU1YCaKRoSSPpbHXkKOMuq24=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
Expand Down
6 changes: 5 additions & 1 deletion pkg/format/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ func (v *dumpVisitor) VisitOptionNode(node *ast.OptionNode) error {
}

func (v *dumpVisitor) VisitPackageNode(node *ast.PackageNode) error {
v.buf.WriteString(fmt.Sprintf("name=%q\n", node.Name.AsIdentifier()))
if node.IsIncomplete() {
v.buf.WriteString("!name")
} else {
v.buf.WriteString(fmt.Sprintf("name=%q\n", node.Name.AsIdentifier()))
}
return nil
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/format/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,9 @@ func (f *formatter) writeSyntax(syntaxNode *ast.SyntaxNode) {
func (f *formatter) writePackage(packageNode *ast.PackageNode) {
f.writeStart(packageNode.Keyword)
f.Space()
f.writeInline(packageNode.Name)
if packageNode.Name != nil {
f.writeInline(packageNode.Name)
}
f.writeLineEnd(packageNode.Semicolon)
}

Expand Down
8 changes: 0 additions & 8 deletions pkg/lsp/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,6 @@ func (c *Cache) FindParseResultByPath(path string) (parser.Result, error) {
return c.FindResultByPath(path)
}

// // FindFileByPath implements linker.Resolver.
// func (c *Cache) FindFileByPath(path protocompile.UnresolvedPath) (protoreflect.FileDescriptor, error) {
// c.resultsMu.RLock()
// defer c.resultsMu.RUnlock()
// c.resolver.f
// return c.results.AsResolver().FindFileByPath(path)
// }

func (c *Cache) FindFileByURI(uri protocol.DocumentURI) (protoreflect.FileDescriptor, error) {
c.resultsMu.RLock()
defer c.resultsMu.RUnlock()
Expand Down
77 changes: 74 additions & 3 deletions pkg/lsp/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ func (c *Cache) GetCompletions(params *protocol.CompletionParams) (result *proto
}
completions = append(completions, completeSyntaxVersions(partialVersion, partialVersionSuffix, params.Position)...)
}
case *ast.PackageNode:
// complete package names
completions = append(completions,
c.completePackageNames(node, path, searchTarget.AST(), maybeCurrentLinkRes, mapper, posOffset, params.Position)...)

}

return &protocol.CompletionList{
Expand Down Expand Up @@ -421,6 +426,72 @@ func editAddImport(parseRes parser.Result, path string) protocol.TextEdit {
}
}

func (c *Cache) completePackageNames(
node *ast.PackageNode,
nodePath []ast.Node,
fileNode *ast.FileNode,
linkRes linker.Result,
mapper *protocol.Mapper,
posOffset int,
pos protocol.Position,
) []protocol.CompletionItem {
var partialName, partialNameSuffix string
if !node.IsIncomplete() {
var err error
partialName, partialNameSuffix, err = findPartialNames(fileNode, node.Name, mapper, posOffset)
if err != nil {
return nil
}
}

dir := path.Dir(linkRes.Path())
var candidates []protoreflect.FullName
if base := protoreflect.FullName(path.Base(dir)); base.IsValid() {
candidates = append(candidates, base)
}

var items []protocol.CompletionItem
c.results.RangeFilesByPrefix(dir, func(f linker.File) bool {
if f == linkRes {
return true
}
if path.Dir(f.Path()) != dir {
return true
}
pkgName := f.Package()
candidates = append(candidates, pkgName)
return true
})
slices.Sort(candidates)
candidates = slices.Compact(candidates)

replaceRange := protocol.Range{
Start: adjustColumn(pos, -len(partialName)),
End: adjustColumn(pos, len(partialNameSuffix)),
}
for _, pkgName := range candidates {
if strings.HasPrefix(string(pkgName), partialName) {
item := protocol.CompletionItem{
Label: string(pkgName),
Kind: protocol.ModuleCompletion,
TextEdit: &protocol.Or_CompletionItem_textEdit{
Value: protocol.InsertReplaceEdit{
NewText: string(pkgName),
Insert: replaceRange,
Replace: replaceRange,
},
},
}
if string(pkgName) == partialName+partialNameSuffix {
item.Preselect = true
}

items = append(items, item)
}
}
return items
}

type fieldCompletionStyle int

const (
Expand Down Expand Up @@ -520,12 +591,12 @@ var (
snippetMode = protocol.SnippetTextFormat
)

func findCompletionScopeAndExistingOptions(path []ast.Node, linkRes linker.Result) (protoreflect.Descriptor, map[string]struct{}) {
func findCompletionScopeAndExistingOptions(nodePath []ast.Node, linkRes linker.Result) (protoreflect.Descriptor, map[string]struct{}) {
var scope protoreflect.Descriptor
existing := map[string]struct{}{}
LOOP:
for i := len(path) - 1; i >= 0; i-- {
switch node := path[i].(type) {
for i := len(nodePath) - 1; i >= 0; i-- {
switch node := nodePath[i].(type) {
case ast.MessageDeclNode:
scope = (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor()
if desc := linkRes.MessageDescriptor(node); desc != nil && desc.Options != nil {
Expand Down
27 changes: 13 additions & 14 deletions pkg/lsp/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func deepPathSearch(path []ast.Node, parseRes parser.Result, linkRes linker.Resu
case *ast.OneofNode:
want.desc = haveDesc.Oneofs().ByName(protoreflect.Name(wantNode.Name.AsIdentifier()))
case *ast.GroupNode:
want.desc = haveDesc.Fields().ByName(protoreflect.Name(wantNode.Name.AsIdentifier()))
want.desc = haveDesc.Messages().ByName(protoreflect.Name(wantNode.Name.AsIdentifier()))
case *ast.MessageNode:
want.desc = haveDesc.Messages().ByName(protoreflect.Name(wantNode.Name.AsIdentifier()))
case *ast.EnumNode:
Expand Down Expand Up @@ -658,6 +658,12 @@ func findNarrowestEnclosingScope(parseRes parser.Result, tokenAtOffset ast.Token
}
return nil
},
DoVisitPackageNode: func(node *ast.PackageNode) error {
if intersectsLocation(node) {
paths = append(paths, slices.Clone(tracker.Path()))
}
return nil
},
}, opts...)
if len(paths) == 0 {
return nil, false
Expand Down Expand Up @@ -692,26 +698,19 @@ func findDefinition(desc protoreflect.Descriptor, files linker.Files) (ast.NodeR
node = linkRes.MethodNode(desc.(protoutil.DescriptorProtoWrapper).AsProto().(*descriptorpb.MethodDescriptorProto)).GetName()
case protoreflect.FieldDescriptor:
if !desc.IsExtension() {
switch desc.(type) {
switch desc := desc.(type) {
case protoutil.DescriptorProtoWrapper:
node = linkRes.FieldNode(desc.(protoutil.DescriptorProtoWrapper).AsProto().(*descriptorpb.FieldDescriptorProto))
node = linkRes.FieldNode(desc.AsProto().(*descriptorpb.FieldDescriptorProto))
default:
// these can be internal filedesc.Field descriptors for e.g. builtin file options
linkRes.RangeFieldReferenceNodesWithDescriptors(func(n ast.Node, fd protoreflect.FieldDescriptor) bool {
// TODO: this is a workaround, figure out why the linker wrapper types aren't being used here
if desc.FullName() == fd.FullName() {
node = n
return false
}
return true
})
// these can be internal filedesc.Field descriptors for e.g. builtin options
node = linkRes.FieldNode(linkRes.FindDescriptorByName(desc.FullName()).(protoutil.DescriptorProtoWrapper).AsProto().(*descriptorpb.FieldDescriptorProto))
}
} else {
switch desc := desc.(type) {
case protoreflect.ExtensionTypeDescriptor:
node = linkRes.FieldNode(desc.Descriptor().(protoutil.DescriptorProtoWrapper).AsProto().(*descriptorpb.FieldDescriptorProto))
case protoutil.DescriptorProtoWrapper:
node = linkRes.FieldNode(desc.AsProto().(*descriptorpb.FieldDescriptorProto))
case protoreflect.ExtensionTypeDescriptor:
node = linkRes.FieldNode(desc.Descriptor().(protoutil.DescriptorProtoWrapper).AsProto().(*descriptorpb.FieldDescriptorProto))
}
}
case protoreflect.EnumValueDescriptor:
Expand Down
7 changes: 7 additions & 0 deletions pkg/lsp/semantic.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,10 @@ func (s *semanticItems) inspect(cache *Cache, node ast.Node, walkOptions ...ast.
s.mktokens(node.Name, append(tracker.Path(), node.Name), semanticTypeType, semanticModifierDefinition)
return nil
},
DoVisitGroupNode: func(node *ast.GroupNode) error {
s.mktokens(node.Name, append(tracker.Path(), node.Name), semanticTypeType, semanticModifierDefinition)
return nil
},
DoVisitFieldNode: func(node *ast.FieldNode) error {
var modifier tokenModifier
if id := string(node.FldType.AsIdentifier()); protocompile.IsScalarType(id) || protocompile.IsWellKnownType(protoreflect.FullName(id)) {
Expand Down Expand Up @@ -580,6 +584,9 @@ func (s *semanticItems) inspect(cache *Cache, node ast.Node, walkOptions ...ast.
return nil
},
DoVisitPackageNode: func(node *ast.PackageNode) error {
if node.IsIncomplete() {
return nil
}
s.mktokens(node.Name, append(tracker.Path(), node.Name), semanticTypeNamespace, 0)
return nil
},
Expand Down

0 comments on commit 2800107

Please sign in to comment.