From 099a23be90a6e280a7f0e9ea2e92f9880fbe32ba Mon Sep 17 00:00:00 2001 From: daisuke8000 Date: Sun, 5 Jul 2026 23:50:18 +0900 Subject: [PATCH] Single-pass highlight with no copy on no-match (DSK-135) Avoid clearing and rebuilding the line buffer when the highlight regex does not match; assign highlighted output directly when it does. Co-authored-by: Cursor --- crates/rustern-core/src/render/highlight.rs | 34 +++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/rustern-core/src/render/highlight.rs b/crates/rustern-core/src/render/highlight.rs index 82b433b..9999cf0 100644 --- a/crates/rustern-core/src/render/highlight.rs +++ b/crates/rustern-core/src/render/highlight.rs @@ -1,3 +1,4 @@ +use std::fmt::Write as _; use std::sync::Arc; use owo_colors::OwoColorize; @@ -21,26 +22,27 @@ impl SternHighlightLineFormatter { impl LineFormatter for SternHighlightLineFormatter { fn format_into(&self, event: &LogEvent, buf: &mut String) { self.inner.format_into(event, buf); - if self.re.find(buf).is_none() { - return; + if let Some(highlighted) = highlight_default_line(buf, &self.re) { + *buf = highlighted; } - let highlighted = highlight_default_line(buf, &self.re); - buf.clear(); - buf.push_str(&highlighted); } } -fn highlight_default_line(text: &str, re: &Regex) -> String { +fn highlight_default_line(text: &str, re: &Regex) -> Option { let mut last = 0usize; - let mut out = String::with_capacity(text.len().saturating_add(text.len().min(4096))); + let mut out = None::; for m in re.find_iter(text) { + let out = out.get_or_insert_with(|| { + String::with_capacity(text.len().saturating_add(text.len().min(4096))) + }); out.push_str(&text[last..m.start()]); - let styled = (&text[m.start()..m.end()]).red().bold().to_string(); - out.push_str(&styled); + let _ = write!(out, "{}", (&text[m.start()..m.end()]).red().bold()); last = m.end(); } - out.push_str(&text[last..]); - out + out.map(|mut highlighted| { + highlighted.push_str(&text[last..]); + highlighted + }) } /// Stern merges `--include` and `--highlight`, sorts alternation segments by descending pattern-string @@ -82,7 +84,7 @@ mod tests { .expect("combined pattern"); assert!(re.is_match("foobar")); - let out = highlight_default_line("- foobar!", &re); + let out = highlight_default_line("- foobar!", &re).expect("match"); assert!(out.contains("foobar")); assert!(out.starts_with('-')); assert!(out.contains('\x1b')); // ansi wrap @@ -91,4 +93,12 @@ mod tests { "prefix before match should survive: {out:?}" ); } + + #[test] + fn no_match_returns_none() { + let re = compile_stern_highlight_regex(&["needle".into()], &[]) + .unwrap() + .expect("pattern"); + assert!(highlight_default_line("no haystack here", &re).is_none()); + } }