From 372ef8da9ebd4e00d26a4403f3c2d50fa861867b Mon Sep 17 00:00:00 2001 From: coder3101 Date: Wed, 25 Dec 2024 22:03:14 +0530 Subject: [PATCH 1/2] wip: Add hover for builtin types --- src/lsp.rs | 2 +- src/nodekind.rs | 6 + src/parser/tree.rs | 9 ++ src/workspace/hover.rs | 108 ++++++++++++++++++ ...ver__test__workspace_test_hover-2.snap.new | 6 + 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new diff --git a/src/lsp.rs b/src/lsp.rs index d0a256c..1939524 100644 --- a/src/lsp.rs +++ b/src/lsp.rs @@ -163,7 +163,7 @@ impl LanguageServer for ProtoLanguageServer { }; let content = self.state.get_content(&uri); - let identifier = tree.get_actionable_node_text_at_position(&pos, content.as_bytes()); + let identifier = tree.get_hoverable_node_text_at_position(&pos, content.as_bytes()); let current_package_name = tree.get_package_name(content.as_bytes()); let Some(identifier) = identifier else { diff --git a/src/nodekind.rs b/src/nodekind.rs index 0205ff0..5d55a43 100644 --- a/src/nodekind.rs +++ b/src/nodekind.rs @@ -8,6 +8,7 @@ pub enum NodeKind { Message, EnumName, FieldName, + FieldBuiltinTypeName, ServiceName, RpcName, PackageName, @@ -23,6 +24,7 @@ impl NodeKind { NodeKind::Message => "message", NodeKind::EnumName => "enum_name", NodeKind::FieldName => "message_or_enum_type", + NodeKind::FieldBuiltinTypeName => "type", NodeKind::ServiceName => "service_name", NodeKind::RpcName => "rpc_name", NodeKind::PackageName => "full_ident", @@ -57,6 +59,10 @@ impl NodeKind { n.kind() == Self::FieldName.as_str() } + pub fn is_builtin_field_type(n: &Node) -> bool { + n.kind() == Self::FieldBuiltinTypeName.as_str() + } + pub fn is_userdefined(n: &Node) -> bool { n.kind() == Self::EnumName.as_str() || n.kind() == Self::MessageName.as_str() } diff --git a/src/parser/tree.rs b/src/parser/tree.rs index 68cffc7..4088c4c 100644 --- a/src/parser/tree.rs +++ b/src/parser/tree.rs @@ -63,6 +63,15 @@ impl ParsedTree { .map(|n| n.utf8_text(content.as_ref()).expect("utf-8 parse error")) } + pub fn get_hoverable_node_text_at_position<'a>(&'a self, pos:&Position, content: &'a [u8]) -> Option<&'a str> { + if let Some(n) = self.get_node_at_position(pos) { + if NodeKind::is_builtin_field_type(&n) { + return Some(n.utf8_text(content).expect("utf8-parse error")) + } + } + self.get_actionable_node_text_at_position(pos, content) + } + pub fn get_ancestor_nodes_at_position<'a>(&'a self, pos: &Position) -> Vec> { let Some(mut n) = self.get_actionable_node_at_position(pos) else { return vec![]; diff --git a/src/workspace/hover.rs b/src/workspace/hover.rs index 70bb3e6..e2c3ded 100644 --- a/src/workspace/hover.rs +++ b/src/workspace/hover.rs @@ -1,11 +1,118 @@ +use std::{collections::HashMap, sync::LazyLock}; + use async_lsp::lsp_types::MarkedString; use crate::{ formatter::ProtoFormatter, state::ProtoLanguageState, utils::split_identifier_package, }; + +static BUITIN_DOCS: LazyLock> = LazyLock::new(|| { + HashMap::from([ + ( + "int32", + r#"A 32-bit integer (varint encoding) + +Values of this type range between `-2147483648` and `2147483647`. +Beware that negative values are encoded as five bytes on the wire!"#, + ), + ( + "int64", + r#"A 64-bit integer (varint encoding) + +Values of this type range between `-9223372036854775808` and `9223372036854775807`. +Beware that negative values are encoded as ten bytes on the wire!"#, + ), + ( + "uint32", + r#"A 32-bit unsigned integer (varint encoding) + +Values of this type range between `0` and `4294967295`."#, + ), + ( + "uint64", + r#"A 64-bit unsigned integer (varint encoding) + +Values of this type range between `0` and `18446744073709551615`."#, + ), + ( + "sint32", + r#"A 32-bit integer (ZigZag encoding) + +Values of this type range between `-2147483648` and `2147483647`."#, + ), + ( + "sint64", + r#"A 64-bit integer (ZigZag encoding) + +Values of this type range between `-9223372036854775808` and `9223372036854775807`."#, + ), + ( + "fixed32", + r#"A 32-bit unsigned integer (4-byte encoding) + +Values of this type range between `0` and `4294967295`."#, + ), + ( + "fixed64", + r#"A 64-bit unsigned integer (8-byte encoding) + +Values of this type range between `0` and `18446744073709551615`."#, + ), + ( + "sfixed32", + r#"A 32-bit integer (4-byte encoding) + +Values of this type range between `-2147483648` and `2147483647`."#, + ), + ( + "sfixed64", + r#"A 64-bit integer (8-byte encoding) + +Values of this type range between `-9223372036854775808` and `9223372036854775807`."#, + ), + ( + "float", + "A single-precision floating point number (IEEE-745.2008 binary32).", + ), + ( + "double", + "A double-precision floating point number (IEEE-745.2008 binary64).", + ), + ( + "string", + r#"A string of text. + +Stores at most 4GB of text. Intended to be UTF-8 encoded Unicode; use `bytes` if you need other encodings."#, + ), + ( + "bytes", + r#"A blob of arbitrary bytes. + +Stores at most 4GB of binary data. Encoded as base64 in JSON."#, + ), + ( + "bool", + r#"A Boolean value: `true` or `false`. + +Encoded as a single byte: `0x00` or `0xff` (all non-zero bytes decode to `true`)."#, + ), + ( + "default", + r#"A magic option that specifies the field's default value. + +Unlike every other option on a field, this does not have a corresponding field in +`google.protobuf.FieldOptions`; it is implemented by compiler magic."#, + ), + ]) +}); + impl ProtoLanguageState { pub fn hover(&self, curr_package: &str, identifier: &str) -> Vec { + if let Some(docs) = BUITIN_DOCS.get(identifier) { + return vec![MarkedString::String(docs.to_string())]; + } + let (mut package, identifier) = split_identifier_package(identifier); if package.is_empty() { package = curr_package; @@ -42,6 +149,7 @@ mod test { state.upsert_file(&c_uri, c.to_owned()); assert_yaml_snapshot!(state.hover("com.workspace", "Author")); + assert_yaml_snapshot!(state.hover("com.workspace", "int64")); assert_yaml_snapshot!(state.hover("com.workspace", "Author.Address")); assert_yaml_snapshot!(state.hover("com.workspace", "com.utility.Foobar.Baz")); assert_yaml_snapshot!(state.hover("com.utility", "Baz")); diff --git a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new new file mode 100644 index 0000000..530fef6 --- /dev/null +++ b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new @@ -0,0 +1,6 @@ +--- +source: src/workspace/hover.rs +assertion_line: 152 +expression: "state.hover(\"com.workspace\", \"int64\")" +--- +- "A 64-bit integer (varint encoding)\n\nValues of this type range between `-9223372036854775808` and `9223372036854775807`.\nBeware that negative values are encoded as ten bytes on the wire!" From 84252c33f95e86c29caadbd3d2cf953e6c7718b1 Mon Sep 17 00:00:00 2001 From: coder3101 Date: Thu, 26 Dec 2024 09:49:31 +0530 Subject: [PATCH 2/2] feat: Add hover docs for builtin types --- src/nodekind.rs | 6 ------ src/parser/tree.rs | 13 +++++++------ ...kspace__hover__test__workspace_test_hover-2.snap | 5 +++-- ...ce__hover__test__workspace_test_hover-2.snap.new | 6 ------ ...kspace__hover__test__workspace_test_hover-3.snap | 5 +++-- ...kspace__hover__test__workspace_test_hover-5.snap | 6 ++++++ 6 files changed, 19 insertions(+), 22 deletions(-) delete mode 100644 src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new create mode 100644 src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-5.snap diff --git a/src/nodekind.rs b/src/nodekind.rs index 5d55a43..0205ff0 100644 --- a/src/nodekind.rs +++ b/src/nodekind.rs @@ -8,7 +8,6 @@ pub enum NodeKind { Message, EnumName, FieldName, - FieldBuiltinTypeName, ServiceName, RpcName, PackageName, @@ -24,7 +23,6 @@ impl NodeKind { NodeKind::Message => "message", NodeKind::EnumName => "enum_name", NodeKind::FieldName => "message_or_enum_type", - NodeKind::FieldBuiltinTypeName => "type", NodeKind::ServiceName => "service_name", NodeKind::RpcName => "rpc_name", NodeKind::PackageName => "full_ident", @@ -59,10 +57,6 @@ impl NodeKind { n.kind() == Self::FieldName.as_str() } - pub fn is_builtin_field_type(n: &Node) -> bool { - n.kind() == Self::FieldBuiltinTypeName.as_str() - } - pub fn is_userdefined(n: &Node) -> bool { n.kind() == Self::EnumName.as_str() || n.kind() == Self::MessageName.as_str() } diff --git a/src/parser/tree.rs b/src/parser/tree.rs index 4088c4c..b4c4844 100644 --- a/src/parser/tree.rs +++ b/src/parser/tree.rs @@ -63,13 +63,14 @@ impl ParsedTree { .map(|n| n.utf8_text(content.as_ref()).expect("utf-8 parse error")) } - pub fn get_hoverable_node_text_at_position<'a>(&'a self, pos:&Position, content: &'a [u8]) -> Option<&'a str> { - if let Some(n) = self.get_node_at_position(pos) { - if NodeKind::is_builtin_field_type(&n) { - return Some(n.utf8_text(content).expect("utf8-parse error")) - } - } + pub fn get_hoverable_node_text_at_position<'a>( + &'a self, + pos: &Position, + content: &'a [u8], + ) -> Option<&'a str> { + let n = self.get_node_at_position(pos)?; self.get_actionable_node_text_at_position(pos, content) + .or(Some(n.kind())) } pub fn get_ancestor_nodes_at_position<'a>(&'a self, pos: &Position) -> Vec> { diff --git a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap index 55ec65d..1dbb2d6 100644 --- a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap +++ b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap @@ -1,5 +1,6 @@ --- source: src/workspace/hover.rs -expression: "state.hover(\"com.library\", \"Author.Address\")" +expression: "state.hover(\"com.workspace\", \"int64\")" +snapshot_kind: text --- -- Address is a Address +- "A 64-bit integer (varint encoding)\n\nValues of this type range between `-9223372036854775808` and `9223372036854775807`.\nBeware that negative values are encoded as ten bytes on the wire!" diff --git a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new deleted file mode 100644 index 530fef6..0000000 --- a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-2.snap.new +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: src/workspace/hover.rs -assertion_line: 152 -expression: "state.hover(\"com.workspace\", \"int64\")" ---- -- "A 64-bit integer (varint encoding)\n\nValues of this type range between `-9223372036854775808` and `9223372036854775807`.\nBeware that negative values are encoded as ten bytes on the wire!" diff --git a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-3.snap b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-3.snap index 7e3ab87..00bbfa0 100644 --- a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-3.snap +++ b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-3.snap @@ -1,5 +1,6 @@ --- source: src/workspace/hover.rs -expression: "state.hover(\"com.library\", \"com.utility.Foobar.Baz\")" +expression: "state.hover(\"com.workspace\", \"Author.Address\")" +snapshot_kind: text --- -- What is baz? +- Address is a Address diff --git a/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-5.snap b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-5.snap new file mode 100644 index 0000000..152acde --- /dev/null +++ b/src/workspace/snapshots/protols__workspace__hover__test__workspace_test_hover-5.snap @@ -0,0 +1,6 @@ +--- +source: src/workspace/hover.rs +expression: "state.hover(\"com.utility\", \"Baz\")" +snapshot_kind: text +--- +- What is baz?