feat: horizontally scroll across log

By default, use left and right arrow keys to horizontally scroll over the lines of logs, also has various refactors to reduced to size of the vec of logs sent to the ui renderer
This commit is contained in:
Jack Wills
2025-08-14 23:20:44 +00:00
parent 6b6d9fcbc1
commit c190f0206c
20 changed files with 617 additions and 332 deletions
+123 -105
View File
@@ -84,6 +84,7 @@ impl HelpInfo {
}
}
// todo ← → for log moving
/// Generate the button information span + metadata
#[allow(clippy::too_many_lines)]
fn gen_keymap_info(colors: AppColors, zone: Option<&TimeZone>, show_timestamp: bool) -> Self {
@@ -111,6 +112,11 @@ impl HelpInfo {
button_item("Home End"),
button_desc("change selected line"),
]),
Line::from(vec![
space(),
button_item("← →"),
button_desc("horizontal scroll across logs"),
]),
Line::from(vec![
space(),
button_item("enter"),
@@ -268,6 +274,8 @@ impl HelpInfo {
or_secondary(km.scroll_up_many, "scroll list by up many"),
or_secondary(km.scroll_end, "scroll list to end"),
or_secondary(km.scroll_start, "scroll list to start"),
or_secondary(km.log_scroll_forward, "horizontal scroll logs right"),
or_secondary(km.log_scroll_back, "horizontal scroll logs left"),
Line::from(vec![
space(),
button_item("enter"),
@@ -436,6 +444,8 @@ mod tests {
#[test]
/// This will cause issues once the version has more than the current 5 chars (0.5.0)
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
/// TODO broken wihh the horizonal scrolls!
fn test_draw_blocks_help() {
let mut setup = test_setup(87, 35, true, true);
let tz = setup.app_data.lock().config.timezone.clone();
@@ -463,30 +473,30 @@ mod tests {
assert_eq!(result_cell.bg, Color::Reset);
assert_eq!(result_cell.fg, Color::Reset);
}
// border is black on magenta
// border is red on black
(1 | 32, _) | (1..=31, 1 | 85) => {
assert_eq!(result_cell.bg, Color::Magenta);
assert_eq!(result_cell.fg, Color::Black);
}
// oxker logo && description
// Buttons
(2..=10, 2..=85)
| (12, 19..=66)
| (14, 2..=10 | 13..=27)
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
| (16 | 23, 2..=12)
| (17..=20 | 22 | 25 | 27, 2..=8)
| (21, 2..=9 | 12..=18)
| (24 | 26, 2..=10) => {
| (16 | 25 | 27, 2..=10)
| (17 | 24, 2..=12)
| (18 | 19 | 20 | 21 | 23 | 26 | 28, 2..=8)
| (22, 2..=9 | 12..=18) => {
assert_eq!(result_cell.bg, Color::Magenta);
assert_eq!(result_cell.fg, Color::White);
}
// The URL is white and underlined
(30, 25..=60) => {
// The URL is yellow and underlined
(31, 25..=60) => {
assert_eq!(result_cell.bg, Color::Magenta);
assert_eq!(result_cell.fg, Color::White);
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
}
// The rest is black on magenta
// The rest is red on black
_ => {
assert_eq!(result_cell.bg, Color::Magenta);
assert_eq!(result_cell.fg, Color::Black);
@@ -498,6 +508,8 @@ mod tests {
#[test]
/// Test that the help panel gets drawn with custom colors
/// This test is annoying
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
fn test_draw_blocks_help_custom_colors() {
let mut setup = test_setup(87, 35, true, true);
let mut colors = AppColors::new();
@@ -535,20 +547,20 @@ mod tests {
assert_eq!(result_cell.bg, Color::Black);
assert_eq!(result_cell.fg, Color::Red);
}
// oxker logo && description
// Buttons
(2..=10, 2..=85)
| (12, 19..=66)
| (14, 2..=10 | 13..=27)
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
| (16 | 23, 2..=12)
| (17..=20 | 22 | 25 | 27, 2..=8)
| (21, 2..=9 | 12..=18)
| (24 | 26, 2..=10) => {
| (16 | 25 | 27, 2..=10)
| (17 | 24, 2..=12)
| (18 | 19 | 20 | 21 | 23 | 26 | 28, 2..=8)
| (22, 2..=9 | 12..=18) => {
assert_eq!(result_cell.bg, Color::Black);
assert_eq!(result_cell.fg, Color::Yellow);
}
// The URL is yellow and underlined
(30, 25..=60) => {
(31, 25..=60) => {
assert_eq!(result_cell.bg, Color::Black);
assert_eq!(result_cell.fg, Color::Yellow);
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
@@ -566,39 +578,41 @@ mod tests {
#[test]
/// Help panel will show custom keymap if in use, with one definition for each entry
fn test_draw_blocks_help_custom_keymap_one_definition() {
let mut setup = test_setup(98, 47, true, true);
let mut setup = test_setup(98, 49, true, true);
let input = Keymap {
clear: (KeyCode::Char('a'), None),
delete_confirm: (KeyCode::Char('b'), None),
delete_deny: (KeyCode::Char('c'), None),
delete_confirm: (KeyCode::Char('e'), None),
exec: (KeyCode::Char('g'), None),
log_section_height_decrease: (KeyCode::Char('z'), None),
log_section_height_increase: (KeyCode::Char('x'), None),
log_section_toggle: (KeyCode::Char('W'), None),
filter_mode: (KeyCode::Char('i'), None),
exec: (KeyCode::Char('d'), None),
filter_mode: (KeyCode::Char('e'), None),
log_scroll_back: (KeyCode::Char('f'), None),
log_scroll_forward: (KeyCode::Char('g'), None),
log_section_height_decrease: (KeyCode::Char('h'), None),
log_section_height_increase: (KeyCode::Char('i'), None),
log_section_toggle: (KeyCode::Char('j'), None),
quit: (KeyCode::Char('k'), None),
save_logs: (KeyCode::Char('m'), None),
scroll_down_many: (KeyCode::Char('o'), None),
scroll_down_one: (KeyCode::Char('q'), None),
scroll_end: (KeyCode::Char('s'), None),
scroll_start: (KeyCode::Char('u'), None),
scroll_up_many: (KeyCode::Char('w'), None),
scroll_up_one: (KeyCode::Char('y'), None),
select_next_panel: (KeyCode::Char('0'), None),
select_previous_panel: (KeyCode::Char('2'), None),
sort_by_name: (KeyCode::Char('4'), None),
sort_by_state: (KeyCode::Char('6'), None),
sort_by_status: (KeyCode::Char('8'), None),
sort_by_cpu: (KeyCode::F(1), None),
sort_by_memory: (KeyCode::Char('#'), None),
sort_by_id: (KeyCode::Char('/'), None),
sort_by_image: (KeyCode::Char(','), None),
sort_by_rx: (KeyCode::Char('.'), None),
sort_by_tx: (KeyCode::Insert, None),
sort_reset: (KeyCode::Up, None),
toggle_help: (KeyCode::Home, None),
toggle_mouse_capture: (KeyCode::PageDown, None),
save_logs: (KeyCode::Char('l'), None),
scroll_down_many: (KeyCode::Char('m'), None),
scroll_down_one: (KeyCode::Char('n'), None),
scroll_end: (KeyCode::Char('o'), None),
scroll_start: (KeyCode::Char('p'), None),
scroll_up_many: (KeyCode::Char('q'), None),
scroll_up_one: (KeyCode::Char('r'), None),
select_next_panel: (KeyCode::Char('s'), None),
select_previous_panel: (KeyCode::Char('t'), None),
sort_by_cpu: (KeyCode::Char('u'), None),
sort_by_id: (KeyCode::Char('v'), None),
sort_by_image: (KeyCode::Char('w'), None),
sort_by_memory: (KeyCode::Char('x'), None),
sort_by_name: (KeyCode::Char('y'), None),
sort_by_rx: (KeyCode::Char('z'), None),
sort_by_state: (KeyCode::Char('0'), None),
sort_by_status: (KeyCode::Char('1'), None),
sort_by_tx: (KeyCode::Char('2'), None),
sort_reset: (KeyCode::Char('3'), None),
toggle_help: (KeyCode::Char('4'), None),
toggle_mouse_capture: (KeyCode::Char('5'), None),
};
setup
@@ -614,39 +628,41 @@ mod tests {
#[test]
/// Help panel will show custom keymap if in use, with two definition for each entry
fn test_draw_blocks_help_custom_keymap_two_definitions() {
let mut setup = test_setup(110, 47, true, true);
let mut setup = test_setup(110, 49, true, true);
let keymap = Keymap {
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('d'))),
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
scroll_down_many: (KeyCode::Char('o'), Some(KeyCode::Char('p'))),
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
scroll_end: (KeyCode::Char('s'), Some(KeyCode::Char('t'))),
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
scroll_up_many: (KeyCode::Char('w'), Some(KeyCode::Char('x'))),
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
select_next_panel: (KeyCode::Char('0'), Some(KeyCode::Char('1'))),
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
sort_by_name: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
sort_by_status: (KeyCode::Char('8'), Some(KeyCode::Char('9'))),
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
sort_by_memory: (KeyCode::Char('#'), Some(KeyCode::Char('-'))),
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
sort_by_image: (KeyCode::Char(','), Some(KeyCode::Char('\\'))),
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
sort_by_tx: (KeyCode::Insert, Some(KeyCode::BackTab)),
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
toggle_help: (KeyCode::Home, Some(KeyCode::End)),
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
delete_confirm: (KeyCode::Char('b'), Some(KeyCode::Char('B'))),
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
exec: (KeyCode::Char('d'), Some(KeyCode::Char('D'))),
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
log_scroll_back: (KeyCode::Char('f'), Some(KeyCode::Char('F'))),
log_scroll_forward: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
log_section_height_decrease: (KeyCode::Char('h'), Some(KeyCode::Char('H'))),
log_section_height_increase: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
log_section_toggle: (KeyCode::Char('j'), Some(KeyCode::Char('J'))),
quit: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
save_logs: (KeyCode::Char('l'), Some(KeyCode::Char('L'))),
scroll_down_many: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
scroll_down_one: (KeyCode::Char('n'), Some(KeyCode::Char('N'))),
scroll_end: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
scroll_start: (KeyCode::Char('p'), Some(KeyCode::Char('P'))),
scroll_up_many: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
scroll_up_one: (KeyCode::Char('r'), Some(KeyCode::Char('R'))),
select_next_panel: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
select_previous_panel: (KeyCode::Char('t'), Some(KeyCode::Char('T'))),
sort_by_cpu: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
sort_by_id: (KeyCode::Char('v'), Some(KeyCode::Char('V'))),
sort_by_image: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
sort_by_memory: (KeyCode::Char('x'), Some(KeyCode::Char('X'))),
sort_by_name: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
sort_by_rx: (KeyCode::Char('z'), Some(KeyCode::Char('Z'))),
sort_by_state: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
sort_by_status: (KeyCode::Char('1'), Some(KeyCode::Char('8'))),
sort_by_tx: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
sort_reset: (KeyCode::Char('3'), Some(KeyCode::Char('6'))),
toggle_help: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
toggle_mouse_capture: (KeyCode::Char('5'), Some(KeyCode::PageDown)),
};
setup
@@ -662,39 +678,41 @@ mod tests {
#[test]
/// Help panel will show custom keymap if in use, with either one or two definition for each entry
fn test_draw_blocks_help_one_and_two_definitions() {
let mut setup = test_setup(110, 47, true, true);
let mut setup = test_setup(110, 49, true, true);
let keymap = Keymap {
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
delete_deny: (KeyCode::Char('c'), None),
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
exec: (KeyCode::Char('g'), None),
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
quit: (KeyCode::Char('k'), None),
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
scroll_down_many: (KeyCode::Char('o'), None),
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
scroll_end: (KeyCode::Char('s'), None),
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
scroll_up_many: (KeyCode::Char('w'), None),
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
select_next_panel: (KeyCode::Char('0'), None),
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
sort_by_name: (KeyCode::Char('4'), None),
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
sort_by_status: (KeyCode::Char('8'), None),
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
sort_by_memory: (KeyCode::Char('#'), None),
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
sort_by_image: (KeyCode::Char(','), None),
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
sort_by_tx: (KeyCode::Insert, None),
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
toggle_help: (KeyCode::Home, None),
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
delete_confirm: (KeyCode::Char('b'), None),
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
exec: (KeyCode::Char('d'), None),
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
log_scroll_back: (KeyCode::Char('f'), None),
log_scroll_forward: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
log_section_height_decrease: (KeyCode::Char('h'), None),
log_section_height_increase: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
log_section_toggle: (KeyCode::Char('j'), None),
quit: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
save_logs: (KeyCode::Char('l'), None),
scroll_down_many: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
scroll_down_one: (KeyCode::Char('n'), None),
scroll_end: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
scroll_start: (KeyCode::Char('p'), None),
scroll_up_many: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
scroll_up_one: (KeyCode::Char('r'), None),
select_next_panel: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
select_previous_panel: (KeyCode::Char('t'), None),
sort_by_cpu: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
sort_by_id: (KeyCode::Char('v'), None),
sort_by_image: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
sort_by_memory: (KeyCode::Char('x'), None),
sort_by_name: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
sort_by_rx: (KeyCode::Char('z'), None),
sort_by_state: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
sort_by_status: (KeyCode::Char('1'), None),
sort_by_tx: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
sort_reset: (KeyCode::Char('3'), None),
toggle_help: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
toggle_mouse_capture: (KeyCode::Char('5'), None),
};
let tz = setup.app_data.lock().config.timezone.clone();