Skip to content

Commit 45d6c0f

Browse files
feat: Add completion for builtin types with documentation (#81)
closes #80 ![Screenshot 2025-06-02 at 10 20 19 PM](https://github.com/user-attachments/assets/b299c66d-edfc-4624-99e8-9cccc06c3293)
1 parent 4f3a820 commit 45d6c0f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+109
-70
lines changed

src/docs.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::{collections::HashMap, sync::LazyLock};
2+
3+
macro_rules! docmap_builtin {
4+
($name:literal) => {
5+
($name, include_str!(concat!("docs/builtin/", $name, ".md")))
6+
};
7+
}
8+
9+
macro_rules! docmap_wellknown {
10+
($name:literal) => {
11+
(
12+
concat!("google.protobuf.", $name),
13+
include_str!(concat!("docs/wellknown/", $name, ".md")),
14+
)
15+
};
16+
}
17+
18+
pub static BUITIN: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
19+
HashMap::from([
20+
docmap_builtin!("int32"),
21+
docmap_builtin!("int64"),
22+
docmap_builtin!("uint32"),
23+
docmap_builtin!("uint64"),
24+
docmap_builtin!("sint32"),
25+
docmap_builtin!("sint64"),
26+
docmap_builtin!("fixed32"),
27+
docmap_builtin!("fixed64"),
28+
docmap_builtin!("sfixed32"),
29+
docmap_builtin!("sfixed64"),
30+
docmap_builtin!("float"),
31+
docmap_builtin!("double"),
32+
docmap_builtin!("string"),
33+
docmap_builtin!("bytes"),
34+
docmap_builtin!("bool"),
35+
docmap_builtin!("default"),
36+
])
37+
});
38+
39+
pub static WELLKNOWN: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
40+
HashMap::from([
41+
docmap_wellknown!("Any"),
42+
docmap_wellknown!("Api"),
43+
docmap_wellknown!("BoolValue"),
44+
docmap_wellknown!("BytesValue"),
45+
docmap_wellknown!("DoubleValue"),
46+
docmap_wellknown!("Duration"),
47+
docmap_wellknown!("Empty"),
48+
docmap_wellknown!("Enum"),
49+
docmap_wellknown!("EnumValue"),
50+
docmap_wellknown!("Field"),
51+
docmap_wellknown!("Field.Cardinality"),
52+
docmap_wellknown!("Field.Kind"),
53+
docmap_wellknown!("FieldMask"),
54+
docmap_wellknown!("FloatValue"),
55+
docmap_wellknown!("Int32Value"),
56+
docmap_wellknown!("Int64Value"),
57+
docmap_wellknown!("ListValue"),
58+
docmap_wellknown!("Method"),
59+
docmap_wellknown!("Mixin"),
60+
docmap_wellknown!("NullValue"),
61+
docmap_wellknown!("Option"),
62+
docmap_wellknown!("SourceContext"),
63+
docmap_wellknown!("StringValue"),
64+
docmap_wellknown!("Struct"),
65+
docmap_wellknown!("Syntax"),
66+
docmap_wellknown!("Timestamp"),
67+
docmap_wellknown!("Type"),
68+
docmap_wellknown!("UInt32Value"),
69+
docmap_wellknown!("UInt64Value"),
70+
docmap_wellknown!("Value"),
71+
])
72+
});

src/lsp.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@ use async_lsp::lsp_types::{
77
CreateFilesParams, DeleteFilesParams, DidChangeConfigurationParams,
88
DidChangeTextDocumentParams, DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams,
99
DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFormattingParams,
10-
DocumentRangeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
10+
DocumentRangeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, Documentation,
1111
FileOperationFilter, FileOperationPattern, FileOperationPatternKind,
1212
FileOperationRegistrationOptions, GotoDefinitionParams, GotoDefinitionResponse, Hover,
1313
HoverContents, HoverParams, HoverProviderCapability, InitializeParams, InitializeResult,
14-
Location, OneOf, PrepareRenameResponse, ReferenceParams, RenameFilesParams, RenameOptions,
15-
RenameParams, ServerCapabilities, ServerInfo, TextDocumentPositionParams,
16-
TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit, Url, WorkspaceEdit,
17-
WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities,
14+
Location, MarkupContent, MarkupKind, OneOf, PrepareRenameResponse, ReferenceParams,
15+
RenameFilesParams, RenameOptions, RenameParams, ServerCapabilities, ServerInfo,
16+
TextDocumentPositionParams, TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit, Url,
17+
WorkspaceEdit, WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities,
1818
WorkspaceServerCapabilities,
1919
};
2020
use async_lsp::{LanguageClient, LanguageServer, ResponseError};
2121
use futures::future::BoxFuture;
2222

23+
use crate::docs;
2324
use crate::formatter::ProtoFormatter;
2425
use crate::server::ProtoLanguageServer;
2526

@@ -159,20 +160,40 @@ impl LanguageServer for ProtoLanguageServer {
159160
) -> BoxFuture<'static, Result<Option<CompletionResponse>, Self::Error>> {
160161
let uri = params.text_document_position.text_document.uri;
161162

163+
// All keywords in the language
162164
let keywords = vec![
163165
"syntax", "package", "option", "import", "service", "rpc", "returns", "message",
164166
"enum", "oneof", "repeated", "reserved", "to",
165167
];
166168

167-
let mut completions: Vec<CompletionItem> = keywords
168-
.into_iter()
169-
.map(|w| CompletionItem {
170-
label: w.to_string(),
171-
kind: Some(CompletionItemKind::KEYWORD),
169+
// Build completion item from builtins as fields
170+
let mut completions: Vec<CompletionItem> = docs::BUITIN
171+
.iter()
172+
.map(|(k, v)| {
173+
(
174+
k,
175+
MarkupContent {
176+
kind: MarkupKind::Markdown,
177+
value: v.to_string(),
178+
},
179+
)
180+
})
181+
.map(|(k, v)| CompletionItem {
182+
label: k.to_string(),
183+
kind: Some(CompletionItemKind::FIELD),
184+
documentation: Some(Documentation::MarkupContent(v)),
172185
..CompletionItem::default()
173186
})
174187
.collect();
175188

189+
// Build completion item from keywords
190+
completions.extend(keywords.into_iter().map(|w| CompletionItem {
191+
label: w.to_string(),
192+
kind: Some(CompletionItemKind::KEYWORD),
193+
..CompletionItem::default()
194+
}));
195+
196+
// Build completion item from the current tree
176197
if let Some(tree) = self.state.get_tree(&uri) {
177198
let content = self.state.get_content(&uri);
178199
if let Some(package_name) = tree.get_package_name(content.as_bytes()) {

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use tracing::Level;
1212

1313
mod config;
1414
mod context;
15+
mod docs;
1516
mod formatter;
1617
mod lsp;
1718
mod nodekind;

src/workspace/hover.rs

Lines changed: 5 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,12 @@
1-
use std::{collections::HashMap, path::PathBuf, sync::LazyLock};
1+
use std::path::PathBuf;
22

33
use async_lsp::lsp_types::{MarkupContent, MarkupKind};
44

55
use crate::{
6-
context::hoverable::Hoverables, state::ProtoLanguageState, utils::split_identifier_package,
6+
context::hoverable::Hoverables, docs, state::ProtoLanguageState,
7+
utils::split_identifier_package,
78
};
89

9-
static BUITIN_DOCS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
10-
HashMap::from([
11-
("int32", include_str!("docs/builtin/int32.md")),
12-
("int64", include_str!("docs/builtin/int64.md")),
13-
("uint32", include_str!("docs/builtin/uint32.md")),
14-
("uint64", include_str!("docs/builtin/uint64.md")),
15-
("sint32", include_str!("docs/builtin/sint32.md")),
16-
("sint64", include_str!("docs/builtin/sint64.md")),
17-
("fixed32", include_str!("docs/builtin/fixed32.md")),
18-
("fixed64", include_str!("docs/builtin/fixed64.md")),
19-
("sfixed32", include_str!("docs/builtin/sfixed32.md")),
20-
("sfixed64", include_str!("docs/builtin/sfixed64.md")),
21-
("float", include_str!("docs/builtin/float.md")),
22-
("double", include_str!("docs/builtin/double.md")),
23-
("string", include_str!("docs/builtin/string.md")),
24-
("bytes", include_str!("docs/builtin/bytes.md")),
25-
("bool", include_str!("docs/builtin/bool.md")),
26-
("default", include_str!("docs/builtin/default.md")),
27-
])
28-
});
29-
30-
static WELLKNOWN_DOCS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
31-
HashMap::from([
32-
("google.protobuf.Any", include_str!("docs/wellknown/Any.md")),
33-
("google.protobuf.Api", include_str!("docs/wellknown/Api.md")),
34-
("google.protobuf.BoolValue", include_str!("docs/wellknown/BoolValue.md")),
35-
("google.protobuf.BytesValue", include_str!("docs/wellknown/BytesValue.md")),
36-
("google.protobuf.DoubleValue", include_str!("docs/wellknown/DoubleValue.md")),
37-
("google.protobuf.Duration", include_str!("docs/wellknown/Duration.md")),
38-
("google.protobuf.Empty", include_str!("docs/wellknown/Empty.md")),
39-
("google.protobuf.Enum", include_str!("docs/wellknown/Enum.md")),
40-
("google.protobuf.EnumValue", include_str!("docs/wellknown/EnumValue.md")),
41-
("google.protobuf.Field", include_str!("docs/wellknown/Field.md")),
42-
("google.protobuf.Field.Cardinality", include_str!("docs/wellknown/Field.Cardinality.md")),
43-
("google.protobuf.Field.Kind", include_str!("docs/wellknown/Field.Kind.md")),
44-
("google.protobuf.FieldMask", include_str!("docs/wellknown/FieldMask.md")),
45-
("google.protobuf.FloatValue", include_str!("docs/wellknown/FloatValue.md")),
46-
("google.protobuf.Int32Value", include_str!("docs/wellknown/Int32Value.md")),
47-
("google.protobuf.Int64Value", include_str!("docs/wellknown/Int64Value.md")),
48-
("google.protobuf.ListValue", include_str!("docs/wellknown/ListValue.md")),
49-
("google.protobuf.Method", include_str!("docs/wellknown/Method.md")),
50-
("google.protobuf.Mixin", include_str!("docs/wellknown/Mixin.md")),
51-
("google.protobuf.NullValue", include_str!("docs/wellknown/NullValue.md")),
52-
("google.protobuf.Option", include_str!("docs/wellknown/Option.md")),
53-
("google.protobuf.SourceContext", include_str!("docs/wellknown/SourceContext.md")),
54-
("google.protobuf.StringValue", include_str!("docs/wellknown/StringValue.md")),
55-
("google.protobuf.Struct", include_str!("docs/wellknown/Struct.md")),
56-
("google.protobuf.Syntax", include_str!("docs/wellknown/Syntax.md")),
57-
("google.protobuf.Timestamp", include_str!("docs/wellknown/Timestamp.md")),
58-
("google.protobuf.Type", include_str!("docs/wellknown/Type.md")),
59-
("google.protobuf.UInt32Value", include_str!("docs/wellknown/UInt32Value.md")),
60-
("google.protobuf.UInt64Value", include_str!("docs/wellknown/UInt64Value.md")),
61-
("google.protobuf.Value", include_str!("docs/wellknown/Value.md")),
62-
])
63-
});
64-
6510
impl ProtoLanguageState {
6611
pub fn hover(
6712
&self,
@@ -72,7 +17,7 @@ impl ProtoLanguageState {
7217
let v = match hv {
7318
Hoverables::FieldType(field) => {
7419
// Type is a builtin
75-
match BUITIN_DOCS.get(field.as_str()) {
20+
match docs::BUITIN.get(field.as_str()) {
7621
Some(docs) => docs.to_string(),
7722
_ => String::new(),
7823
}
@@ -97,7 +42,7 @@ Included from {}"#,
9742

9843
// Node is user defined type or well known type
9944
// If user defined,
100-
let mut result = WELLKNOWN_DOCS
45+
let mut result = docs::WELLKNOWN
10146
.get(format!("{package}.{identifier}").as_str())
10247
.map(|&s| s.to_string())
10348
.unwrap_or_default();

0 commit comments

Comments
 (0)