feat(lsp): add completions for type system keywords

Added top-level keyword completions for:
- concept: with semicolon-terminated snippet
- sub_concept: with dot notation snippet
- concept_comparison: with brace-delimited snippet

Added test verifying type system keywords appear in
completions with correct snippet formatting.
This commit is contained in:
2026-02-14 14:32:51 +00:00
parent de95332fe1
commit b3110c8b0f
2 changed files with 54 additions and 0 deletions

View File

@@ -683,6 +683,9 @@ fn top_level_keyword_completions() -> Vec<CompletionItem> {
keyword_item("location", "Define a location", "location ${1:Name} {\n $0\n}"), keyword_item("location", "Define a location", "location ${1:Name} {\n $0\n}"),
keyword_item("species", "Define a species", "species ${1:Name} {\n $0\n}"), keyword_item("species", "Define a species", "species ${1:Name} {\n $0\n}"),
keyword_item("use", "Import declarations", "use ${1:path::to::item};"), keyword_item("use", "Import declarations", "use ${1:path::to::item};"),
keyword_item("concept", "Define an algebraic data type", "concept ${1:Name};"),
keyword_item("sub_concept", "Define a sub-type", "sub_concept ${1:Parent}.${2:Name} {\n $0\n}"),
keyword_item("concept_comparison", "Pattern match on concepts", "concept_comparison ${1:Name} {\n $0\n}"),
] ]
} }

View File

@@ -248,6 +248,57 @@ character Bob {}"#;
} }
} }
#[test]
fn test_type_system_completions() {
let doc = Document::new("".to_string());
let params = make_params(0, 0);
let result = completion::get_completions(&doc, &params);
assert!(result.is_some());
if let Some(response) = result {
match response {
| tower_lsp::lsp_types::CompletionResponse::Array(items) => {
// Should have type system keywords
assert!(
items.iter().any(|item| item.label == "concept"),
"Should have concept keyword"
);
assert!(
items.iter().any(|item| item.label == "sub_concept"),
"Should have sub_concept keyword"
);
assert!(
items.iter().any(|item| item.label == "concept_comparison"),
"Should have concept_comparison keyword"
);
// Check snippets have correct format
let concept_item = items.iter().find(|item| item.label == "concept");
assert!(concept_item.is_some());
if let Some(item) = concept_item {
let snippet = item.insert_text.as_ref().unwrap();
assert!(
snippet.contains(";"),
"concept snippet should end with semicolon"
);
}
let sub_item = items.iter().find(|item| item.label == "sub_concept");
assert!(sub_item.is_some());
if let Some(item) = sub_item {
let snippet = item.insert_text.as_ref().unwrap();
assert!(
snippet.contains("."),
"sub_concept snippet should contain dot notation"
);
}
},
| _ => panic!("Expected array response"),
}
}
}
#[test] #[test]
fn test_no_duplicate_completions() { fn test_no_duplicate_completions() {
let source = "character Alice {}\ncharacter Alice {}"; // Duplicate name let source = "character Alice {}\ncharacter Alice {}"; // Duplicate name