From 284483b347d15bee3a7bf293d33e5f19a9740102 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Sun, 30 May 2021 14:52:19 +0100 Subject: Improve completion of cfg attributes The completion of cfg will look at the enabled cfg keys when performing completion. It will also look crate features when completing a feature cfg option. A fixed list of known values for some cfg options are provided. For unknown keys it will look at the enabled values for that cfg key, which means that completion will only show enabled options for those. --- crates/ide_completion/src/completions/attribute.rs | 15 +++ .../src/completions/attribute/cfg.rs | 126 +++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 crates/ide_completion/src/completions/attribute/cfg.rs (limited to 'crates/ide_completion') diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 78fc30e16..cc4f4b2af 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -15,6 +15,7 @@ use crate::{ Completions, }; +mod cfg; mod derive; mod lint; mod repr; @@ -30,6 +31,9 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS); lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); } + "cfg" => { + cfg::complete_cfg(acc, ctx); + } _ => (), }, (None, Some(_)) => (), @@ -852,4 +856,15 @@ mod tests { "#]], ); } + + #[test] + fn test_cfg() { + check( + r#"#[cfg(target_endian = $0"#, + expect![[r#" + at little + at big +"#]], + ); + } } diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs new file mode 100644 index 000000000..71e659563 --- /dev/null +++ b/crates/ide_completion/src/completions/attribute/cfg.rs @@ -0,0 +1,126 @@ +//! Completion for cfg + +use std::iter; + +use syntax::SyntaxKind; + +use crate::{ + completions::Completions, context::CompletionContext, item::CompletionKind, CompletionItem, + CompletionItemKind, +}; + +pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) { + let add_completion = |item: &&str| { + let mut completion = + CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), *item); + completion.insert_text(format!(r#""{}""#, item)); + completion.kind(CompletionItemKind::Attribute); + acc.add(completion.build()); + }; + + let previous = iter::successors(ctx.original_token.prev_token(), |t| { + (matches!(t.kind(), SyntaxKind::EQ) || t.kind().is_trivia()) + .then(|| t.prev_token()) + .flatten() + }) + .find(|t| matches!(t.kind(), SyntaxKind::IDENT)); + + match previous.as_ref().map(|p| p.text()) { + Some("feature") => { + ctx.krate.map(|krate| { + krate.features(ctx.db).iter().for_each(|f| { + let mut item = CompletionItem::new( + CompletionKind::Attribute, + ctx.source_range(), + f.clone(), + ); + item.insert_text(format!(r#""{}""#, f)); + + acc.add(item.build()) + }) + }); + } + Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion), + Some("target_env") => KNOWN_ENV.iter().for_each(add_completion), + Some("target_os") => KNOWN_OS.iter().for_each(add_completion), + Some("target_vendor") => KNOWN_VENDOR.iter().for_each(add_completion), + Some("target_endian") => ["little", "big"].iter().for_each(add_completion), + Some(name) => { + ctx.krate.map(|krate| { + krate.cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| { + let mut item = CompletionItem::new( + CompletionKind::Attribute, + ctx.source_range(), + s.as_str(), + ); + item.insert_text(format!(r#""{}""#, s)); + + acc.add(item.build()); + }) + }); + } + None => { + ctx.krate.map(|krate| { + krate.cfg(ctx.db).get_cfg_keys().iter().for_each(|s| { + let item = CompletionItem::new( + CompletionKind::Attribute, + ctx.source_range(), + s.as_str(), + ); + acc.add(item.build()); + }) + }); + } + }; +} + +const KNOWN_ARCH: [&'static str; 19] = [ + "aarch64", + "arm", + "avr", + "hexagon", + "mips", + "mips64", + "msp430", + "nvptx64", + "powerpc", + "powerpc64", + "riscv32", + "riscv64", + "s390x", + "sparc", + "sparc64", + "wasm32", + "wasm64", + "x86", + "x86_64", +]; + +const KNOWN_ENV: [&'static str; 7] = + ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; + +const KNOWN_OS: [&'static str; 20] = [ + "cuda", + "dragonfly", + "emscripten", + "freebsd", + "fuchsia", + "haiku", + "hermit", + "illumos", + "l4re", + "linux", + "netbsd", + "none", + "openbsd", + "psp", + "redox", + "solaris", + "uefi", + "unknown", + "vxworks", + "windows", +]; + +const KNOWN_VENDOR: [&'static str; 8] = + ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"]; -- cgit v1.2.3 From ae823aa23f1c4fa55e71dd972d0b10c69148b0b4 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Mon, 31 May 2021 20:45:01 +0100 Subject: Move features into potential_cfg_options --- crates/ide_completion/src/completions/attribute/cfg.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'crates/ide_completion') diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs index 71e659563..847e6529a 100644 --- a/crates/ide_completion/src/completions/attribute/cfg.rs +++ b/crates/ide_completion/src/completions/attribute/cfg.rs @@ -26,20 +26,6 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) { .find(|t| matches!(t.kind(), SyntaxKind::IDENT)); match previous.as_ref().map(|p| p.text()) { - Some("feature") => { - ctx.krate.map(|krate| { - krate.features(ctx.db).iter().for_each(|f| { - let mut item = CompletionItem::new( - CompletionKind::Attribute, - ctx.source_range(), - f.clone(), - ); - item.insert_text(format!(r#""{}""#, f)); - - acc.add(item.build()) - }) - }); - } Some("target_arch") => KNOWN_ARCH.iter().for_each(add_completion), Some("target_env") => KNOWN_ENV.iter().for_each(add_completion), Some("target_os") => KNOWN_OS.iter().for_each(add_completion), @@ -47,7 +33,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) { Some("target_endian") => ["little", "big"].iter().for_each(add_completion), Some(name) => { ctx.krate.map(|krate| { - krate.cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| { + krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| { let mut item = CompletionItem::new( CompletionKind::Attribute, ctx.source_range(), @@ -61,7 +47,7 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) { } None => { ctx.krate.map(|krate| { - krate.cfg(ctx.db).get_cfg_keys().iter().for_each(|s| { + krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| { let item = CompletionItem::new( CompletionKind::Attribute, ctx.source_range(), -- cgit v1.2.3