lotabout.skim/tests/ansi.rs
LoricAndre dce26d622a
feat: add --hide-nth to hide fields from display but keep them searchable (#1122)
* Add --hide-nth flag to hide fields while keeping them searchable

Introduce a `--hide-nth <fieldspec>` option that takes the same
comma-separated field index expressions as `--nth`/`--with-nth`. The
listed fields are removed from the displayed line but remain part of the
text used for matching, so a query can still match them. Characters in
the hidden fields are ignored for match highlighting and horizontal
scrolling.

Implementation:
- Resolve the fieldspec to byte ranges in the same coordinate space as
  the matching/display text and store them as `hidden_ranges` in
  DefaultSkimItem metadata, exposed via a new `SkimItem::hidden_ranges()`
  trait method. text()/output() keep the full text so hidden fields stay
  searchable and are preserved on output.
- DefaultSkimItem::display() removes hidden characters and remaps match
  highlight positions into visible coordinates (project_visible_text /
  project_match_indices); this path takes precedence over ANSI styling.
- ItemRenderer::render_item applies the same projection to derive the
  visible sub-line text and hscroll match range, so hidden characters are
  ignored for horizontal scrolling.

Add unit tests for range normalization/projection and item behavior,
plus insta snapshot tests covering display removal, searchability, and
hscroll. Update ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCunXeAFMYAFduTc8SNjSM

* Preserve ANSI colors for surviving text under --hide-nth

Previously the hidden-field rendering path was applied ahead of the ANSI
display branch and rebuilt the line from the ANSI-stripped text, so
combining --hide-nth with --ansi dropped the colors of the visible
fields.

Integrate hidden-field removal into the ANSI branch instead: after
parsing the styled spans, drop the hidden characters while preserving
each span's style (retain_visible_spans) and remap the match positions
into the resulting visible coordinate space, then run the normal
highlighting. The plain (non-ANSI) branch keeps its project-and-to_line
handling. Surviving characters now keep their ANSI colors while hidden
fields stay searchable.

Add unit tests for ANSI color preservation and remapped highlighting,
plus ANSI color-snapshot integration tests. Update ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCunXeAFMYAFduTc8SNjSM

* Set hidden fields via builder instead of DefaultSkimItem::new param

Remove the `hidden_fields` parameter from `DefaultSkimItem::new` and set
the hidden fields through a `hidden_fields(&[FieldRange], &Regex)`
builder method instead. The builder resolves the fields against the
item's own `text()` (the same coordinate space `new` would have used),
so the result is identical while keeping `new`'s signature unchanged for
its many existing call sites.

The reader chains `.hidden_fields(&opt.hidden_fields, &opt.delimiter)`
onto construction. Revert the extra `&[]` argument at the other call
sites (selector, fuzz target, tests) and update the hide-nth tests to
use the builder. Update ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCunXeAFMYAFduTc8SNjSM

* chore: generate files

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-18 13:13:43 +00:00

77 lines
2.7 KiB
Rust

#![allow(missing_docs, clippy::pedantic)]
#[allow(dead_code)]
#[macro_use]
mod common;
// With --ansi the colored input is interpreted: the items render with their
// ANSI colors and the matched query characters are highlighted. `@snap_color`
// captures the per-cell styling so this actually verifies color, while
// `--color current_match_bg:1,current_bg:2` exercises the themed selection.
insta_test!(test_ansi_flag_enabled, @bytes b"plain\n\x1b[31mred\x1b[0m\n\x1b[32mgreen\x1b[0m\n", &["--ansi", "--color", "current_match_bg:1,current_bg:2"], {
@type "d";
@snap;
@snap_color;
});
// Without --ansi, the escape sequences are not interpreted: they are matched
// and displayed as literal text, and the items carry no color. `@snap_color`
// asserts the absence of ANSI-derived styling on the item rows.
insta_test!(test_ansi_flag_disabled, @bytes b"plain\n\x1b[31mred\x1b[0m\n\x1b[32mgreen\x1b[0m\n", &[], {
@type "red";
@snap;
@snap_color;
});
// With --ansi, matching happens on the ANSI-stripped text and the tiebreak
// reorders the matches. The color snapshot confirms each item keeps its own
// (red / green) foreground after matching.
insta_test!(test_ansi_matching_on_stripped_text, @bytes b"\x1b[32mgreen\x1b[0m text\n\x1b[31mred\x1b[0m text\nplain text\n", &["--ansi"], {
@type "text";
@snap;
@snap_color;
@ctrl 'u';
@type "green";
@snap;
});
// --no-strip-ansi only affects the accepted output (it keeps the escape
// sequences); on screen it renders identically to --ansi.
insta_test!(test_ansi_flag_no_strip, @bytes b"plain\n\x1b[31mred\x1b[0m\n\x1b[32mgreen\x1b[0m\n", &["--ansi", "--no-strip-ansi", "--color", "current_match_bg:1,current_bg:2"], {
@type "d";
@snap;
@snap_color;
});
insta_test!(test_prompt_ansi, ["a"], &["--prompt", "\x1b[1;34mprompt\x1b[0m nocol"], {
@snap;
@snap_color;
});
// --ansi combined with --hide-nth: the hidden (red) middle field is removed from
// the rendered line, while the surviving green/plain fields keep their ANSI colors.
// The color snapshot confirms the green foreground survives and the red one is gone.
insta_test!(
test_ansi_hide_nth,
@bytes b"\x1b[32mgreen\x1b[0m \x1b[31mred\x1b[0m plain\n",
&["--ansi", "--delimiter", " ", "--hide-nth", "2"],
{
@snap;
@snap_color;
}
);
// The hidden ANSI field stays searchable: matching its text ("red") still selects
// the item even though the field is not shown, and no highlight leaks onto the
// visible text.
insta_test!(
test_ansi_hide_nth_searchable,
@bytes b"\x1b[32mgreen\x1b[0m \x1b[31mred\x1b[0m plain\n",
&["--ansi", "--delimiter", " ", "--hide-nth", "2"],
{
@type "red";
@snap;
@snap_color;
}
);