Skip to content

Commit 4bf2c35

Browse files
committed
fix(els): completion retrigger
1 parent 475eca9 commit 4bf2c35

File tree

5 files changed

+76
-37
lines changed

5 files changed

+76
-37
lines changed

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/els/completion.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use lsp_types::{
3232
};
3333

3434
use crate::server::{ELSResult, RedirectableStdout, Server};
35-
use crate::util::{self, NormalizedUrl};
35+
use crate::util::{self, loc_to_pos, NormalizedUrl};
3636

3737
fn comp_item_kind(vi: &VarInfo) -> CompletionItemKind {
3838
match &vi.t {
@@ -51,20 +51,21 @@ fn comp_item_kind(vi: &VarInfo) -> CompletionItemKind {
5151

5252
#[derive(Debug, PartialEq, Eq)]
5353
pub enum CompletionKind {
54+
RetriggerLocal,
5455
Local,
55-
Space,
5656
LParen,
5757
Method,
58+
RetriggerMethod,
5859
// Colon, // :, Type ascription or private access `::`
5960
}
6061

6162
impl CompletionKind {
6263
pub const fn should_be_local(&self) -> bool {
63-
matches!(self, Self::Local | Self::Space | Self::LParen)
64+
matches!(self, Self::RetriggerLocal | Self::Local | Self::LParen)
6465
}
6566

6667
pub const fn should_be_method(&self) -> bool {
67-
matches!(self, Self::Method)
68+
matches!(self, Self::Method | Self::RetriggerMethod)
6869
}
6970

7071
pub const fn _is_lparen(&self) -> bool {
@@ -493,7 +494,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
493494
self.send_log(format!("completion requested: {params:?}"))?;
494495
let uri = NormalizedUrl::new(params.text_document_position.text_document.uri);
495496
let path = util::uri_to_path(&uri);
496-
let pos = params.text_document_position.position;
497+
let mut pos = params.text_document_position.position;
497498
// ignore comments
498499
// TODO: multiline comments
499500
if self
@@ -510,32 +511,39 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
510511
let comp_kind = match trigger {
511512
Some(".") => CompletionKind::Method,
512513
Some(":") => CompletionKind::Method,
513-
Some(" ") => CompletionKind::Space,
514+
Some(" ") => CompletionKind::Local,
514515
Some("(") => CompletionKind::LParen,
515-
_ => CompletionKind::Local,
516+
_ => {
517+
let offset = match self.file_cache.get_token(&uri, pos).map(|tk| tk.kind) {
518+
Some(TokenKind::Newline | TokenKind::EOF) => -2,
519+
_ => -1,
520+
};
521+
let prev_token = self.file_cache.get_token_relatively(&uri, pos, offset);
522+
match prev_token {
523+
Some(prev) if matches!(prev.kind, Dot | DblColon) => {
524+
if let Some(p) = loc_to_pos(prev.loc()) {
525+
pos = p;
526+
}
527+
CompletionKind::RetriggerMethod
528+
}
529+
_ => CompletionKind::RetriggerLocal,
530+
}
531+
}
516532
};
517533
self.send_log(format!("CompletionKind: {comp_kind:?}"))?;
518534
let mut result: Vec<CompletionItem> = vec![];
519535
let mut already_appeared = Set::new();
520536
let contexts = if comp_kind.should_be_local() {
521-
let prev_token = self.file_cache.get_token_relatively(&uri, pos, -1);
522-
match prev_token {
523-
Some(prev) if matches!(prev.kind, Dot | DblColon) => {
524-
let Some(dot_pos) = util::loc_to_pos(prev.loc()) else {
525-
return Ok(None);
526-
};
527-
self.get_receiver_ctxs(&uri, dot_pos)?
528-
}
529-
_ => self.get_local_ctx(&uri, pos),
530-
}
537+
self.get_local_ctx(&uri, pos)
531538
} else {
532539
self.get_receiver_ctxs(&uri, pos)?
533540
};
534541
let offset = match comp_kind {
535-
CompletionKind::Local => 0,
542+
CompletionKind::RetriggerLocal => 0,
536543
CompletionKind::Method => -1,
537-
CompletionKind::Space => -1,
544+
CompletionKind::Local => -1,
538545
CompletionKind::LParen => 0,
546+
CompletionKind::RetriggerMethod => -1,
539547
};
540548
let arg_pt = self
541549
.get_min_expr(&uri, pos, offset)
@@ -547,7 +555,7 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
547555
let nth = nth + additional;
548556
sig_t.non_default_params()?.get(nth).cloned()
549557
}
550-
other if comp_kind == CompletionKind::Space => {
558+
other if comp_kind == CompletionKind::Local => {
551559
match other.show_acc().as_deref() {
552560
Some("import") => {
553561
let insert = other

crates/els/server.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
918918
self.shared.clear(&path);
919919
}
920920

921+
#[allow(unused)]
922+
pub fn get_file_cache(&self) -> &FileCache {
923+
&self.file_cache
924+
}
925+
921926
pub fn remove_module_entry(&mut self, uri: &NormalizedUrl) -> Option<ModuleEntry> {
922927
let path = uri.to_file_path().ok()?;
923928
self.shared.mod_cache.remove(&path)

crates/els/tests/retrigger.er

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
l = [1, 2]
2+
for! l, i =>
3+
pri
4+
print! i.bi

crates/els/tests/test.rs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const FILE_B: &str = "tests/b.er";
99
const FILE_C: &str = "tests/c.er";
1010
const FILE_IMPORTS: &str = "tests/imports.er";
1111
const FILE_INVALID_SYNTAX: &str = "tests/invalid_syntax.er";
12+
const FILE_RETRIGGER: &str = "tests/retrigger.er";
1213

1314
use els::{NormalizedUrl, Server};
1415
use erg_proc_macros::exec_new_thread;
@@ -68,6 +69,34 @@ fn test_neighbor_completion() -> Result<(), Box<dyn std::error::Error>> {
6869
}
6970
}
7071

72+
#[test]
73+
fn test_completion_retrigger() -> Result<(), Box<dyn std::error::Error>> {
74+
let mut client = Server::bind_fake_client();
75+
client.request_initialize()?;
76+
client.notify_initialized()?;
77+
let uri = NormalizedUrl::from_file_path(Path::new(FILE_RETRIGGER).canonicalize()?)?;
78+
client.notify_open(FILE_RETRIGGER)?;
79+
let _ = client.wait_diagnostics()?;
80+
client.notify_change(uri.clone().raw(), add_char(2, 7, "n"))?;
81+
let resp = client.request_completion(uri.clone().raw(), 2, 7, "n")?;
82+
if let Some(CompletionResponse::Array(items)) = resp {
83+
assert!(!items.is_empty());
84+
assert!(items.iter().any(|item| item.label == "print!"));
85+
} else {
86+
return Err(format!("not items: {resp:?}").into());
87+
}
88+
client.notify_change(uri.clone().raw(), add_char(3, 15, "t"))?;
89+
let resp = client.request_completion(uri.raw(), 3, 15, "t")?;
90+
if let Some(CompletionResponse::Array(items)) = resp {
91+
assert!(!items.is_empty());
92+
assert!(items.iter().any(|item| item.label == "bit_count"));
93+
assert!(items.iter().any(|item| item.label == "bit_length"));
94+
} else {
95+
return Err(format!("not items: {resp:?}").into());
96+
}
97+
Ok(())
98+
}
99+
71100
#[test]
72101
fn test_rename() -> Result<(), Box<dyn std::error::Error>> {
73102
let mut client = Server::bind_fake_client();
@@ -269,24 +298,17 @@ fn test_fix_error() -> Result<(), Box<dyn std::error::Error>> {
269298
let mut client = Server::bind_fake_client();
270299
client.request_initialize()?;
271300
client.notify_initialized()?;
272-
client.wait_messages(3)?;
273-
client.responses.clear();
274301
client.notify_open(FILE_INVALID_SYNTAX)?;
275-
client.wait_messages(6)?;
276-
let msg = client.responses.last().unwrap();
277-
let diags = PublishDiagnosticsParams::deserialize(&msg["params"])?;
302+
let diags = client.wait_diagnostics()?;
278303
assert_eq!(diags.diagnostics.len(), 1);
279304
assert_eq!(
280305
diags.diagnostics[0].severity,
281306
Some(DiagnosticSeverity::ERROR)
282307
);
283-
client.responses.clear();
284308
let uri = NormalizedUrl::from_file_path(Path::new(FILE_INVALID_SYNTAX).canonicalize()?)?;
285309
client.notify_change(uri.clone().raw(), add_char(0, 10, " 1"))?;
286310
client.notify_save(uri.clone().raw())?;
287-
client.wait_messages(4)?;
288-
let msg = client.responses.last().unwrap();
289-
let diags = PublishDiagnosticsParams::deserialize(&msg["params"])?;
311+
let diags = client.wait_diagnostics()?;
290312
assert_eq!(diags.diagnostics.len(), 0);
291313
Ok(())
292314
}

0 commit comments

Comments
 (0)