From 416a0e09834dbb4eae0069123d75e51bfa5d9254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Fri, 3 Jul 2026 03:07:29 +0200 Subject: [PATCH] fix: continue comment with injected `comment` syntax (#15940) Noticed in Go which injects `comment` syntax for comments. The comment continuation wouldn't work because it would try to resolve the comment continuation token from the injected comment syntax which doesn't define one. Resolved by bubbling up until we find a first layer that defines comment token. --- helix-term/src/commands.rs | 35 ++++++++++++++--- helix-term/tests/test/commands/insert.rs | 50 ++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5d63cdd3..c9560f33 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3825,6 +3825,29 @@ pub enum CommentContinuation { Disabled, } +fn continued_line_comment_token<'a>( + doc: &'a Document, + loader: &'a helix_core::syntax::Loader, + text: RopeSlice, + line_num: usize, + byte_pos: usize, +) -> Option<&'a str> { + if let Some(syntax) = doc.syntax() { + let mut token = None; + for layer in syntax.layers_for_byte_range(byte_pos as u32, byte_pos as u32) { + let config = loader.language(syntax.layer(layer).language).config(); + if let Some(tokens) = config.comment_tokens.as_ref() { + token = comment::get_comment_token(text, tokens, line_num).or(token); + } + } + token + } else { + doc.language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .and_then(|tokens| comment::get_comment_token(text, tokens, line_num)) + } +} + fn open(cx: &mut Context, open: Open, comment_continuation: CommentContinuation) { let count = cx.count(); enter_insert_mode(cx); @@ -3860,9 +3883,9 @@ fn open(cx: &mut Context, open: Open, comment_continuation: CommentContinuation) text.line(curr_line_num) .first_non_whitespace_char() .map(|c| text.char_to_byte(text.line_to_char(curr_line_num) + c)) - .and_then(|byte| doc.language_config_at(&loader, byte)) - .and_then(|config| config.comment_tokens.as_ref()) - .and_then(|tokens| comment::get_comment_token(text, tokens, curr_line_num)) + .and_then(|byte| { + continued_line_comment_token(doc, &loader, text, curr_line_num, byte) + }) } else { None }; @@ -4489,9 +4512,9 @@ pub mod insert { text.line(current_line) .first_non_whitespace_char() .map(|c| text.char_to_byte(line_start + c)) - .and_then(|byte| doc.language_config_at(&loader, byte)) - .and_then(|config| config.comment_tokens.as_ref()) - .and_then(|tokens| comment::get_comment_token(text, tokens, current_line)) + .and_then(|byte| { + continued_line_comment_token(doc, &loader, text, current_line, byte) + }) } else { None }; diff --git a/helix-term/tests/test/commands/insert.rs b/helix-term/tests/test/commands/insert.rs index 7f00826b..640a2390 100644 --- a/helix-term/tests/test/commands/insert.rs +++ b/helix-term/tests/test/commands/insert.rs @@ -201,6 +201,36 @@ async fn insert_newline_continue_line_comment() -> anyhow::Result<()> { )) .await?; + // Continuation should use the enclosing layer's comment tokens if an injected layer + // doesn't define comment token. + test(( + indoc! {"\ + // Hello world!#[| + ]# + "}, + ":lang goi", + indoc! {"\ + // Hello world! + // #[| + ]# + "}, + )) + .await?; + + test(( + indoc! {"\ + //go:generate echo hello#[| + ]# + "}, + ":lang goi", + indoc! {"\ + //go:generate echo hello + // #[| + ]# + "}, + )) + .await?; + // The comment is not continued if the cursor is before the comment token. (Note that we // are entering insert-mode with `I`.) test(( @@ -461,6 +491,26 @@ async fn test_open_below_with_multiple_cursors() -> anyhow::Result<()> { )) .await?; + // Open below should continue comment even if language has `comment` grammar + // injection. + test(( + indoc! {"\ + package main + + // VIP#[|]# comment + func main() {} + "}, + ":lang goo", + indoc! {"\ + package main + + // VIP comment + // #[\n|]# + func main() {} + "}, + )) + .await?; + Ok(()) } -- 2.51.2