mirror of https://github.com/astral-sh/ruff
add qualify code-action
This commit is contained in:
parent
bb464ed924
commit
72ef51b7bc
|
|
@ -38,6 +38,11 @@ pub fn code_actions(
|
||||||
{
|
{
|
||||||
actions.extend(import_quick_fix);
|
actions.extend(import_quick_fix);
|
||||||
}
|
}
|
||||||
|
if is_unresolved_reference
|
||||||
|
&& let Some(import_quick_fix) = create_qualify_symbol_quick_fix(db, file, diagnostic_range)
|
||||||
|
{
|
||||||
|
actions.extend(import_quick_fix);
|
||||||
|
}
|
||||||
|
|
||||||
// Suggest just suppressing the lint (always a valid option, but never ideal)
|
// Suggest just suppressing the lint (always a valid option, but never ideal)
|
||||||
actions.push(QuickFix {
|
actions.push(QuickFix {
|
||||||
|
|
@ -69,6 +74,26 @@ fn create_import_symbol_quick_fix(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_qualify_symbol_quick_fix(
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
diagnostic_range: TextRange,
|
||||||
|
) -> Option<impl Iterator<Item = QuickFix>> {
|
||||||
|
let parsed = parsed_module(db, file).load(db);
|
||||||
|
let node = covering_node(parsed.syntax().into(), diagnostic_range).node();
|
||||||
|
let symbol = &node.expr_name()?.id;
|
||||||
|
|
||||||
|
Some(
|
||||||
|
completion::missing_qualifications(db, file, &parsed, symbol, node)
|
||||||
|
.into_iter()
|
||||||
|
.map(|import| QuickFix {
|
||||||
|
title: import.label,
|
||||||
|
edits: vec![import.edit],
|
||||||
|
preferred: true,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,29 @@ impl<'db> Completions<'db> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn into_qualified(mut self, range: TextRange) -> Vec<ImportEdit> {
|
||||||
|
self.items.sort_by(compare_suggestions);
|
||||||
|
self.items
|
||||||
|
.dedup_by(|c1, c2| (&c1.name, c1.module_name) == (&c2.name, c2.module_name));
|
||||||
|
self.items
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|item| {
|
||||||
|
if item.import.is_none() {
|
||||||
|
Some(ImportEdit {
|
||||||
|
label: format!("qualify {}", item.insert.as_ref()?),
|
||||||
|
edit: Edit::replacement(
|
||||||
|
item.insert?.into_string(),
|
||||||
|
range.start(),
|
||||||
|
range.end(),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempts to adds the given completion to this collection.
|
/// Attempts to adds the given completion to this collection.
|
||||||
///
|
///
|
||||||
/// When added, `true` is returned.
|
/// When added, `true` is returned.
|
||||||
|
|
@ -578,6 +601,29 @@ pub(crate) fn missing_imports(
|
||||||
completions.into_imports()
|
completions.into_imports()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn missing_qualifications(
|
||||||
|
db: &dyn Db,
|
||||||
|
file: File,
|
||||||
|
parsed: &ParsedModuleRef,
|
||||||
|
symbol: &str,
|
||||||
|
node: AnyNodeRef,
|
||||||
|
) -> Vec<ImportEdit> {
|
||||||
|
let mut completions = Completions::exactly(db, symbol);
|
||||||
|
let scoped = ScopedTarget { node };
|
||||||
|
add_unimported_completions(
|
||||||
|
db,
|
||||||
|
file,
|
||||||
|
parsed,
|
||||||
|
scoped,
|
||||||
|
|module_name: &ModuleName, symbol: &str| {
|
||||||
|
ImportRequest::import(module_name.as_str(), symbol).force()
|
||||||
|
},
|
||||||
|
&mut completions,
|
||||||
|
);
|
||||||
|
|
||||||
|
completions.into_qualified(node.range())
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds completions derived from keywords.
|
/// Adds completions derived from keywords.
|
||||||
///
|
///
|
||||||
/// This should generally only be used when offering "scoped" completions.
|
/// This should generally only be used when offering "scoped" completions.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue