feat(core): Expand filtering into pipeline supporting multiple text search modes.
Modes include: exact match, smart-case, and regular expressions.
This commit is contained in:
@@ -113,6 +113,34 @@ impl Viewport {
|
||||
}
|
||||
}
|
||||
|
||||
/// Move cursor up by `n` half-pages (half viewport height
|
||||
/// each). Clamps to the top.
|
||||
pub fn half_page_up(&mut self, n: usize) {
|
||||
if self.height == 0 {
|
||||
return;
|
||||
}
|
||||
let half = (self.height / 2).max(1);
|
||||
let distance = half.saturating_mul(n);
|
||||
self.cursor = self.cursor.saturating_sub(distance);
|
||||
if self.cursor < self.scroll_offset {
|
||||
self.scroll_offset = self.cursor;
|
||||
}
|
||||
}
|
||||
|
||||
/// Move cursor down by `n` half-pages (half viewport height
|
||||
/// each). Clamps to the last item.
|
||||
pub fn half_page_down(&mut self, n: usize) {
|
||||
if self.height == 0 || self.filtered_count == 0 {
|
||||
return;
|
||||
}
|
||||
let half = (self.height / 2).max(1);
|
||||
let distance = half.saturating_mul(n);
|
||||
self.cursor = (self.cursor + distance).min(self.filtered_count - 1);
|
||||
if self.cursor >= self.scroll_offset + self.height {
|
||||
self.scroll_offset = self.cursor - self.height + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Move cursor down by `n` pages (viewport height each).
|
||||
/// Clamps to the last item.
|
||||
pub fn page_down(&mut self, n: usize) {
|
||||
@@ -353,4 +381,106 @@ mod tests {
|
||||
v.set_height(3);
|
||||
assert!(v.cursor() < v.scroll_offset() + 3);
|
||||
}
|
||||
|
||||
// -- half_page unit tests --
|
||||
|
||||
#[test]
|
||||
fn half_page_down_basic() {
|
||||
let mut v = viewport(10, 30);
|
||||
v.half_page_down(1);
|
||||
assert_eq!(v.cursor(), 5);
|
||||
assert_eq!(v.scroll_offset(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_down_scrolls() {
|
||||
let mut v = viewport(10, 30);
|
||||
// Move cursor near viewport edge, then half page down
|
||||
v.half_page_down(1); // cursor 5
|
||||
v.half_page_down(1); // cursor 10, should scroll
|
||||
assert_eq!(v.cursor(), 10);
|
||||
assert_eq!(v.scroll_offset(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_down_clamps() {
|
||||
let mut v = viewport(10, 12);
|
||||
v.half_page_down(1); // cursor 5
|
||||
v.half_page_down(1); // cursor 10
|
||||
v.half_page_down(1); // clamps to 11
|
||||
assert_eq!(v.cursor(), 11);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_down_n_multiplier() {
|
||||
let mut v = viewport(10, 30);
|
||||
v.half_page_down(3); // (10/2)*3 = 15
|
||||
assert_eq!(v.cursor(), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_up_basic() {
|
||||
let mut v = viewport(10, 30);
|
||||
v.half_page_down(2); // cursor 10
|
||||
v.half_page_up(1); // cursor 5
|
||||
assert_eq!(v.cursor(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_up_clamps_at_top() {
|
||||
let mut v = viewport(10, 30);
|
||||
v.half_page_down(1); // cursor 5
|
||||
v.half_page_up(1); // cursor 0
|
||||
assert_eq!(v.cursor(), 0);
|
||||
v.half_page_up(1); // still 0
|
||||
assert_eq!(v.cursor(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_up_scrolls() {
|
||||
let mut v = viewport(10, 30);
|
||||
// Scroll down far enough that offset > 0
|
||||
v.half_page_down(3); // cursor 15, offset 6
|
||||
assert!(v.scroll_offset() > 0);
|
||||
// Now half page up should track cursor back
|
||||
v.half_page_up(1); // cursor 10
|
||||
v.half_page_up(1); // cursor 5
|
||||
assert_eq!(v.cursor(), 5);
|
||||
// Offset should have followed cursor if it went above
|
||||
assert!(v.scroll_offset() <= v.cursor());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_height_one() {
|
||||
let mut v = viewport(1, 10);
|
||||
// max(1/2, 1) = 1, moves 1 item
|
||||
v.half_page_down(1);
|
||||
assert_eq!(v.cursor(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_height_two() {
|
||||
let mut v = viewport(2, 10);
|
||||
// 2/2 = 1, moves 1 item
|
||||
v.half_page_down(1);
|
||||
assert_eq!(v.cursor(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_zero_height() {
|
||||
let mut v = viewport(0, 10);
|
||||
v.half_page_down(1);
|
||||
assert_eq!(v.cursor(), 0);
|
||||
v.half_page_up(1);
|
||||
assert_eq!(v.cursor(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn half_page_empty_list() {
|
||||
let mut v = viewport(10, 0);
|
||||
v.half_page_down(1);
|
||||
assert_eq!(v.cursor(), 0);
|
||||
v.half_page_up(1);
|
||||
assert_eq!(v.cursor(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user