Skip to content

Commit ce0f9a9

Browse files
John Van Schultzmeta-codesync[bot]
authored andcommitted
Move add_autoimport_completions into completions module.
Summary: Moves add_autoimport_completions to the completion module. Reviewed By: yangdanny97 Differential Revision: D91782195 fbshipit-source-id: 455bdcfaafc381aca06bc9fda0cc0c0409738110
1 parent 499066b commit ce0f9a9

File tree

2 files changed

+116
-109
lines changed

2 files changed

+116
-109
lines changed

pyrefly/lib/lsp/wasm/completion.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
use dupe::Dupe;
89
use fuzzy_matcher::FuzzyMatcher;
910
use fuzzy_matcher::skim::SkimMatcherV2;
1011
use lsp_types::CompletionItem;
1112
use lsp_types::CompletionItemKind;
13+
use lsp_types::CompletionItemLabelDetails;
1214
use lsp_types::CompletionItemTag;
15+
use lsp_types::TextEdit;
1316
use pyrefly_build::handle::Handle;
1417
use pyrefly_python::docstring::Docstring;
1518
use pyrefly_python::dunder;
@@ -19,13 +22,18 @@ use pyrefly_types::literal::Lit;
1922
use pyrefly_types::types::Union;
2023
use ruff_python_ast::Identifier;
2124
use ruff_text_size::Ranged;
25+
use ruff_text_size::TextRange;
2226
use ruff_text_size::TextSize;
2327

2428
use crate::alt::attr::AttrInfo;
2529
use crate::binding::binding::Key;
2630
use crate::export::exports::Export;
2731
use crate::export::exports::ExportLocation;
32+
use crate::state::ide::import_regular_import_edit;
33+
use crate::state::ide::insert_import_edit;
2834
use crate::state::lsp::FindPreference;
35+
use crate::state::lsp::ImportFormat;
36+
use crate::state::lsp::MIN_CHARACTERS_TYPED_AUTOIMPORT;
2937
use crate::state::state::Transaction;
3038
use crate::types::callable::Param;
3139
use crate::types::types::Type;
@@ -316,4 +324,111 @@ impl Transaction<'_> {
316324
);
317325
}
318326
}
327+
328+
/// Adds auto-import completions from exports of other modules using fuzzy matching.
329+
pub(crate) fn add_autoimport_completions(
330+
&self,
331+
handle: &Handle,
332+
identifier: &Identifier,
333+
completions: &mut Vec<CompletionItem>,
334+
import_format: ImportFormat,
335+
supports_completion_item_details: bool,
336+
) {
337+
// Auto-import can be slow. Let's only return results if there are no local
338+
// results for now. TODO: re-enable it once we no longer have perf issues.
339+
// We should not try to generate autoimport when the user has typed very few
340+
// characters. It's unhelpful to narrow down suggestions.
341+
if identifier.as_str().len() >= MIN_CHARACTERS_TYPED_AUTOIMPORT
342+
&& let Some(ast) = self.get_ast(handle)
343+
&& let Some(module_info) = self.get_module_info(handle)
344+
{
345+
for (handle_to_import_from, name, export) in
346+
self.search_exports_fuzzy(identifier.as_str())
347+
{
348+
// Using handle itself doesn't always work because handles can be made separately and have different hashes
349+
if handle_to_import_from.module() == handle.module()
350+
|| handle_to_import_from.module() == ModuleName::builtins()
351+
{
352+
continue;
353+
}
354+
let depth = handle_to_import_from.module().components().len();
355+
let module_description = handle_to_import_from.module().as_str().to_owned();
356+
let (insert_text, additional_text_edits, imported_module) = {
357+
let (position, insert_text, module_name) = insert_import_edit(
358+
&ast,
359+
self.config_finder(),
360+
handle.dupe(),
361+
handle_to_import_from,
362+
&name,
363+
import_format,
364+
);
365+
let import_text_edit = TextEdit {
366+
range: module_info.to_lsp_range(TextRange::at(position, TextSize::new(0))),
367+
new_text: insert_text.clone(),
368+
};
369+
(insert_text, Some(vec![import_text_edit]), module_name)
370+
};
371+
let auto_import_label_detail = format!(" (import {imported_module})");
372+
373+
completions.push(CompletionItem {
374+
label: name,
375+
detail: Some(insert_text),
376+
kind: export
377+
.symbol_kind
378+
.map_or(Some(CompletionItemKind::VARIABLE), |k| {
379+
Some(k.to_lsp_completion_item_kind())
380+
}),
381+
additional_text_edits,
382+
label_details: supports_completion_item_details.then_some(
383+
CompletionItemLabelDetails {
384+
detail: Some(auto_import_label_detail),
385+
description: Some(module_description),
386+
},
387+
),
388+
tags: if export.deprecation.is_some() {
389+
Some(vec![CompletionItemTag::DEPRECATED])
390+
} else {
391+
None
392+
},
393+
sort_text: Some(format!("4{}", depth)),
394+
..Default::default()
395+
});
396+
}
397+
398+
for module_name in self.search_modules_fuzzy(identifier.as_str()) {
399+
if module_name == handle.module() {
400+
continue;
401+
}
402+
let module_name_str = module_name.as_str().to_owned();
403+
if let Some(module_handle) = self.import_handle(handle, module_name, None).finding()
404+
{
405+
let (insert_text, additional_text_edits) = {
406+
let (position, insert_text) =
407+
import_regular_import_edit(&ast, module_handle);
408+
let import_text_edit = TextEdit {
409+
range: module_info
410+
.to_lsp_range(TextRange::at(position, TextSize::new(0))),
411+
new_text: insert_text.clone(),
412+
};
413+
(insert_text, Some(vec![import_text_edit]))
414+
};
415+
let auto_import_label_detail = format!(" (import {module_name_str})");
416+
417+
completions.push(CompletionItem {
418+
label: module_name_str.clone(),
419+
detail: Some(insert_text),
420+
kind: Some(CompletionItemKind::MODULE),
421+
additional_text_edits,
422+
label_details: supports_completion_item_details.then_some(
423+
CompletionItemLabelDetails {
424+
detail: Some(auto_import_label_detail),
425+
description: Some(module_name_str),
426+
},
427+
),
428+
..Default::default()
429+
});
430+
}
431+
}
432+
}
433+
}
319434
}

pyrefly/lib/state/lsp.rs

Lines changed: 1 addition & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ use fuzzy_matcher::skim::SkimMatcherV2;
1616
use itertools::Itertools;
1717
use lsp_types::CompletionItem;
1818
use lsp_types::CompletionItemKind;
19-
use lsp_types::CompletionItemLabelDetails;
2019
use lsp_types::CompletionItemTag;
21-
use lsp_types::TextEdit;
2220
use pyrefly_build::handle::Handle;
2321
use pyrefly_python::ast::Ast;
2422
use pyrefly_python::docstring::Docstring;
@@ -1845,7 +1843,7 @@ impl<'a> Transaction<'a> {
18451843
.map(|item| TextRangeWithModule::new(item.module, item.definition_range))
18461844
}
18471845

1848-
fn search_modules_fuzzy(&self, pattern: &str) -> Vec<ModuleName> {
1846+
pub(crate) fn search_modules_fuzzy(&self, pattern: &str) -> Vec<ModuleName> {
18491847
let matcher = SkimMatcherV2::default().smart_case();
18501848
let mut results = Vec::new();
18511849

@@ -2589,112 +2587,6 @@ impl<'a> Transaction<'a> {
25892587
Some(references)
25902588
}
25912589

2592-
fn add_autoimport_completions(
2593-
&self,
2594-
handle: &Handle,
2595-
identifier: &Identifier,
2596-
completions: &mut Vec<CompletionItem>,
2597-
import_format: ImportFormat,
2598-
supports_completion_item_details: bool,
2599-
) {
2600-
// Auto-import can be slow. Let's only return results if there are no local
2601-
// results for now. TODO: re-enable it once we no longer have perf issues.
2602-
// We should not try to generate autoimport when the user has typed very few
2603-
// characters. It's unhelpful to narrow down suggestions.
2604-
if identifier.as_str().len() >= MIN_CHARACTERS_TYPED_AUTOIMPORT
2605-
&& let Some(ast) = self.get_ast(handle)
2606-
&& let Some(module_info) = self.get_module_info(handle)
2607-
{
2608-
for (handle_to_import_from, name, export) in
2609-
self.search_exports_fuzzy(identifier.as_str())
2610-
{
2611-
// Using handle itself doesn't always work because handles can be made separately and have different hashes
2612-
if handle_to_import_from.module() == handle.module()
2613-
|| handle_to_import_from.module() == ModuleName::builtins()
2614-
{
2615-
continue;
2616-
}
2617-
let depth = handle_to_import_from.module().components().len();
2618-
let module_description = handle_to_import_from.module().as_str().to_owned();
2619-
let (insert_text, additional_text_edits, imported_module) = {
2620-
let (position, insert_text, module_name) = insert_import_edit(
2621-
&ast,
2622-
self.config_finder(),
2623-
handle.dupe(),
2624-
handle_to_import_from,
2625-
&name,
2626-
import_format,
2627-
);
2628-
let import_text_edit = TextEdit {
2629-
range: module_info.to_lsp_range(TextRange::at(position, TextSize::new(0))),
2630-
new_text: insert_text.clone(),
2631-
};
2632-
(insert_text, Some(vec![import_text_edit]), module_name)
2633-
};
2634-
let auto_import_label_detail = format!(" (import {imported_module})");
2635-
2636-
completions.push(CompletionItem {
2637-
label: name,
2638-
detail: Some(insert_text),
2639-
kind: export
2640-
.symbol_kind
2641-
.map_or(Some(CompletionItemKind::VARIABLE), |k| {
2642-
Some(k.to_lsp_completion_item_kind())
2643-
}),
2644-
additional_text_edits,
2645-
label_details: supports_completion_item_details.then_some(
2646-
CompletionItemLabelDetails {
2647-
detail: Some(auto_import_label_detail),
2648-
description: Some(module_description),
2649-
},
2650-
),
2651-
tags: if export.deprecation.is_some() {
2652-
Some(vec![CompletionItemTag::DEPRECATED])
2653-
} else {
2654-
None
2655-
},
2656-
sort_text: Some(format!("4{}", depth)),
2657-
..Default::default()
2658-
});
2659-
}
2660-
2661-
for module_name in self.search_modules_fuzzy(identifier.as_str()) {
2662-
if module_name == handle.module() {
2663-
continue;
2664-
}
2665-
let module_name_str = module_name.as_str().to_owned();
2666-
if let Some(module_handle) = self.import_handle(handle, module_name, None).finding()
2667-
{
2668-
let (insert_text, additional_text_edits) = {
2669-
let (position, insert_text) =
2670-
import_regular_import_edit(&ast, module_handle);
2671-
let import_text_edit = TextEdit {
2672-
range: module_info
2673-
.to_lsp_range(TextRange::at(position, TextSize::new(0))),
2674-
new_text: insert_text.clone(),
2675-
};
2676-
(insert_text, Some(vec![import_text_edit]))
2677-
};
2678-
let auto_import_label_detail = format!(" (import {module_name_str})");
2679-
2680-
completions.push(CompletionItem {
2681-
label: module_name_str.clone(),
2682-
detail: Some(insert_text),
2683-
kind: Some(CompletionItemKind::MODULE),
2684-
additional_text_edits,
2685-
label_details: supports_completion_item_details.then_some(
2686-
CompletionItemLabelDetails {
2687-
detail: Some(auto_import_label_detail),
2688-
description: Some(module_name_str),
2689-
},
2690-
),
2691-
..Default::default()
2692-
});
2693-
}
2694-
}
2695-
}
2696-
}
2697-
26982590
// Kept for backwards compatibility - used by external callers (lsp/server.rs, playground.rs)
26992591
// who don't need the is_incomplete flag
27002592
pub fn completion(

0 commit comments

Comments
 (0)