From 93cebe063ae28b45b38af875c57d6ad7ecd85e3f Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Wed, 26 Jun 2024 18:27:36 +0300 Subject: [PATCH 1/6] cover getWord function with tests --- components/jump_definition_test.go | 71 ++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 components/jump_definition_test.go diff --git a/components/jump_definition_test.go b/components/jump_definition_test.go new file mode 100644 index 0000000..e5fe1d3 --- /dev/null +++ b/components/jump_definition_test.go @@ -0,0 +1,71 @@ +package components + +import ( + "fmt" + "testing" +) + +func Test_getWord(t *testing.T) { + type args struct { + line string + idx int + includeDot bool + } + tests := []struct { + args args + want string + }{ + { + args: args{ + // cursor is right here | + line: "rpc MethodName(SearchDashboardReq) returns (SearchDashboardResp) {", + idx: 38, + includeDot: false, + }, + want: "returns", + }, + { + args: args{ + // cursor is right here | + line: "rpc MethodName(SearchDashboardReq) returns (SearchDashboardResp) {", + idx: 21, + includeDot: false, + }, + want: "SearchDashboardReq", + }, + { + args: args{ + // cursor is right here | + line: "rpc MethodName(SearchDashboardReq) returns (SearchDashboardResp) {", + idx: 34, + includeDot: false, + }, + want: "", + }, + { + args: args{ + // cursor is right here | + line: "rpc MethodName(SearchDashboardReq) returns (google.protobuf.Empty) {", + idx: 53, + includeDot: false, + }, + want: "protobuf", + }, + { + args: args{ + // cursor is right here | + line: "rpc MethodName(SearchDashboardReq) returns (google.protobuf.Empty) {", + idx: 53, + includeDot: true, + }, + want: "google.protobuf.Empty", + }, + } + for i, tt := range tests { + t.Run(fmt.Sprint(i), func(t *testing.T) { + if got := getWord(tt.args.line, tt.args.idx, tt.args.includeDot); got != tt.want { + t.Errorf("getWord() = '%v', want '%v'", got, tt.want) + } + }) + } +} From b2f3b09085331286b6ec31ef247d6777aef4f029 Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Thu, 27 Jun 2024 16:02:50 +0300 Subject: [PATCH 2/6] clean up getWord function --- components/jump_definition.go | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/components/jump_definition.go b/components/jump_definition.go index 09ee7e9..8368ce8 100644 --- a/components/jump_definition.go +++ b/components/jump_definition.go @@ -278,21 +278,15 @@ func getWord(line string, idx int, includeDot bool) string { isWordChar := func(ch byte) bool { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_' || (ch == '.' && includeDot) } - ll := l - for ll >= 0 { - if !isWordChar(line[ll]) { - break - } - ll-- + + for l >= 0 && isWordChar(line[l]) { + l-- } - if ll != l { - ll = ll + 1 + if l != idx { + l += 1 } - l = ll - for r < len(line) { - if !isWordChar(line[r]) { - break - } + + for r < len(line) && isWordChar(line[r]) { r++ } return line[l:r] From e6e544d197ab02e37a00b84b34bf17ca49415289 Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Mon, 1 Jul 2024 01:31:25 +0300 Subject: [PATCH 3/6] refactor jump_definition to allow reuse --- components/jump_definition.go | 235 ++++++++++++++++++++++------------ 1 file changed, 153 insertions(+), 82 deletions(-) diff --git a/components/jump_definition.go b/components/jump_definition.go index 8368ce8..c790f95 100644 --- a/components/jump_definition.go +++ b/components/jump_definition.go @@ -2,7 +2,9 @@ package components import ( "context" + "errors" "fmt" + "pls/proto/parser" "pls/proto/view" "regexp" "strings" @@ -11,18 +13,92 @@ import ( "github.com/TobiasYin/go-lsp/lsp/defines" ) +type SymbolDefinition struct { + Filename string + Position defines.Position + Type string + Enum parser.Enum + Message parser.Message + ImportUri string +} + +const ( + DefinitionTypeImport = "import" + DefinitionTypeMessage = "message" + DefinitionTypeEnum = "enum" +) + +var ErrSymbolNotFound = errors.New("symbol not found") + func JumpDefine(ctx context.Context, req *defines.DefinitionParams) (result *[]defines.LocationLink, err error) { - if view.IsProtoFile(req.TextDocument.Uri) { - return JumpProtoDefine(ctx, req) + + symbols, err := findSymbolDefinition(ctx, &req.TextDocumentPositionParams) + if err != nil { + return nil, err } - if view.IsPbHeader(req.TextDocument.Uri) { - return JumpPbHeaderDefine(ctx, req) + locations := locationFromSymbols(symbols) + + return &locations, nil +} + +func locationFromSymbols(symbols []SymbolDefinition) (result []defines.LocationLink) { + + for _, symbol := range symbols { + switch symbol.Type { + case DefinitionTypeImport: + result = append(result, defines.LocationLink{ + TargetUri: defines.DocumentUri(symbol.ImportUri), + }) + case DefinitionTypeEnum: + proto := symbol.Enum.Protobuf() + result = append(result, defines.LocationLink{ + TargetUri: defines.DocumentUri(proto.Position.Filename), + TargetSelectionRange: defines.Range{ + Start: defines.Position{ + Line: symbol.Position.Line, + Character: symbol.Position.Character, + }, + End: defines.Position{ + Line: symbol.Position.Line, + Character: symbol.Position.Character + uint(len(proto.Name)), + }, + }, + }) + case DefinitionTypeMessage: + proto := symbol.Message.Protobuf() + result = append(result, defines.LocationLink{ + TargetUri: defines.DocumentUri(proto.Position.Filename), + TargetSelectionRange: defines.Range{ + Start: defines.Position{ + Line: symbol.Position.Line, + Character: symbol.Position.Character, + }, + End: defines.Position{ + Line: symbol.Position.Line, + Character: symbol.Position.Character + uint(len(proto.Name)), + }, + }, + }) + } } - return nil, nil + + return result } -func JumpPbHeaderDefine(ctx context.Context, req *defines.DefinitionParams) (result *[]defines.LocationLink, err error) { +func findSymbolDefinition(ctx context.Context, position *defines.TextDocumentPositionParams) (result []SymbolDefinition, err error) { + + if view.IsProtoFile(position.TextDocument.Uri) { + return JumpProtoDefine(ctx, position) + } + if view.IsPbHeader(position.TextDocument.Uri) { + return JumpPbHeaderDefine(ctx, position) + } + + return nil, ErrSymbolNotFound +} + +func JumpPbHeaderDefine(ctx context.Context, req *defines.TextDocumentPositionParams) (result []SymbolDefinition, err error) { proto_uri := strings.ReplaceAll(string(req.TextDocument.Uri), "bazel-out/local_linux-fastbuild/genfiles/", "") proto_uri = strings.ReplaceAll(proto_uri, ".pb.h", ".proto") proto_file, err := view.ViewManager.GetFile(defines.DocumentUri(proto_uri)) @@ -34,7 +110,7 @@ func JumpPbHeaderDefine(ctx context.Context, req *defines.DefinitionParams) (res logs.Printf("line %v, word %v", line, word) res, err := searchType(proto_file, word) // better than nothing - if (res == nil || len(*res) == 0) && strings.Contains(word, "_") { + if (res == nil || len(res) == 0) && strings.Contains(word, "_") { split_res := strings.Split(word, "_") if len(split_res) > 0 { res, err = searchType(proto_file, split_res[0]) @@ -43,24 +119,24 @@ func JumpPbHeaderDefine(ctx context.Context, req *defines.DefinitionParams) (res return res, err } -func JumpProtoDefine(ctx context.Context, req *defines.DefinitionParams) (result *[]defines.LocationLink, err error) { - proto_file, err := view.ViewManager.GetFile(req.TextDocument.Uri) +func JumpProtoDefine(ctx context.Context, position *defines.TextDocumentPositionParams) (result []SymbolDefinition, err error) { + proto_file, err := view.ViewManager.GetFile(position.TextDocument.Uri) if err != nil { return nil, err } - line_str := proto_file.ReadLine(int(req.Position.Line)) - if len(line_str) < int(req.Position.Character) { - return nil, fmt.Errorf("pos %v line_str %v", req.Position, line_str) + line_str := proto_file.ReadLine(int(position.Position.Line)) + if len(line_str) < int(position.Position.Character) { + return nil, fmt.Errorf("pos %v line_str %v", position.Position, line_str) } // dont consider single line if strings.HasPrefix(line_str, "import") { - return jumpImport(ctx, req, line_str) + return jumpImport(ctx, position, line_str) } // type define - package_and_word := getWord(line_str, int(req.Position.Character), true) + package_and_word := getWord(line_str, int(position.Position.Character), true) pos := strings.LastIndexAny(package_and_word, ".") my_package := "" @@ -79,14 +155,14 @@ func JumpProtoDefine(ctx context.Context, req *defines.DefinitionParams) (result } if word_only { - res, err := searchTypeNested(proto_file, word, int(req.Position.Line+1)) - if err == nil && len(*res) > 0 { + res, err := searchTypeNested(proto_file, word, int(position.Position.Line+1)) + if err == nil && len(res) > 0 { return res, nil } } if my_package == package_name { res, err := searchType(proto_file, word) - if err == nil && len(*res) > 0 { + if err == nil && len(res) > 0 { return res, nil } } @@ -107,13 +183,13 @@ func JumpProtoDefine(ctx context.Context, req *defines.DefinitionParams) (result if qualifierReferencesPackage(package_name, packages[0].ProtoPackage.Name, my_package) { // same packages_name in different file res, err := searchType(import_file, word) - if err == nil && len(*res) > 0 { + if err == nil && len(res) > 0 { return res, nil } } } res, err := searchPublicImport(import_file, package_name, my_package, word) - if res != nil && len(*res) > 0 { + if res != nil && len(res) > 0 { return res, err } } @@ -121,7 +197,7 @@ func JumpProtoDefine(ctx context.Context, req *defines.DefinitionParams) (result return nil, nil } -func searchPublicImport(import_file view.ProtoFile, package_name string, my_package string, word string) (result *[]defines.LocationLink, err error) { +func searchPublicImport(import_file view.ProtoFile, package_name string, my_package string, word string) (result []SymbolDefinition, err error) { for _, imp := range import_file.Proto().Imports() { if imp.ProtoImport.Kind == "public" { import_uri, err := view.GetDocumentUriFromImportPath(import_file.URI(), imp.ProtoImport.Filename) @@ -138,13 +214,13 @@ func searchPublicImport(import_file view.ProtoFile, package_name string, my_pack if qualifierReferencesPackage(package_name, packages[0].ProtoPackage.Name, my_package) { // same packages_name in different file res, err := searchType(import_file, word) - if err == nil && len(*res) > 0 { + if err == nil && len(res) > 0 { return res, nil } } } res, err := searchPublicImport(import_file, package_name, my_package, word) - if res != nil && len(*res) > 0 { + if res != nil && len(res) > 0 { return res, err } } @@ -168,99 +244,94 @@ func qualifierReferencesPackage(query_pkg string, candidate_pkg string, current_ return current_pkg == prefix || strings.HasPrefix(current_pkg, prefix+".") } -func jumpImport(ctx context.Context, req *defines.DefinitionParams, line_str string) (result *[]defines.LocationLink, err error) { +func jumpImport(ctx context.Context, position *defines.TextDocumentPositionParams, line_str string) (result []SymbolDefinition, err error) { r, _ := regexp.Compile("\"(.+)\\/([^\\/]+)\"") pos := r.FindStringIndex(line_str) if pos == nil { return nil, fmt.Errorf("import match failed") } - import_uri, err := view.GetDocumentUriFromImportPath(req.TextDocument.Uri, line_str[pos[0]+1:pos[1]-1]) + import_uri, err := view.GetDocumentUriFromImportPath(position.TextDocument.Uri, line_str[pos[0]+1:pos[1]-1]) if err != nil { return nil, err } - return &[]defines.LocationLink{{ - TargetUri: import_uri, + return []SymbolDefinition{{ + Type: DefinitionTypeImport, + ImportUri: string(import_uri), }}, nil } -func searchTypeNested(proto_file view.ProtoFile, word string, line int) (result *[]defines.LocationLink, err error) { +func searchTypeNested(proto_file view.ProtoFile, word string, line int) (result []SymbolDefinition, err error) { // search message for _, message := range proto_file.Proto().GetAllParentMessage(line) { if message.Protobuf().Name == word { - line := proto_file.ReadLine(message.Protobuf().Position.Line - 1) - return &[]defines.LocationLink{{ - TargetUri: proto_file.URI(), - TargetSelectionRange: defines.Range{ - Start: defines.Position{ - Line: uint(message.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word)), - }, - End: defines.Position{ - Line: uint(message.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word) + len(word)), - }}, - }}, nil + message.Protobuf().Position.Filename = string(proto_file.URI()) + result = append(result, messageSymbolDefinition(proto_file, message)) } } // search enum for _, enum := range proto_file.Proto().GetAllParentEnum(line) { if enum.Protobuf().Name == word { - line := proto_file.ReadLine(enum.Protobuf().Position.Line - 1) - return &[]defines.LocationLink{{ - TargetUri: proto_file.URI(), - TargetSelectionRange: defines.Range{ - Start: defines.Position{ - Line: uint(enum.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word)), - }, - End: defines.Position{ - Line: uint(enum.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word) + len(word)), - }}, - }}, nil + enum.Protobuf().Position.Filename = string(proto_file.URI()) + result = append(result, enumSymbolDefinition(proto_file, enum)) } } - return nil, fmt.Errorf("%v not found", word) + + if len(result) == 0 { + return nil, fmt.Errorf("%w: %s", ErrSymbolNotFound, word) + } + + return result, nil } -func searchType(proto_file view.ProtoFile, word string) (result *[]defines.LocationLink, err error) { +func searchType(proto_file view.ProtoFile, word string) (result []SymbolDefinition, err error) { // search message for _, message := range proto_file.Proto().Messages() { if message.Protobuf().Name == word { - line := proto_file.ReadLine(message.Protobuf().Position.Line - 1) - return &[]defines.LocationLink{{ - TargetUri: proto_file.URI(), - TargetSelectionRange: defines.Range{ - Start: defines.Position{ - Line: uint(message.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word)), - }, - End: defines.Position{ - Line: uint(message.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word) + len(word)), - }}, - }}, nil + message.Protobuf().Position.Filename = string(proto_file.URI()) + result = append(result, messageSymbolDefinition(proto_file, message)) } } // search enum for _, enum := range proto_file.Proto().Enums() { if enum.Protobuf().Name == word { - line := proto_file.ReadLine(enum.Protobuf().Position.Line - 1) - return &[]defines.LocationLink{{ - TargetUri: proto_file.URI(), - TargetSelectionRange: defines.Range{ - Start: defines.Position{ - Line: uint(enum.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word)), - }, - End: defines.Position{ - Line: uint(enum.Protobuf().Position.Line) - 1, - Character: uint(strings.Index(line, word) + len(word)), - }}, - }}, nil + enum.Protobuf().Position.Filename = string(proto_file.URI()) + result = append(result, enumSymbolDefinition(proto_file, enum)) } } - return nil, fmt.Errorf("%v not found", word) + + if len(result) == 0 { + return nil, fmt.Errorf("%w: %s", ErrSymbolNotFound, word) + } + + return result, nil +} + +func messageSymbolDefinition(proto_file view.ProtoFile, message parser.Message) SymbolDefinition { + line := proto_file.ReadLine(message.Protobuf().Position.Line - 1) + symbolStart := strings.Index(line, message.Protobuf().Name) + return SymbolDefinition{ + Filename: string(proto_file.URI()), + Position: defines.Position{ + Line: uint(message.Protobuf().Position.Line - 1), + Character: uint(symbolStart), + }, + Type: DefinitionTypeMessage, + Message: message, + } +} + +func enumSymbolDefinition(proto_file view.ProtoFile, enum parser.Enum) SymbolDefinition { + line := proto_file.ReadLine(enum.Protobuf().Position.Line - 1) + symbolStart := strings.Index(line, enum.Protobuf().Name) + return SymbolDefinition{ + Filename: string(proto_file.URI()), + Position: defines.Position{ + Line: uint(enum.Protobuf().Position.Line - 1), + Character: uint(symbolStart), + }, + Type: DefinitionTypeEnum, + Enum: enum, + } } func getWord(line string, idx int, includeDot bool) string { From d4b1096405fec7f9d87a16317469fc687b57ad26 Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Mon, 1 Jul 2024 01:32:28 +0300 Subject: [PATCH 4/6] add hover support --- components/hover.go | 270 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 1 + 2 files changed, 271 insertions(+) create mode 100644 components/hover.go diff --git a/components/hover.go b/components/hover.go new file mode 100644 index 0000000..a80bda1 --- /dev/null +++ b/components/hover.go @@ -0,0 +1,270 @@ +package components + +import ( + "bytes" + "context" + "pls/proto/parser" + "strings" + "text/template" + + "github.com/TobiasYin/go-lsp/lsp/defines" + "github.com/emicklei/proto" +) + +var hoverTmpl *template.Template + +// Parsing templates once on server start +func init() { + hoverTmpl = template.New("hover") + hoverTmpl = hoverTmpl.Funcs(getCustomFuncs(hoverTmpl)) + hoverTmpl = template.Must(hoverTmpl.Parse(hoverTemplate)) + + messageTmpl := template.New("message") + messageTmpl = messageTmpl.Funcs(getCustomFuncs(hoverTmpl)) + messageTmpl = template.Must(hoverTmpl.Parse(messageTemplate)) + + enumTmpl := template.New("enum") + enumTmpl = enumTmpl.Funcs(getCustomFuncs(hoverTmpl)) + enumTmpl = template.Must(hoverTmpl.Parse(enumTemplate)) +} + +func Hover(ctx context.Context, req *defines.HoverParams) (result *defines.Hover, err error) { + + symbols, err := findSymbolDefinition(ctx, &req.TextDocumentPositionParams) + if err != nil { + return nil, err + } + + if len(symbols) == 0 { + return nil, ErrSymbolNotFound + } + + result = &defines.Hover{ + Contents: defines.MarkupContent{ + Kind: defines.MarkupKindMarkdown, + Value: formatHover(symbols[0]), + }, + } + + return result, nil +} + +func formatHover(symbol SymbolDefinition) string { + + var hoverData hoverData + + switch symbol.Type { + case DefinitionTypeEnum: + hoverData.Enum = prepareEnumData(symbol.Enum) + case DefinitionTypeMessage: + hoverData.Message = prepareMessageData(symbol.Message) + default: + return "" + } + + buffer := bytes.NewBuffer(nil) + err := hoverTmpl.Execute(buffer, hoverData) + if err != nil { + return err.Error() + } + + return buffer.String() +} + +const hoverTemplate = "```proto" + ` +{{- if .Message }} +{{- templateWithIndent "message" .Message 0 }} +{{- end }} +{{- if .Enum }} +{{- templateWithIndent "enum" .Enum 0 }} +{{- end }} +` + "```" + +type hoverData struct { + Message *messageData + Enum *enumData +} + +const enumTemplate = `{{- define "enum" }} +{{- range .Comments }} +{{ . }} +{{- end }} +enum {{ .Name }} { + {{- range .Items }} + {{- range .Comments }} + {{ . }} + {{- end }} + {{ .Name }} = {{ .Value }}; {{ if .InlineComment }}{{ .InlineComment }}{{end}} + {{- end }} +} +{{- end }}` + +type enumData struct { + Comments []string + Name string + Items []enumItem +} + +type enumItem struct { + Comments []string + Name string + Value int + InlineComment string +} + +type enumFieldVisitor struct { + proto.NoopVisitor + visitFunc func(*proto.EnumField) +} + +func (v *enumFieldVisitor) VisitEnumField(ef *proto.EnumField) { + v.visitFunc(ef) +} + +func prepareEnumData(enum parser.Enum) *enumData { + + data := enumData{ + Name: enum.Protobuf().Name, + Items: []enumItem{}, + } + + if enum.Protobuf().Comment != nil { + data.Comments = formatComments(enum.Protobuf().Comment.Lines) + } + + for _, item := range enum.Protobuf().Elements { + item.Accept(&enumFieldVisitor{visitFunc: func(ef *proto.EnumField) { + + enumItem := enumItem{ + Name: ef.Name, + Value: ef.Integer, + } + + if ef.Comment != nil { + enumItem.Comments = formatComments(ef.Comment.Lines) + } + + if ef.InlineComment != nil && len(ef.InlineComment.Lines) != 0 { + enumItem.InlineComment = formatComments(ef.InlineComment.Lines[0:1])[0] + } + + data.Items = append(data.Items, enumItem) + }}) + } + + return &data +} + +const messageTemplate = `{{- define "message" }} +{{- range .Comments }} +{{ . }} +{{- end }} +message {{ .Name }} { +{{- range .NestedEnums }} + {{- templateWithIndent "enum" . 1 }} +{{- end }} +{{- range .NestedMessages }} + {{- templateWithIndent "message" . 1 }} +{{- end }} +{{- range .Fields -}} + {{- range .Comments }} + {{ . }} + {{- end }} + {{.Optional}}{{.Repeated}}{{.Type}} {{.Name}} = {{.ProtoSequence}};{{ if .InlineComment }} // {{.InlineComment }}{{ end }} +{{- end }} +} +{{- end }}` + +type messageData struct { + Comments []string + Name string + Fields []field + NestedEnums []*enumData + NestedMessages []*messageData +} + +type field struct { + Comments []string + Repeated string + Optional string + Type string + Name string + ProtoSequence int + InlineComment string +} + +func prepareMessageData(message parser.Message) *messageData { + + data := messageData{ + Name: message.Protobuf().Name, + } + + if message.Protobuf().Comment != nil { + data.Comments = formatComments(message.Protobuf().Comment.Lines) + } + + for _, nestedMsg := range message.NestedMessages() { + data.NestedMessages = append(data.NestedMessages, prepareMessageData(nestedMsg)) + } + + for _, nestedEnum := range message.NestedEnums() { + data.NestedEnums = append(data.NestedEnums, prepareEnumData(nestedEnum)) + } + + for _, item := range message.Fields() { + + var field field + + if item.ProtoField.Comment != nil { + field.Comments = formatComments(item.ProtoField.Comment.Lines) + } + + if item.ProtoField.Optional { + field.Optional = "optional " + } + if item.ProtoField.Repeated { + field.Repeated = "repeated " + } + + field.Type = item.ProtoField.Type + field.Name = item.ProtoField.Name + field.ProtoSequence = item.ProtoField.Sequence + + if item.ProtoField.InlineComment != nil { + field.InlineComment = formatComments(item.ProtoField.InlineComment.Lines[0:1])[0] + } + data.Fields = append(data.Fields, field) + } + + return &data +} + +func getCustomFuncs(parent *template.Template) template.FuncMap { + return template.FuncMap{ + "templateWithIndent": func(name string, data interface{}, indent int) (string, error) { + buf := bytes.NewBuffer(nil) + if err := parent.ExecuteTemplate(buf, name, data); err != nil { + return "", err + } + + return indentText(buf.String(), indent), nil + }, + } +} + +func indentText(text string, level int) string { + indent := strings.Repeat("\t", level) + return indent + strings.ReplaceAll(text, "\n", "\n"+indent) +} + +func formatComments(lines []string) []string { + if len(lines) == 0 { + return nil + } + + out := make([]string, 0, len(lines)) + for _, item := range lines { + out = append(out, "//"+item) + } + return out +} diff --git a/main.go b/main.go index ce8ebc7..b531e7c 100644 --- a/main.go +++ b/main.go @@ -56,5 +56,6 @@ func main() { server.OnDefinition(components.JumpDefine) server.OnDocumentFormatting(components.Format) server.OnCompletion(components.Completion) + server.OnHover(components.Hover) server.Run() } From cfdcd3b5522a6bf306d7f5ce0fde832e57348038 Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Mon, 1 Jul 2024 01:33:29 +0300 Subject: [PATCH 5/6] update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fc2747e..bca99d3 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,8 @@ if you use vscode, see [vscode-extension/README.md](./vscode-extension/README.md ## features 1. Parsing document symbols -2. Go to definition -3. Format file with clang-format -4. Code completion -5. Jump from protobuf's cpp header to proto define (only global message and enum) +1. Go to definition +1. Symbol definition on hover +1. Format file with clang-format +1. Code completion +1. Jump from protobuf's cpp header to proto define (only global message and enum) From b65792a533c05eac800b0a71ae1e2bcaaf0b9191 Mon Sep 17 00:00:00 2001 From: brotifypacha Date: Mon, 1 Jul 2024 08:43:54 +0300 Subject: [PATCH 6/6] refactor: deduplicate searchImportPuclic function code --- components/jump_definition.go | 51 +++++++++++++---------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/components/jump_definition.go b/components/jump_definition.go index c790f95..9854e38 100644 --- a/components/jump_definition.go +++ b/components/jump_definition.go @@ -167,8 +167,22 @@ func JumpProtoDefine(ctx context.Context, position *defines.TextDocumentPosition } } - for _, im := range proto_file.Proto().Imports() { - import_uri, err := view.GetDocumentUriFromImportPath(proto_file.URI(), im.ProtoImport.Filename) + res, err := searchImport(proto_file, package_name, my_package, word, "") + if err == nil && len(res) > 0 { + return res, nil + } + + return nil, nil +} + +func searchImport(proto view.ProtoFile, package_name, my_package, word, kind string) (result []SymbolDefinition, err error) { + for _, im := range proto.Proto().Imports() { + + if kind != "" && im.ProtoImport.Kind != kind { + continue + } + + import_uri, err := view.GetDocumentUriFromImportPath(proto.URI(), im.ProtoImport.Filename) if err != nil { continue } @@ -188,45 +202,16 @@ func JumpProtoDefine(ctx context.Context, position *defines.TextDocumentPosition } } } - res, err := searchPublicImport(import_file, package_name, my_package, word) + res, err := searchImport(import_file, package_name, my_package, word, "public") if res != nil && len(res) > 0 { return res, err } } return nil, nil -} -func searchPublicImport(import_file view.ProtoFile, package_name string, my_package string, word string) (result []SymbolDefinition, err error) { - for _, imp := range import_file.Proto().Imports() { - if imp.ProtoImport.Kind == "public" { - import_uri, err := view.GetDocumentUriFromImportPath(import_file.URI(), imp.ProtoImport.Filename) - if err != nil { - continue - } - - import_file, err := view.ViewManager.GetFile(import_uri) - if err != nil { - continue - } - packages := import_file.Proto().Packages() - if len(packages) > 0 { - if qualifierReferencesPackage(package_name, packages[0].ProtoPackage.Name, my_package) { - // same packages_name in different file - res, err := searchType(import_file, word) - if err == nil && len(res) > 0 { - return res, nil - } - } - } - res, err := searchPublicImport(import_file, package_name, my_package, word) - if res != nil && len(res) > 0 { - return res, err - } - } - } - return nil, nil } + func qualifierReferencesPackage(query_pkg string, candidate_pkg string, current_pkg string) bool { if query_pkg == candidate_pkg { // fully qualified name return true