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        acc.add(completion.build(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
53                acc.add(item.build(ctx.db));
54            }),
55        },
56        None => ctx
57            .krate
58            .potential_cfg(ctx.db)
59            .into_iter()
60            .map(|x| match x {
61                hir::CfgAtom::Flag(key) => (key.as_str(), "".into()),
62                hir::CfgAtom::KeyValue { key, .. } => (
63                    key.as_str(),
64                    if ctx.config.snippet_cap.is_some() {
65                        SmolStr::from_iter([key.as_str(), " = $0"])
66                    } else {
67                        SmolStr::default()
68                    },
69                ),
70            })
71            .chain(CFG_CONDITION.iter().map(|&(k, snip)| (k, SmolStr::new_static(snip))))
72            .unique_by(|&(s, _)| s)
73            .for_each(|(s, snippet)| {
74                let mut item = CompletionItem::new(
75                    SymbolKind::BuiltinAttr,
76                    ctx.source_range(),
77                    s,
78                    ctx.edition,
79                );
80                if let Some(cap) = ctx.config.snippet_cap
81                    && !snippet.is_empty()
82                {
83                    item.insert_snippet(cap, snippet);
84                }
85                acc.add(item.build(ctx.db));
86            }),
87    }
88}
89
90const CFG_CONDITION: &[(&str, &str)] =
91    &[("all", "all($0)"), ("any", "any($0)"), ("not", "not($0)")];
92
93const KNOWN_ARCH: [&str; 20] = [
94    "aarch64",
95    "arm",
96    "avr",
97    "csky",
98    "hexagon",
99    "mips",
100    "mips64",
101    "msp430",
102    "nvptx64",
103    "powerpc",
104    "powerpc64",
105    "riscv32",
106    "riscv64",
107    "s390x",
108    "sparc",
109    "sparc64",
110    "wasm32",
111    "wasm64",
112    "x86",
113    "x86_64",
114];
115
116const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"];
117
118const KNOWN_OS: [&str; 20] = [
119    "cuda",
120    "dragonfly",
121    "emscripten",
122    "freebsd",
123    "fuchsia",
124    "haiku",
125    "hermit",
126    "illumos",
127    "l4re",
128    "linux",
129    "netbsd",
130    "none",
131    "openbsd",
132    "psp",
133    "redox",
134    "solaris",
135    "uefi",
136    "unknown",
137    "vxworks",
138    "windows",
139];
140
141const KNOWN_VENDOR: [&str; 8] =
142    ["apple", "fortanix", "nvidia", "pc", "sony", "unknown", "wrs", "uwp"];