summaryrefslogtreecommitdiff
path: root/cli/lsp/completions.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2024-10-11 07:40:17 +0100
committerGitHub <noreply@github.com>2024-10-11 07:40:17 +0100
commit94b588ce6624ae2f2ed648c7b1a479a10513542f (patch)
treee9aa7437950d7b8f21f409ec3ec09642145424a0 /cli/lsp/completions.rs
parentccdbeb433b64fec409da2d541456ddf5a35ea4a4 (diff)
fix(lsp): relative completions for bare import-mapped specifiers (#26137)
Diffstat (limited to 'cli/lsp/completions.rs')
-rw-r--r--cli/lsp/completions.rs130
1 files changed, 63 insertions, 67 deletions
diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs
index a040be569..1590743b2 100644
--- a/cli/lsp/completions.rs
+++ b/cli/lsp/completions.rs
@@ -200,15 +200,11 @@ pub async fn get_import_completions(
{
// completions for import map specifiers
Some(lsp::CompletionResponse::List(completion_list))
- } else if text.starts_with("./")
- || text.starts_with("../")
- || text.starts_with('/')
+ } else if let Some(completion_list) =
+ get_local_completions(specifier, &text, &range, resolver)
{
// completions for local relative modules
- Some(lsp::CompletionResponse::List(CompletionList {
- is_incomplete: false,
- items: get_local_completions(specifier, &text, &range, resolver)?,
- }))
+ Some(lsp::CompletionResponse::List(completion_list))
} else if !text.is_empty() {
// completion of modules from a module registry or cache
check_auto_config_registry(
@@ -363,15 +359,15 @@ fn get_local_completions(
text: &str,
range: &lsp::Range,
resolver: &LspResolver,
-) -> Option<Vec<lsp::CompletionItem>> {
+) -> Option<CompletionList> {
if base.scheme() != "file" {
return None;
}
- let parent = base.join(text).ok()?.join(".").ok()?;
+ let parent = &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
let resolved_parent = resolver
.as_graph_resolver(Some(base))
.resolve(
- parent.as_str(),
+ parent,
&Range {
specifier: base.clone(),
start: deno_graph::Position::zeroed(),
@@ -381,62 +377,62 @@ fn get_local_completions(
)
.ok()?;
let resolved_parent_path = url_to_file_path(&resolved_parent).ok()?;
- let raw_parent =
- &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
if resolved_parent_path.is_dir() {
let cwd = std::env::current_dir().ok()?;
- let items = std::fs::read_dir(resolved_parent_path).ok()?;
- Some(
- items
- .filter_map(|de| {
- let de = de.ok()?;
- let label = de.path().file_name()?.to_string_lossy().to_string();
- let entry_specifier = resolve_path(de.path().to_str()?, &cwd).ok()?;
- if entry_specifier == *base {
- return None;
- }
- let full_text = format!("{raw_parent}{label}");
- let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
- range: *range,
- new_text: full_text.clone(),
- }));
- let filter_text = Some(full_text);
- match de.file_type() {
- Ok(file_type) if file_type.is_dir() => Some(lsp::CompletionItem {
- label,
- kind: Some(lsp::CompletionItemKind::FOLDER),
- detail: Some("(local)".to_string()),
- filter_text,
- sort_text: Some("1".to_string()),
- text_edit,
- commit_characters: Some(
- IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
- ),
- ..Default::default()
- }),
- Ok(file_type) if file_type.is_file() => {
- if is_importable_ext(&de.path()) {
- Some(lsp::CompletionItem {
- label,
- kind: Some(lsp::CompletionItemKind::FILE),
- detail: Some("(local)".to_string()),
- filter_text,
- sort_text: Some("1".to_string()),
- text_edit,
- commit_characters: Some(
- IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
- ),
- ..Default::default()
- })
- } else {
- None
- }
+ let entries = std::fs::read_dir(resolved_parent_path).ok()?;
+ let items = entries
+ .filter_map(|de| {
+ let de = de.ok()?;
+ let label = de.path().file_name()?.to_string_lossy().to_string();
+ let entry_specifier = resolve_path(de.path().to_str()?, &cwd).ok()?;
+ if entry_specifier == *base {
+ return None;
+ }
+ let full_text = format!("{parent}{label}");
+ let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ range: *range,
+ new_text: full_text.clone(),
+ }));
+ let filter_text = Some(full_text);
+ match de.file_type() {
+ Ok(file_type) if file_type.is_dir() => Some(lsp::CompletionItem {
+ label,
+ kind: Some(lsp::CompletionItemKind::FOLDER),
+ detail: Some("(local)".to_string()),
+ filter_text,
+ sort_text: Some("1".to_string()),
+ text_edit,
+ commit_characters: Some(
+ IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
+ ),
+ ..Default::default()
+ }),
+ Ok(file_type) if file_type.is_file() => {
+ if is_importable_ext(&de.path()) {
+ Some(lsp::CompletionItem {
+ label,
+ kind: Some(lsp::CompletionItemKind::FILE),
+ detail: Some("(local)".to_string()),
+ filter_text,
+ sort_text: Some("1".to_string()),
+ text_edit,
+ commit_characters: Some(
+ IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(),
+ ),
+ ..Default::default()
+ })
+ } else {
+ None
}
- _ => None,
}
- })
- .collect(),
- )
+ _ => None,
+ }
+ })
+ .collect();
+ Some(CompletionList {
+ is_incomplete: false,
+ items,
+ })
} else {
None
}
@@ -921,11 +917,11 @@ mod tests {
},
},
&Default::default(),
- );
- assert!(actual.is_some());
- let actual = actual.unwrap();
- assert_eq!(actual.len(), 3);
- for item in actual {
+ )
+ .unwrap();
+ assert!(!actual.is_incomplete);
+ assert_eq!(actual.items.len(), 3);
+ for item in actual.items {
match item.text_edit {
Some(lsp::CompletionTextEdit::Edit(text_edit)) => {
assert!(["./b", "./f.mjs", "./g.json"]