mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
fix: visibility completion
This commit is contained in:
parent
6c9fc4fec2
commit
1b5f0462ed
9 changed files with 103 additions and 57 deletions
|
@ -143,12 +143,15 @@ pub fn completions(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
|
trigger_character: Option<&str>,
|
||||||
) -> Option<Completions> {
|
) -> Option<Completions> {
|
||||||
let ctx = &CompletionContext::new(db, position, config)?;
|
let ctx = &CompletionContext::new(db, position, config)?;
|
||||||
let mut acc = Completions::default();
|
let mut acc = Completions::default();
|
||||||
|
|
||||||
{
|
{
|
||||||
let acc = &mut acc;
|
let acc = &mut acc;
|
||||||
|
// prevent `(` from triggering unwanted completion noise
|
||||||
|
if trigger_character != Some("(") {
|
||||||
completions::attribute::complete_attribute(acc, ctx);
|
completions::attribute::complete_attribute(acc, ctx);
|
||||||
completions::attribute::complete_derive(acc, ctx);
|
completions::attribute::complete_derive(acc, ctx);
|
||||||
completions::attribute::complete_known_attribute_input(acc, ctx);
|
completions::attribute::complete_known_attribute_input(acc, ctx);
|
||||||
|
@ -173,6 +176,7 @@ pub fn completions(
|
||||||
completions::r#type::complete_type_path(acc, ctx);
|
completions::r#type::complete_type_path(acc, ctx);
|
||||||
completions::r#type::complete_inferred_type(acc, ctx);
|
completions::r#type::complete_inferred_type(acc, ctx);
|
||||||
completions::use_::complete_use_tree(acc, ctx);
|
completions::use_::complete_use_tree(acc, ctx);
|
||||||
|
}
|
||||||
completions::vis::complete_vis_path(acc, ctx);
|
completions::vis::complete_vis_path(acc, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -410,7 +410,7 @@ mod tests {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
|
fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) {
|
||||||
let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
|
let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
|
||||||
actual.retain(|it| kinds.contains(&it.kind()));
|
actual.retain(|it| kinds.contains(&it.kind()));
|
||||||
actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
|
actual.sort_by_key(|it| cmp::Reverse(it.relevance().score()));
|
||||||
check_relevance_(actual, expect);
|
check_relevance_(actual, expect);
|
||||||
|
@ -418,7 +418,7 @@ mod tests {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn check_relevance(ra_fixture: &str, expect: Expect) {
|
fn check_relevance(ra_fixture: &str, expect: Expect) {
|
||||||
let mut actual = get_all_items(TEST_CONFIG, ra_fixture);
|
let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);
|
||||||
actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
|
actual.retain(|it| it.kind() != CompletionItemKind::Snippet);
|
||||||
actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
|
actual.retain(|it| it.kind() != CompletionItemKind::Keyword);
|
||||||
actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
|
actual.retain(|it| it.kind() != CompletionItemKind::BuiltinType);
|
||||||
|
|
|
@ -79,20 +79,28 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn completion_list(ra_fixture: &str) -> String {
|
pub(crate) fn completion_list(ra_fixture: &str) -> String {
|
||||||
completion_list_with_config(TEST_CONFIG, ra_fixture, true)
|
completion_list_with_config(TEST_CONFIG, ra_fixture, true, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
|
pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
|
||||||
completion_list_with_config(TEST_CONFIG, ra_fixture, false)
|
completion_list_with_config(TEST_CONFIG, ra_fixture, false, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn completion_list_with_trigger_character(
|
||||||
|
ra_fixture: &str,
|
||||||
|
trigger_character: Option<&str>,
|
||||||
|
) -> String {
|
||||||
|
completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completion_list_with_config(
|
fn completion_list_with_config(
|
||||||
config: CompletionConfig,
|
config: CompletionConfig,
|
||||||
ra_fixture: &str,
|
ra_fixture: &str,
|
||||||
include_keywords: bool,
|
include_keywords: bool,
|
||||||
|
trigger_character: Option<&str>,
|
||||||
) -> String {
|
) -> String {
|
||||||
// filter out all but one builtintype completion for smaller test outputs
|
// filter out all but one builtintype completion for smaller test outputs
|
||||||
let items = get_all_items(config, ra_fixture);
|
let items = get_all_items(config, ra_fixture, trigger_character);
|
||||||
let mut bt_seen = false;
|
let mut bt_seen = false;
|
||||||
let items = items
|
let items = items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -126,7 +134,7 @@ pub(crate) fn do_completion_with_config(
|
||||||
code: &str,
|
code: &str,
|
||||||
kind: CompletionItemKind,
|
kind: CompletionItemKind,
|
||||||
) -> Vec<CompletionItem> {
|
) -> Vec<CompletionItem> {
|
||||||
get_all_items(config, code)
|
get_all_items(config, code, None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|c| c.kind() == kind)
|
.filter(|c| c.kind() == kind)
|
||||||
.sorted_by(|l, r| l.label().cmp(r.label()))
|
.sorted_by(|l, r| l.label().cmp(r.label()))
|
||||||
|
@ -173,7 +181,7 @@ pub(crate) fn check_edit_with_config(
|
||||||
let ra_fixture_after = trim_indent(ra_fixture_after);
|
let ra_fixture_after = trim_indent(ra_fixture_after);
|
||||||
let (db, position) = position(ra_fixture_before);
|
let (db, position) = position(ra_fixture_before);
|
||||||
let completions: Vec<CompletionItem> =
|
let completions: Vec<CompletionItem> =
|
||||||
crate::completions(&db, &config, position).unwrap().into();
|
crate::completions(&db, &config, position, None).unwrap().into();
|
||||||
let (completion,) = completions
|
let (completion,) = completions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|it| it.lookup() == what)
|
.filter(|it| it.lookup() == what)
|
||||||
|
@ -214,9 +222,14 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: impl FnOnce(SyntaxE
|
||||||
assert!(check(NodeOrToken::Token(token)));
|
assert!(check(NodeOrToken::Token(token)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<CompletionItem> {
|
pub(crate) fn get_all_items(
|
||||||
|
config: CompletionConfig,
|
||||||
|
code: &str,
|
||||||
|
trigger_character: Option<&str>,
|
||||||
|
) -> Vec<CompletionItem> {
|
||||||
let (db, position) = position(code);
|
let (db, position) = position(code);
|
||||||
let res = crate::completions(&db, &config, position).map_or_else(Vec::default, Into::into);
|
let res = crate::completions(&db, &config, position, trigger_character)
|
||||||
|
.map_or_else(Vec::default, Into::into);
|
||||||
// validate
|
// validate
|
||||||
res.iter().for_each(|it| {
|
res.iter().for_each(|it| {
|
||||||
let sr = it.source_range();
|
let sr = it.source_range();
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
use crate::tests::completion_list;
|
use crate::tests::{completion_list, completion_list_with_trigger_character};
|
||||||
|
|
||||||
fn check(ra_fixture: &str, expect: Expect) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
let actual = completion_list(ra_fixture);
|
let actual = completion_list(ra_fixture);
|
||||||
expect.assert_eq(&actual);
|
expect.assert_eq(&actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_with_trigger_character(ra_fixture: &str, trigger_character: Option<&str>, expect: Expect) {
|
||||||
|
let actual = completion_list_with_trigger_character(ra_fixture, trigger_character);
|
||||||
|
expect.assert_eq(&actual)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_param() {
|
fn only_param() {
|
||||||
check(
|
check(
|
||||||
|
@ -113,6 +118,17 @@ fn outer(text: &str) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trigger_by_l_paren() {
|
||||||
|
check_with_trigger_character(
|
||||||
|
r#"
|
||||||
|
fn foo($0)
|
||||||
|
"#,
|
||||||
|
Some("("),
|
||||||
|
expect![[]],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shows_non_ident_pat_param() {
|
fn shows_non_ident_pat_param() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
//! Completion tests for visibility modifiers.
|
//! Completion tests for visibility modifiers.
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
use crate::tests::completion_list;
|
use crate::tests::{completion_list, completion_list_with_trigger_character};
|
||||||
|
|
||||||
fn check(ra_fixture: &str, expect: Expect) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
let actual = completion_list(ra_fixture);
|
let actual = completion_list(ra_fixture);
|
||||||
expect.assert_eq(&actual)
|
expect.assert_eq(&actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_with_trigger_character(ra_fixture: &str, trigger_character: Option<&str>, expect: Expect) {
|
||||||
|
let actual = completion_list_with_trigger_character(ra_fixture, trigger_character);
|
||||||
|
expect.assert_eq(&actual)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_pub() {
|
fn empty_pub() {
|
||||||
cov_mark::check!(kw_completion_in);
|
cov_mark::check!(kw_completion_in);
|
||||||
check(
|
check_with_trigger_character(
|
||||||
r#"
|
r#"
|
||||||
pub($0)
|
pub($0)
|
||||||
"#,
|
"#,
|
||||||
|
Some("("),
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
kw crate
|
kw crate
|
||||||
kw in
|
kw in
|
||||||
|
|
|
@ -547,8 +547,11 @@ impl Analysis {
|
||||||
&self,
|
&self,
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
|
trigger_character: Option<&str>,
|
||||||
) -> Cancellable<Option<Vec<CompletionItem>>> {
|
) -> Cancellable<Option<Vec<CompletionItem>>> {
|
||||||
self.with_db(|db| ide_completion::completions(db, config, position).map(Into::into))
|
self.with_db(|db| {
|
||||||
|
ide_completion::completions(db, config, position, trigger_character).map(Into::into)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves additional completion data at the position given.
|
/// Resolves additional completion data at the position given.
|
||||||
|
|
|
@ -29,7 +29,12 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
|
||||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||||
completion_provider: Some(CompletionOptions {
|
completion_provider: Some(CompletionOptions {
|
||||||
resolve_provider: completions_resolve_provider(config.caps()),
|
resolve_provider: completions_resolve_provider(config.caps()),
|
||||||
trigger_characters: Some(vec![":".to_string(), ".".to_string(), "'".to_string()]),
|
trigger_characters: Some(vec![
|
||||||
|
":".to_string(),
|
||||||
|
".".to_string(),
|
||||||
|
"'".to_string(),
|
||||||
|
"(".to_string(),
|
||||||
|
]),
|
||||||
all_commit_characters: None,
|
all_commit_characters: None,
|
||||||
completion_item: None,
|
completion_item: None,
|
||||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||||
|
|
|
@ -796,27 +796,26 @@ pub(crate) fn handle_completion(
|
||||||
let _p = profile::span("handle_completion");
|
let _p = profile::span("handle_completion");
|
||||||
let text_document_position = params.text_document_position.clone();
|
let text_document_position = params.text_document_position.clone();
|
||||||
let position = from_proto::file_position(&snap, params.text_document_position)?;
|
let position = from_proto::file_position(&snap, params.text_document_position)?;
|
||||||
let completion_triggered_after_single_colon = {
|
let completion_trigger_character = params.context.and_then(|ctx| ctx.trigger_character);
|
||||||
let mut res = false;
|
|
||||||
if let Some(ctx) = params.context {
|
if Some(":") == completion_trigger_character.as_deref() {
|
||||||
if ctx.trigger_character.as_deref() == Some(":") {
|
|
||||||
let source_file = snap.analysis.parse(position.file_id)?;
|
let source_file = snap.analysis.parse(position.file_id)?;
|
||||||
let left_token =
|
let left_token = source_file.syntax().token_at_offset(position.offset).left_biased();
|
||||||
source_file.syntax().token_at_offset(position.offset).left_biased();
|
let completion_triggered_after_single_colon = match left_token {
|
||||||
match left_token {
|
Some(left_token) => left_token.kind() == T![:],
|
||||||
Some(left_token) => res = left_token.kind() == T![:],
|
None => true,
|
||||||
None => res = true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
};
|
};
|
||||||
if completion_triggered_after_single_colon {
|
if completion_triggered_after_single_colon {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let completion_config = &snap.config.completion();
|
let completion_config = &snap.config.completion();
|
||||||
let items = match snap.analysis.completions(completion_config, position)? {
|
let items = match snap.analysis.completions(
|
||||||
|
completion_config,
|
||||||
|
position,
|
||||||
|
completion_trigger_character.as_deref(),
|
||||||
|
)? {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(items) => items,
|
Some(items) => items,
|
||||||
};
|
};
|
||||||
|
|
|
@ -148,7 +148,7 @@ fn integrated_completion_benchmark() {
|
||||||
};
|
};
|
||||||
let position =
|
let position =
|
||||||
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
||||||
analysis.completions(&config, position).unwrap();
|
analysis.completions(&config, position, None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let completion_offset = {
|
let completion_offset = {
|
||||||
|
@ -185,7 +185,7 @@ fn integrated_completion_benchmark() {
|
||||||
};
|
};
|
||||||
let position =
|
let position =
|
||||||
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
||||||
analysis.completions(&config, position).unwrap();
|
analysis.completions(&config, position, None).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue