Skip to main content

ide_completion/completions/attribute/
cfg.rs

1//! Completion for cfg
2
3use ide_db::SymbolKind;
4use itertools::Itertools;
5use syntax::{AstToken, Direction, NodeOrToken, SmolStr, SyntaxKind, algo, ast::Ident};
6
7use crate::{CompletionItem, completions::Completions, context::CompletionContext};
8
9pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_, '_>) {
10    let add_completion = |item: &str| {
11        let mut completion =
12            CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item, ctx.edition);
13        completion.insert_text(format!(r#""{item}""#));
14        completion.add_to(acc, ctx.db);
15    };
16
17    // FIXME: Move this into context/analysis.rs
18    let previous = ctx
19        .original_token
20        .prev_token()
21        .and_then(|it| {
22            if matches!(it.kind(), SyntaxKind::EQ) {
23                Some(it.into())
24            } else {
25                algo::non_trivia_sibling(it.into(), Direction::Prev)
26            }
27        })
28        .filter(|t| matches!(t.kind(), SyntaxKind::EQ))
29        .and_then(|it| algo::non_trivia_sibling(it.prev_sibling_or_token()?, Direction::Prev))
30        .map(|it| match it {
31            NodeOrToken::Node(_) => None,
32            NodeOrToken::Token(t) => Ident::cast(t),
33        });
34    match previous {
35        Some(None) => (),
36        Some(Some(p)) => match p.text() {
37            "target_arch" => KNOWN_ARCH.iter().copied().for_each(add_completion),
38            "target_env" => KNOWN_ENV.iter().copied().for_each(add_completion),
39            "target_os" => KNOWN_OS.iter().copied().for_each(add_completion),
40            "target_vendor" => KNOWN_VENDOR.iter().copied().for_each(add_completion),
41            "target_endian" => ["little", "big"].into_iter().for_each(add_completion),
42            name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).for_each(|s| {
43                let s = s.as_str();
44                let insert_text = format!(r#""{s}""#);
45                let mut item = CompletionItem::new(
46                    SymbolKind::BuiltinAttr,
47                    ctx.source_range(),
48                    s,
49                    ctx.edition,
50                );
51                item.insert_text(insert_text);
52                item.add_to(acc, ctx.db);
53            }),
54        },
55        None => ctx
56            .krate
57            .potential_cfg(ctx.db)
58            .into_iter()
59            .map(|x| match x {
60                hir::CfgAtom::Flag(key) => (key.as_str(), "".into()),
61                hir::CfgAtom::KeyValue { key, .. } => (
62                    key.as_str(),
63                    if ctx.config.snippet_cap.is_some() {
64                        SmolStr::from_iter([key.as_str(), " = $0"])
65                    } else {
66                        SmolStr::default()
67                    },
68                ),
69            })
70            .chain(CFG_CONDITION.iter().map(|&(k, snip)| (k, SmolStr::new_static(snip))))
71            .unique_by(|&(s, _)| s)
72            .for_each(|(s, snippet)| {
73                let mut item = CompletionItem::new(
74                    SymbolKind::BuiltinAttr,
75                    ctx.source_range(),
76                    s,
77                    ctx.edition,
78                );
79                if let Some(cap) = ctx.config.snippet_cap
80                    && !snippet.is_empty()
81                {
82                    item.insert_snippet(cap, snippet);
83                }
84                item.add_to(acc, ctx.db);
85            }),
86    }
87}
88
89const CFG_CONDITION: &[(&str, &str)] =
90    &[("all", "all($0)"), ("any", "any($0)"), ("not", "not($0)")];
91
92const KNOWN_ARCH: [&str; 20] = [
93    "aarch64",
94    "arm",
95    "avr",
96    "csky",
97    "hexagon",
98    "mips",
99    "mips64",
100    "msp430",
101    "nvptx64",
102    "powerpc",
103    "powerpc64",
104    "riscv32",
105    "riscv64",
106    "s390x",
107    "sparc",
108    "sparc64",
109    "wasm32",
110    "wasm64",
111    "x86",
112    "x86_64",
113];
114
115const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];
116
117const KNOWN_OS: [&str; 20] = [
118    "cuda",
119    "dragonfly",
120    "emscripten",
121    "freebsd",
122    "fuchsia",
123    "haiku",
124    "hermit",
125    "illumos",
126    "l4re",
127    "linux",
128    "netbsd",
129    "none",
130    "openbsd",
131    "psp",
132    "redox",
133    "solaris",
134    "uefi",
135    "unknown",
136    "vxworks",
137    "windows",
138];
139
140const KNOWN_VENDOR: [&str; 8] =
141    ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];