Skip to content

Commit 49f1186

Browse files
committed
Merge #172: LSP: refactor completions, add specific type cast completions
7d4e59d Fixed the typo in the LSP completion strategy (Kyryl R) 037b447 move handling completion types to nom parser (Volodymyr Herashchenko) f203221 bump lsp crate version to 0.2.1 (Volodymyr Herashchenko) 9725182 add separate tokenizer for completions (Volodymyr Herashchenko) Pull request description: ACKs for top commit: KyrylR: ACK 7d4e59d Tree-SHA512: d18df2563085d62c433bc4405104c37348744214977106b1869a49e10b4d8d396627df79107c3fae74ec29e908db5543e60d78741b7ea4f0d9c074a652054ad8
2 parents 999b3ee + 7d4e59d commit 49f1186

File tree

5 files changed

+354
-40
lines changed

5 files changed

+354
-40
lines changed

lsp/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "simplicityhl-lsp"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2021"
55
rust-version = "1.79"
66
description = "Language Server Protocol (LSP) server for SimplicityHL."
@@ -22,6 +22,8 @@ thiserror = "2.0.17"
2222
ropey = "1.6.1"
2323
miniscript = "12"
2424
simplicityhl = { version = "0.3.0" }
25+
nom = "8.0.0"
26+
lazy_static = "1.5.0"
2527

2628
[lints.rust]
2729
unsafe_code = "deny"

lsp/src/backend.rs

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl LanguageServer for Backend {
7474
)),
7575
completion_provider: Some(CompletionOptions {
7676
resolve_provider: Some(false),
77-
trigger_characters: Some(vec![":".to_string()]),
77+
trigger_characters: Some(vec![":".to_string(), "<".to_string()]),
7878
work_done_progress_options: WorkDoneProgressOptions::default(),
7979
all_commit_characters: None,
8080
completion_item: None,
@@ -174,30 +174,12 @@ impl LanguageServer for Backend {
174174
"RopeSlice to str conversion failed".into(),
175175
))?;
176176

177-
let trimmed_prefix = prefix.trim_end();
178-
179-
if let Some(last) = trimmed_prefix
180-
.rsplit(|c: char| !c.is_alphanumeric() && c != ':')
181-
.next()
182-
{
183-
if last.starts_with("jet:::") {
184-
return Ok(Some(CompletionResponse::Array(vec![])));
185-
} else if last == "jet::" || last.starts_with("jet::") {
186-
return Ok(Some(CompletionResponse::Array(
187-
self.completion_provider.jets().to_vec(),
188-
)));
189-
}
190-
// Completion after a colon is needed only for jets.
191-
} else if trimmed_prefix.ends_with(':') {
192-
return Ok(Some(CompletionResponse::Array(vec![])));
193-
}
194-
195-
let mut completions =
196-
CompletionProvider::get_function_completions(&doc.functions.functions_and_docs());
197-
completions.extend_from_slice(self.completion_provider.builtins());
198-
completions.extend_from_slice(self.completion_provider.modules());
177+
let completions = self
178+
.completion_provider
179+
.process_completions(prefix, &doc.functions.functions_and_docs())
180+
.map(CompletionResponse::Array);
199181

200-
Ok(Some(CompletionResponse::Array(completions)))
182+
Ok(completions)
201183
}
202184

203185
async fn hover(&self, params: HoverParams) -> Result<Option<Hover>> {

lsp/src/completion/mod.rs

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ use simplicityhl::parse::Function;
22

33
pub mod builtin;
44
pub mod jet;
5+
pub mod tokens;
6+
pub mod type_cast;
57
pub mod types;
68

79
use tower_lsp_server::lsp_types::{
810
CompletionItem, CompletionItemKind, Documentation, InsertTextFormat, MarkupContent, MarkupKind,
911
};
1012

13+
use tokens::parse;
14+
use tokens::CompletionType;
15+
1116
/// Build and provide [`CompletionItem`] for jets and builtin functions.
1217
#[derive(Debug)]
1318
pub struct CompletionProvider {
@@ -19,6 +24,9 @@ pub struct CompletionProvider {
1924

2025
/// Modules completions.
2126
modules: Vec<CompletionItem>,
27+
28+
/// Default Type cast completions.
29+
type_casts: Vec<CompletionItem>,
2230
}
2331

2432
impl CompletionProvider {
@@ -41,28 +49,28 @@ impl CompletionProvider {
4149
.iter()
4250
.map(|(module, detail)| module_to_completion((*module).to_string(), (*detail).to_string()))
4351
.collect();
52+
53+
let type_casts_completion = type_cast::TYPE_CASTS
54+
.iter()
55+
.map(|(&to, &from)| CompletionItem {
56+
label: format!("{to} <- {from}"),
57+
kind: Some(CompletionItemKind::FUNCTION),
58+
detail: Some(format!("Cast into type `{to}`",)),
59+
documentation: None,
60+
insert_text: Some(format!("{from}>::into(${{1:{from}}})")),
61+
insert_text_format: Some(InsertTextFormat::SNIPPET),
62+
..Default::default()
63+
})
64+
.collect::<Vec<_>>();
65+
4466
Self {
4567
jets: jets_completion,
4668
builtin: builtin_completion,
4769
modules: modules_completion,
70+
type_casts: type_casts_completion,
4871
}
4972
}
5073

51-
/// Return jets completions.
52-
pub fn jets(&self) -> &[CompletionItem] {
53-
&self.jets
54-
}
55-
56-
/// Return builtin functions completions.
57-
pub fn builtins(&self) -> &[CompletionItem] {
58-
&self.builtin
59-
}
60-
61-
/// Return builtin functions completions.
62-
pub fn modules(&self) -> &[CompletionItem] {
63-
&self.modules
64-
}
65-
6674
/// Get generic functions completions.
6775
pub fn get_function_completions(functions: &[(&Function, &str)]) -> Vec<CompletionItem> {
6876
functions
@@ -73,6 +81,57 @@ impl CompletionProvider {
7381
})
7482
.collect()
7583
}
84+
85+
/// Return completions based on line and functions provided.
86+
pub fn process_completions(
87+
&self,
88+
prefix: &str,
89+
functions: &[(&Function, &str)],
90+
) -> Option<Vec<CompletionItem>> {
91+
let completion_type = parse(prefix)?;
92+
93+
match completion_type {
94+
CompletionType::Jet => Some(self.jets.clone()),
95+
96+
CompletionType::Assignment(type_name) => {
97+
let to = type_name.as_str();
98+
99+
if let Some(from) = type_cast::TYPE_CASTS.get(to) {
100+
return Some(vec![CompletionItem {
101+
label: format!("{to} <- {from}"),
102+
kind: Some(CompletionItemKind::FUNCTION),
103+
detail: Some(format!("Cast into type `{to}`",)),
104+
documentation: None,
105+
insert_text: Some(format!("{from}>::into(${{1:{from}}})")),
106+
insert_text_format: Some(InsertTextFormat::SNIPPET),
107+
..Default::default()
108+
}]);
109+
}
110+
Some(self.type_casts.clone())
111+
}
112+
113+
CompletionType::ClosingType => Some(vec![CompletionItem {
114+
label: "into".to_string(),
115+
kind: Some(CompletionItemKind::FUNCTION),
116+
detail: Some("Cast into type".to_string()),
117+
documentation: None,
118+
insert_text: Some("into(${1:type})".to_string()),
119+
insert_text_format: Some(InsertTextFormat::SNIPPET),
120+
..Default::default()
121+
}]),
122+
123+
CompletionType::NonCompletionSymbol => None,
124+
125+
_ => {
126+
let mut completions = CompletionProvider::get_function_completions(functions);
127+
128+
completions.extend_from_slice(&self.builtin);
129+
completions.extend_from_slice(&self.modules);
130+
131+
Some(completions)
132+
}
133+
}
134+
}
76135
}
77136

78137
/// Convert [`simplicityhl::parse::Function`] to [`types::FunctionTemplate`].

0 commit comments

Comments
 (0)