Skip to main content

bbnf_analysis/features/
completion.rs

1use bbnf::generate::prettify::hints::HINT_DEFS;
2use ls_types::*;
3
4use crate::state::DocumentState;
5
6/// BBNF keywords and operators for completion.
7const BBNF_KEYWORDS: &[(&str, &str)] = &[
8    ("epsilon", "Empty match (ε)"),
9    ("ε", "Empty match"),
10    ("@import", "Import rules from another grammar"),
11    ("@recover", "Error recovery directive for a rule"),
12    ("@no_collapse", "Prevent span collapse for a rule (preserve Vec<Span>)"),
13    ("@pretty", "Formatting hints for pretty-printer output"),
14];
15
16pub fn completion(state: &DocumentState) -> CompletionResponse {
17    let mut items = Vec::new();
18
19    // All defined rule names.
20    for rule in &state.info.rules {
21        items.push(CompletionItem {
22            label: rule.name.clone(),
23            kind: Some(CompletionItemKind::FUNCTION),
24            detail: Some(rule.rhs_text.clone()),
25            ..Default::default()
26        });
27    }
28
29    // BBNF keywords.
30    for (keyword, detail) in BBNF_KEYWORDS {
31        items.push(CompletionItem {
32            label: keyword.to_string(),
33            kind: Some(CompletionItemKind::KEYWORD),
34            detail: Some(detail.to_string()),
35            ..Default::default()
36        });
37    }
38
39    // @pretty hint keywords.
40    for hint_def in HINT_DEFS {
41        items.push(CompletionItem {
42            label: hint_def.name.to_string(),
43            kind: Some(CompletionItemKind::ENUM_MEMBER),
44            detail: Some(hint_def.description.to_string()),
45            ..Default::default()
46        });
47    }
48
49    // sep("...") hint with snippet.
50    items.push(CompletionItem {
51        label: "sep(\"...\")".to_string(),
52        kind: Some(CompletionItemKind::ENUM_MEMBER),
53        detail: Some("Custom separator string for Vec/tuple items".to_string()),
54        insert_text: Some("sep(\"$1\")".to_string()),
55        insert_text_format: Some(InsertTextFormat::SNIPPET),
56        ..Default::default()
57    });
58
59    // split("...") hint with snippet.
60    items.push(CompletionItem {
61        label: "split(\"...\")".to_string(),
62        kind: Some(CompletionItemKind::ENUM_MEMBER),
63        detail: Some(
64            "Split Span text on delimiter at format time (depth-aware, respects ()[] and quotes)"
65                .to_string(),
66        ),
67        insert_text: Some("split(\"$1\")".to_string()),
68        insert_text_format: Some(InsertTextFormat::SNIPPET),
69        ..Default::default()
70    });
71
72    CompletionResponse::Array(items)
73}