fix: fix lsp adding two @

This commit is contained in:
Konstantin Fickel 2026-04-19 20:48:56 +02:00
parent 76a1a6b695
commit 2307891d0d
Signed by: kfickel
GPG key ID: A793722F9933C1A5

View file

@ -113,28 +113,6 @@ pub fn completions_for_line(
let after_at = &line_prefix[at_pos + 1..]; let after_at = &line_prefix[at_pos + 1..];
// Temporal snippet: `@` followed by a digit → offer date/time format snippets.
if after_at.starts_with(|c: char| c.is_ascii_digit()) {
return vec![
CompletionItem {
label: "YYYYMMDD".to_string(),
kind: Some(CompletionItemKind::SNIPPET),
detail: Some("Date marker (R16)".to_string()),
insert_text: Some("${1:YYYYMMDD}".to_string()),
insert_text_format: Some(InsertTextFormat::SNIPPET),
..Default::default()
},
CompletionItem {
label: "HHMMSS".to_string(),
kind: Some(CompletionItemKind::SNIPPET),
detail: Some("Time marker (R16)".to_string()),
insert_text: Some("${1:HHMMSS}".to_string()),
insert_text_format: Some(InsertTextFormat::SNIPPET),
..Default::default()
},
];
}
// Markers already on this line (for conditional suggestion logic). // Markers already on this line (for conditional suggestion logic).
let existing: Vec<String> = extract_markers_from_line(line); let existing: Vec<String> = extract_markers_from_line(line);
@ -166,6 +144,7 @@ pub fn completions_for_line(
label: format!("@{}", name), label: format!("@{}", name),
kind: Some(CompletionItemKind::KEYWORD), kind: Some(CompletionItemKind::KEYWORD),
detail: Some(marker.display_name.clone()), detail: Some(marker.display_name.clone()),
insert_text: Some(name.clone()),
// Conditional completions sort before unconditional ones. // Conditional completions sort before unconditional ones.
sort_text: Some(if is_conditional { sort_text: Some(if is_conditional {
format!("0_{}", name) format!("0_{}", name)
@ -177,6 +156,28 @@ pub fn completions_for_line(
}) })
.collect(); .collect();
// Offer date/time snippets when prefix is empty or starts with a digit.
if prefix.is_empty() || prefix.starts_with(|c: char| c.is_ascii_digit()) {
items.push(CompletionItem {
label: "@YYYYMMDD".to_string(),
kind: Some(CompletionItemKind::SNIPPET),
detail: Some("Date marker (R16)".to_string()),
insert_text: Some("${1:YYYYMMDD}".to_string()),
insert_text_format: Some(InsertTextFormat::SNIPPET),
sort_text: Some("2_date".to_string()),
..Default::default()
});
items.push(CompletionItem {
label: "@HHMMSS".to_string(),
kind: Some(CompletionItemKind::SNIPPET),
detail: Some("Time marker (R16)".to_string()),
insert_text: Some("${1:HHMMSS}".to_string()),
insert_text_format: Some(InsertTextFormat::SNIPPET),
sort_text: Some("2_time".to_string()),
..Default::default()
});
}
items.sort_by(|a, b| { items.sort_by(|a, b| {
a.sort_text a.sort_text
.as_deref() .as_deref()
@ -1035,17 +1036,37 @@ mod tests {
.starts_with("0_")); .starts_with("0_"));
} }
#[test]
fn test_completions_temporal_snippet_at_sign() {
let config = make_config();
// Timestamps suggested when prefix is empty (just @)
let items = completions_for_line("@", 1, &config);
let labels: Vec<&str> = items.iter().map(|i| i.label.as_str()).collect();
assert!(labels.contains(&"@YYYYMMDD"));
assert!(labels.contains(&"@HHMMSS"));
assert!(items
.iter()
.any(|i| i.kind == Some(CompletionItemKind::SNIPPET)));
}
#[test] #[test]
fn test_completions_temporal_snippet_digit_after_at() { fn test_completions_temporal_snippet_digit_after_at() {
let config = make_config(); let config = make_config();
let items = completions_for_line("@2", 2, &config); let items = completions_for_line("@2", 2, &config);
assert!(!items.is_empty()); assert!(!items.is_empty());
let labels: Vec<&str> = items.iter().map(|i| i.label.as_str()).collect(); let labels: Vec<&str> = items.iter().map(|i| i.label.as_str()).collect();
assert!(labels.contains(&"YYYYMMDD")); assert!(labels.contains(&"@YYYYMMDD"));
assert!(labels.contains(&"HHMMSS")); assert!(labels.contains(&"@HHMMSS"));
// Temporal items use snippet format
assert!(items assert!(items
.iter() .iter()
.any(|i| i.kind == Some(CompletionItemKind::SNIPPET))); .any(|i| i.kind == Some(CompletionItemKind::SNIPPET)));
} }
#[test]
fn test_completions_no_double_at() {
let config = make_config();
let items = completions_for_line("@Br", 3, &config);
let break_item = items.iter().find(|i| i.label == "@Break").unwrap();
assert_eq!(break_item.insert_text.as_deref(), Some("Break"));
}
} }