From 4e4789a045f03176885388555057ffebb85352b9 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:17:43 +0800 Subject: [PATCH] fix(links): peel a CJK label off a path glued behind it (#1053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An agent reporting a file it wrote prints `原型:/tmp/a.html` or `原型:/tmp/a.html` with no space. The label rule only accepted ASCII labels behind an ASCII colon, so the whole token was read as a relative path and the click reported it missing under the pane's directory. Accept any alphabetic label, one character long when it is not ASCII, behind either colon. A single ASCII letter stays a Windows drive. --- src/terminal/search.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/terminal/search.rs b/src/terminal/search.rs index 0be17715..a034a6a4 100644 --- a/src/terminal/search.rs +++ b/src/terminal/search.rs @@ -1278,12 +1278,17 @@ fn left_cuts(chars: &[char]) -> Vec { // follows has to be spelled like a path too, or `branch:main` and // `remote:origin` become links the moment the pane's directory holds // a `main/` or an `origin/`. - if let Some(i) = rest.iter().position(|&c| c == ':') - && i >= 2 - && rest[0].is_ascii_alphabetic() + // + // CJK prose writes the label with no space and either colon: + // `原型:/tmp/a.html`, `原型:/tmp/a.html`. A one-character label is + // only a drive when it is an ASCII letter, so `图:/tmp/a.png` still + // counts as a label. + if let Some(i) = rest.iter().position(|&c| matches!(c, ':' | ':')) + && (i >= 2 || (i == 1 && !rest[0].is_ascii())) + && rest[0].is_alphabetic() && rest[..i] .iter() - .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '+')) + .all(|c| c.is_alphanumeric() || matches!(c, '_' | '-' | '+')) && rest[i + 1..] .iter() .any(|c| matches!(c, '/' | '\\' | '.' | '~')) @@ -2132,6 +2137,18 @@ mod tests { assert_file_link(&line, col, Path::new("/"), &path, Some(42), None); } + /// An agent reporting the file it wrote puts a CJK label and a colon + /// straight in front of the path, full-width or not. + #[test] + fn link_at_peels_a_cjk_label_off_an_absolute_path() { + let path = temp_file("cjk-label/mock.html"); + for label in ["原型:", "原型:", "图:", "图:"] { + let line = format!("交互 HTML {label}{}", path.display()); + let col = line.chars().position(|c| c == '/').unwrap() + 3; + assert_file_link(&line, col, Path::new("/"), &path, None, None); + } + } + #[test] fn link_at_trims_wrappers_and_trailing_punctuation_around_file_paths() { let path = temp_file("wrapped/src/lib.rs");