From 61ae0fe96476f73f0edeb82a62a3369ab766a1f1 Mon Sep 17 00:00:00 2001 From: Randy James Date: Sun, 3 May 2026 07:05:36 -0700 Subject: [PATCH] fix(grid): add box-drawing characters to FILE_LINK_SEPARATORS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds Unicode box-drawing characters (single and double-line variants) to the file-link separator set so that tree/eza --tree/lsd --tree output filenames are tokenized as standalone clickable candidates. Previously, rows like '│ └── alpha.md' were treated as a single token because │, ├, └, ─ were not in the separator set. Closes #9909 --- app/src/terminal/model/grid/grid_handler.rs | 10 ++++- .../terminal/model/grid/grid_handler_test.rs | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/src/terminal/model/grid/grid_handler.rs b/app/src/terminal/model/grid/grid_handler.rs index f6d2a0be1..3054a41ac 100644 --- a/app/src/terminal/model/grid/grid_handler.rs +++ b/app/src/terminal/model/grid/grid_handler.rs @@ -89,7 +89,15 @@ const BG_SGR_PARAM: u8 = 48; lazy_static! { pub static ref FILE_LINK_SEPARATORS: HashSet = - HashSet::from(['\0', '\t', ' ', '(', ')', ':', '\\', ',', '"', '\'', '[', ']', '{', '}', '<', '>', ';', '|', '`', '=']); + HashSet::from([ + '\0', '\t', ' ', '(', ')', ':', '\\', ',', '"', '\'', '[', ']', '{', '}', '<', '>', + ';', '|', '`', '=', + // Box-drawing characters used by tree/eza --tree/lsd --tree output. + // Single-line variants: + '│', '├', '└', '─', '┬', '┴', '┼', '┌', '┐', '┘', + // Double-line variants: + '║', '╠', '╚', '═', '╦', '╩', '╬', '╔', '╗', '╝', + ]); /// The set of characters where, if we encounter them, we have a high degree of confidence that /// we're not in a valid URL. Other characters (e.g. '%') might be used in such a way that they diff --git a/app/src/terminal/model/grid/grid_handler_test.rs b/app/src/terminal/model/grid/grid_handler_test.rs index 832ccd6c0..ce3c1c6ac 100644 --- a/app/src/terminal/model/grid/grid_handler_test.rs +++ b/app/src/terminal/model/grid/grid_handler_test.rs @@ -2124,3 +2124,46 @@ fn content_len_equals_len_when_no_trailing_blanks() { let expected = grid.grid_storage().max_cursor_point.row.0 + grid.history_size() + 1; assert_eq!(grid.content_len(), expected); } + +#[test] +fn test_box_drawing_chars_are_link_separators() { + // Tree output: "│ └── alpha.md" — hovering on "alpha.md" should produce it as a candidate. + let blockgrid = mock_blockgrid("│ └── alpha.md"); + let paths = blockgrid + .grid_handler + .possible_file_paths_at_point(Point { row: 0, col: 12 }); + // The candidate list should include "alpha.md" as a standalone path. + assert!( + paths.iter().any(|p| p.path.path == "alpha.md"), + "Expected 'alpha.md' as a candidate in tree output, got: {:?}", + paths.iter().map(|p| &p.path.path).collect::>() + ); +} + +#[test] +fn test_box_drawing_tree_branch_with_directory() { + // Tree output: "├── src" — hovering on "src" should produce it as a candidate. + let blockgrid = mock_blockgrid("├── src"); + let paths = blockgrid + .grid_handler + .possible_file_paths_at_point(Point { row: 0, col: 6 }); + assert!( + paths.iter().any(|p| p.path.path == "src"), + "Expected 'src' as a candidate, got: {:?}", + paths.iter().map(|p| &p.path.path).collect::>() + ); +} + +#[test] +fn test_double_line_box_drawing_separators() { + // Double-line variant: "║ ╚══ notes.txt" + let blockgrid = mock_blockgrid("║ ╚══ notes.txt"); + let paths = blockgrid + .grid_handler + .possible_file_paths_at_point(Point { row: 0, col: 13 }); + assert!( + paths.iter().any(|p| p.path.path == "notes.txt"), + "Expected 'notes.txt' as a candidate in double-line tree output, got: {:?}", + paths.iter().map(|p| &p.path.path).collect::>() + ); +}