Skip to content

Commit 129c189

Browse files
committed
feat: add completion for enum and message in a package
1 parent 4757f01 commit 129c189

26 files changed

+93
-39
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ A Language Server for **proto3** files. It uses tree-sitter parser for all opera
44
![](./assets/protols.mov)
55

66
## Features
7-
- [x] Hover
8-
- [x] Go to definition
9-
- [x] Diagnostics
10-
- [x] Document Symbols for message and enums in current document
11-
- [x] Rename message, enum and rpc
12-
- [x] Completion for proto3 keywords
7+
- [x] Completion (keywords, enums and messages of the package)
8+
- [x] Diagnostics - based on sytax errors
9+
- [x] Document Symbols for message and enums
10+
- [x] Go to definition - across packages
11+
- [x] Hover - across packages
12+
- [x] Rename - in current buffer only
1313

1414
## Installation
1515

sample/simple.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ message Book {
99
string title = 2;
1010
Author author = 3;
1111
google.protobuf.Any data = 4;
12+
BookState state = 5;
1213

1314
// Author is a author of a book
1415
message Author {
1516
string name = 1;
1617
int64 age = 2;
1718
}
19+
20+
enum BookState {
21+
HARD_COVER = 1;
22+
SOFT_COVER = 2;
23+
}
1824
}
1925

2026
// This is a comment on message

src/lsp.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,16 @@ impl LanguageServer for ProtoLanguageServer {
156156
}
157157
fn completion(
158158
&mut self,
159-
_params: CompletionParams,
159+
params: CompletionParams,
160160
) -> BoxFuture<'static, Result<Option<CompletionResponse>, Self::Error>> {
161+
let uri = params.text_document_position.text_document.uri;
162+
161163
let keywords = vec![
162164
"syntax", "package", "option", "import", "service", "rpc", "returns", "message",
163165
"enum", "oneof", "repeated", "reserved", "to",
164166
];
165167

166-
let keywords = keywords
168+
let mut keywords: Vec<CompletionItem> = keywords
167169
.into_iter()
168170
.map(|w| CompletionItem {
169171
label: w.to_string(),
@@ -172,6 +174,12 @@ impl LanguageServer for ProtoLanguageServer {
172174
})
173175
.collect();
174176

177+
if let Some(tree) = self.state.get_tree(&uri) {
178+
let content = self.state.get_content(&uri);
179+
if let Some(package_name) = tree.get_package_name(content.as_bytes()) {
180+
keywords.extend(self.state.completion_items(package_name));
181+
}
182+
}
175183
Box::pin(async move { Ok(Some(CompletionResponse::Array(keywords))) })
176184
}
177185

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use tower::ServiceBuilder;
1010
use tracing::Level;
1111

1212
mod lsp;
13+
mod nodekind;
1314
mod parser;
1415
mod server;
1516
mod state;

src/parser/nodekind.rs renamed to src/nodekind.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ impl NodeKind {
3939
n.kind() == Self::PackageName.as_str()
4040
}
4141

42+
pub fn is_enum_name(n: &Node) -> bool {
43+
n.kind() == Self::EnumName.as_str()
44+
}
45+
46+
pub fn is_message_name(n: &Node) -> bool {
47+
n.kind() == Self::MessageName.as_str()
48+
}
49+
4250
pub fn is_userdefined(n: &Node) -> bool {
4351
n.kind() == Self::EnumName.as_str() || n.kind() == Self::MessageName.as_str()
4452
}

src/parser/definition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use async_lsp::lsp_types::{Location, Range};
22
use tree_sitter::Node;
33

4-
use crate::{parser::nodekind::NodeKind, utils::ts_to_lsp_position};
4+
use crate::{nodekind::NodeKind, utils::ts_to_lsp_position};
55

66
use super::ParsedTree;
77

src/parser/diagnostics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use async_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, PublishDiagnosticsParams, Range};
22

3-
use crate::utils::ts_to_lsp_position;
3+
use crate::{nodekind::NodeKind, utils::ts_to_lsp_position};
44

5-
use super::{nodekind::NodeKind, ParsedTree};
5+
use super::ParsedTree;
66

77
impl ParsedTree {
88
pub fn collect_parse_errors(&self) -> PublishDiagnosticsParams {

src/parser/docsymbol.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use async_lsp::lsp_types::{DocumentSymbol, Range};
22
use tree_sitter::TreeCursor;
33

4-
use crate::utils::ts_to_lsp_position;
4+
use crate::{nodekind::NodeKind, utils::ts_to_lsp_position};
55

6-
use super::{nodekind::NodeKind, ParsedTree};
6+
use super::ParsedTree;
77

88
#[derive(Default)]
99
pub(super) struct DocumentSymbolTreeBuilder {

src/parser/hover.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use async_lsp::lsp_types::MarkedString;
22
use tree_sitter::Node;
33

4-
use crate::parser::nodekind::NodeKind;
4+
use crate::nodekind::NodeKind;
55

66
use super::ParsedTree;
77

src/parser/input/test_can_rename.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
// A Book is book
66
message Book {

src/parser/input/test_collect_parse_error1.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package test;
3+
package com.parser;
44

55
message Foo {
66
reserved 1;

src/parser/input/test_collect_parse_error2.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
message Book {
66
message Author {

src/parser/input/test_document_symbols.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.symbols;
3+
package com.parser;
44

55
// outer 1 comment
66
message Outer1 {

src/parser/input/test_filter.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
message Book {
66

src/parser/input/test_goto_definition.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
message Book {
66
message Author {

src/parser/input/test_hover.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
// A Book is book
66
message Book {

src/parser/input/test_rename.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.book;
3+
package com.parser;
44

55
// A Book is book
66
message Book {

src/parser/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ mod definition;
55
mod diagnostics;
66
mod docsymbol;
77
mod hover;
8-
mod nodekind;
98
mod rename;
109
mod tree;
1110

src/parser/rename.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::collections::HashMap;
22

33
use async_lsp::lsp_types::{Position, Range, TextEdit, WorkspaceEdit};
44

5-
use crate::utils::ts_to_lsp_position;
5+
use crate::{nodekind::NodeKind, utils::ts_to_lsp_position};
66

7-
use super::{nodekind::NodeKind, ParsedTree};
7+
use super::ParsedTree;
88

99
impl ParsedTree {
1010
pub fn can_rename(&self, pos: &Position) -> Option<Range> {

src/parser/snapshots/protols__parser__tree__test__filter-2.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
source: src/parser/tree.rs
33
expression: package_name
44
---
5-
com.book
5+
com.parser

src/parser/tree.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use async_lsp::lsp_types::Position;
22
use tree_sitter::{Node, TreeCursor};
33

4-
use crate::utils::lsp_to_ts_point;
4+
use crate::{nodekind::NodeKind, utils::lsp_to_ts_point};
55

6-
use super::{nodekind::NodeKind, ParsedTree};
6+
use super::ParsedTree;
77

88
impl ParsedTree {
99
pub(super) fn walk_and_collect_filter<'a>(

src/state.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
use std::{collections::HashMap, fs::read_to_string};
22
use tracing::{error, info};
33

4-
use async_lsp::lsp_types::{PublishDiagnosticsParams, Url, WorkspaceFolder};
4+
use async_lsp::lsp_types::{
5+
CompletionItem, CompletionItemKind, PublishDiagnosticsParams, Url, WorkspaceFolder,
6+
};
7+
use tree_sitter::Node;
58
use walkdir::WalkDir;
69

7-
use crate::parser::{ParsedTree, ProtoParser};
10+
use crate::{
11+
nodekind::NodeKind,
12+
parser::{ParsedTree, ProtoParser},
13+
};
814

915
pub struct ProtoLanguageState {
1016
documents: HashMap<Url, String>,
@@ -106,4 +112,31 @@ impl ProtoLanguageState {
106112
self.trees.insert(new_uri.clone(), v);
107113
}
108114
}
115+
116+
pub fn completion_items(&self, package: &str) -> Vec<CompletionItem> {
117+
let collector = |f: fn(&Node) -> bool, k: CompletionItemKind| {
118+
self.get_trees_for_package(package)
119+
.into_iter()
120+
.fold(vec![], |mut v, tree| {
121+
let content = self.get_content(&tree.uri);
122+
let t = tree.filter_nodes(f).into_iter().map(|n| CompletionItem {
123+
label: n.utf8_text(content.as_bytes()).unwrap().to_string(),
124+
kind: Some(k),
125+
..Default::default()
126+
});
127+
v.extend(t);
128+
return v;
129+
})
130+
};
131+
132+
let mut result = collector(NodeKind::is_enum_name, CompletionItemKind::ENUM);
133+
result.extend(collector(
134+
NodeKind::is_message_name,
135+
CompletionItemKind::STRUCT,
136+
));
137+
// Better ways to dedup, but who cares?...
138+
result.sort_by_key(|k| k.label.clone());
139+
result.dedup_by_key(|k| k.label.clone());
140+
result
141+
}
109142
}

src/workspace/definition.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ mod test {
3838
state.upsert_file(&b_uri, b.to_owned());
3939
state.upsert_file(&c_uri, c.to_owned());
4040

41-
assert_yaml_snapshot!(state.definition("com.library", "Author"));
42-
assert_yaml_snapshot!(state.definition("com.library", "Author.Address"));
43-
assert_yaml_snapshot!(state.definition("com.library", "com.utility.Foobar.Baz"));
41+
assert_yaml_snapshot!(state.definition("com.workspace", "Author"));
42+
assert_yaml_snapshot!(state.definition("com.workspace", "Author.Address"));
43+
assert_yaml_snapshot!(state.definition("com.workspace", "com.utility.Foobar.Baz"));
4444
assert_yaml_snapshot!(state.definition("com.utility", "Baz"));
4545
}
4646
}

src/workspace/hover.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ mod test {
3939
state.upsert_file(&b_uri, b.to_owned());
4040
state.upsert_file(&c_uri, c.to_owned());
4141

42-
assert_yaml_snapshot!(state.hover("com.library", "Author"));
43-
assert_yaml_snapshot!(state.hover("com.library", "Author.Address"));
44-
assert_yaml_snapshot!(state.hover("com.library", "com.utility.Foobar.Baz"));
42+
assert_yaml_snapshot!(state.hover("com.workspace", "Author"));
43+
assert_yaml_snapshot!(state.hover("com.workspace", "Author.Address"));
44+
assert_yaml_snapshot!(state.hover("com.workspace", "com.utility.Foobar.Baz"));
4545
assert_yaml_snapshot!(state.hover("com.utility", "Baz"));
4646
}
4747
}

src/workspace/input/a.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.library;
3+
package com.workspace;
44

55
import "c.proto";
66

src/workspace/input/b.proto

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
package com.library;
3+
package com.workspace;
44

55
// A author is a author
66
message Author {
@@ -13,4 +13,3 @@ message Author {
1313

1414
Address foo = 2;
1515
}
16-

0 commit comments

Comments
 (0)