From c5bbffdb5f9e800951e4060aa6aee8e00db589aa Mon Sep 17 00:00:00 2001 From: Jack Wills <32690432+mrjackwills@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:19:10 +0000 Subject: [PATCH] feat: ctrl scroll modifier Use the `ctrl` button to scroll by a factor of ten --- .github/screenshot_01.png | Bin 36041 -> 45020 bytes README.md | 3 +- example_config/example.config.jsonc | 7 + example_config/example.config.toml | 13 +- src/app_data/container_state.rs | 3 +- src/config/config.toml | 9 + src/config/keymap_parser.rs | 163 +++++++++++------- src/input_handler/message.rs | 2 +- src/input_handler/mod.rs | 77 ++++++--- src/ui/draw_blocks/help.rs | 57 ++++-- ...blocks__help__tests__draw_blocks_help.snap | 3 +- ...tests__draw_blocks_help_custom_colors.snap | 3 +- ...cks_help_custom_keymap_one_definition.snap | 2 +- ...ks_help_custom_keymap_two_definitions.snap | 2 +- ...w_blocks_help_one_and_two_definitions.snap | 2 +- ...tests__draw_blocks_help_show_timezone.snap | 4 +- ...__draw_blocks_whole_layout_help_panel.snap | 24 +-- src/ui/mod.rs | 5 +- 18 files changed, 249 insertions(+), 130 deletions(-) diff --git a/.github/screenshot_01.png b/.github/screenshot_01.png index 567dd3ad61354aee5114941ed6770920011b3393..f39df4830683b677f0ddeca08532a1f49f667b39 100644 GIT binary patch literal 45020 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 IZTk6t0infoq5uE@ literal 36041 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 CmG&k8 diff --git a/README.md b/README.md index fb9ef37..1c85e30 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,9 @@ In application controls, these, amongst many other settings, can be customized w | button| result| |--|--| | ```( tab )``` or ```( shift+tab )``` | Change panel, clicking on a panel also changes the selected panel.| -| ```( ↑ ↓ )``` or ```( j k )``` or ```( PgUp PgDown )``` or ```( Home End )```| Change selected line in selected panel, mouse scroll also changes selected line.| +| ```( ↑ ↓ )``` or ```( j k )``` or ```( PgUp PgDown )``` or ```( Home End )```| Scroll line in selected panel - mouse wheel will also scroll.| | ```( ← → )``` | When logs panel selected, scroll horizontally across the text of the logs.| +| ```( ctrl )``` | Increase scroll speed, used in conjuction scroll keys.| | ```( enter )```| Run selected docker command.| | ```( 1-9 )``` | Sort containers by heading, clicking on headings also sorts the selected column. | | ```( 0 )``` | Stop sorting.| diff --git a/example_config/example.config.jsonc b/example_config/example.config.jsonc index bf0436a..8abb678 100644 --- a/example_config/example.config.jsonc +++ b/example_config/example.config.jsonc @@ -42,6 +42,7 @@ // 3) F1-F12 // 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down // Each definition can have two keys associated with it + // WARNING "scroll_many" only accepts control, alt, shift, with no secondary option // If any key clashes are found, oxker will revert to it's default keymap "keymap": { // Clear any popup boxes, filter panel, or help panel @@ -74,10 +75,12 @@ "save_logs": [ "s" ], + // TODO "scroll_down_many" will be removed in the next release // Scroll down a list by many "scroll_down_many": [ "pagedown" ], + // TODO rename in next release // Scroll down a list by one item "scroll_down_one": [ "down", @@ -87,14 +90,18 @@ "scroll_end": [ "end" ], + // Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x + "scroll_many": ["control"], // Scroll up to the start of a list "scroll_start": [ "home" ], + // TODO "scroll_up_many" will be removed in the next release // Scroll up a list by many "scroll_up_many": [ "pageup" ], + // TODO rename in next release // Scroll up a list by one item "scroll_up_one": [ "up", diff --git a/example_config/example.config.toml b/example_config/example.config.toml index a7132ac..182e7c5 100644 --- a/example_config/example.config.toml +++ b/example_config/example.config.toml @@ -55,8 +55,10 @@ show_logs = true # 3) F1-F12 # 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down - # Each definition can have two keys associated with it + +# WARNING "scroll_many" only accepts control, alt, shift, with no secondary option + # If any key clashes are found, oxker will revert to it's default keymap [keymap] @@ -74,16 +76,23 @@ filter_mode = ["/", "F1"] quit = ["q"] # Save logs of selected container to file on disk save_logs = ["s"] +# TODO "scroll_down_many" will be removed in the next release # scroll down a list by many scroll_down_many = ["pagedown"] +# TODO rename in next release # scroll down a list by one item scroll_down_one = ["down", "j"] + # scroll down to the end of a list scroll_end = ["end"] +# Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x +scroll_many = ["control"] # scroll up to the start of a list scroll_start = ["home"] +# TODO "scroll_up_many" will be removed in the next release # scroll up a list by many scroll_up_many = ["pageup"] +# TODO rename in next release # scroll up a list by one item scroll_up_one = ["up", "k"] # Horizontal scroll of the logs @@ -111,7 +120,6 @@ toggle_help = ["h"] toggle_mouse_capture = ["m"] # Reduce the height of the logs list section log_section_height_decrease = ["-"] -# Increase the height of the logs list section log_section_height_increase = ["+"] # Toggle visibility of the log section log_section_toggle = ["\\"] @@ -191,6 +199,7 @@ selected_filter_text = "black" # Highlighted text color highlight = "magenta" + # The color the of Docker commands available for each container [colors.commands] # Background color of panel diff --git a/src/app_data/container_state.rs b/src/app_data/container_state.rs index d5a4ff6..d31550e 100644 --- a/src/app_data/container_state.rs +++ b/src/app_data/container_state.rs @@ -630,7 +630,6 @@ impl Logs { } } - // TODO test me! /// If scrolling horiztonally along the logs, display a counter of the position in the in the scroll, `x/y` pub fn get_scroll_title(&mut self, width: u16) -> Option { if self.horizontal_scroll_able(width) { @@ -938,7 +937,7 @@ mod tests { text::{Line, Text}, }; - use crate::{ + use crate::{ app_data::{ContainerImage, Logs, LogsTz, RunningState}, ui::log_sanitizer, }; diff --git a/src/config/config.toml b/src/config/config.toml index 25ee594..182e7c5 100644 --- a/src/config/config.toml +++ b/src/config/config.toml @@ -56,6 +56,9 @@ show_logs = true # 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down # Each definition can have two keys associated with it + +# WARNING "scroll_many" only accepts control, alt, shift, with no secondary option + # If any key clashes are found, oxker will revert to it's default keymap [keymap] @@ -73,17 +76,23 @@ filter_mode = ["/", "F1"] quit = ["q"] # Save logs of selected container to file on disk save_logs = ["s"] +# TODO "scroll_down_many" will be removed in the next release # scroll down a list by many scroll_down_many = ["pagedown"] +# TODO rename in next release # scroll down a list by one item scroll_down_one = ["down", "j"] # scroll down to the end of a list scroll_end = ["end"] +# Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x +scroll_many = ["control"] # scroll up to the start of a list scroll_start = ["home"] +# TODO "scroll_up_many" will be removed in the next release # scroll up a list by many scroll_up_many = ["pageup"] +# TODO rename in next release # scroll up a list by one item scroll_up_one = ["up", "k"] # Horizontal scroll of the logs diff --git a/src/config/keymap_parser.rs b/src/config/keymap_parser.rs index 808cc18..3f62e44 100644 --- a/src/config/keymap_parser.rs +++ b/src/config/keymap_parser.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crossterm::event::KeyCode; +use crossterm::event::{KeyCode, KeyModifiers}; /// The macro accepts a list of struct names with key names /// Returns a struct where every key name is an Option, with the correct derived attributes @@ -12,6 +12,7 @@ macro_rules! optional_config_struct { $( $key_name: Option>, )* + pub scroll_many: Option>, } )* }; @@ -24,9 +25,10 @@ macro_rules! config_struct { $( #[derive(Debug, Clone, PartialEq, Eq)] pub struct $struct_name { - $( + $( pub $key_name: (KeyCode, Option), )* + pub scroll_many: KeyModifiers, } )* }; @@ -47,11 +49,15 @@ optional_config_struct!( log_scroll_back, quit, save_logs, + // TODO remove in next release scroll_down_many, + // TODO rename in next release scroll_down_one, scroll_end, scroll_start, + // TODO remove in next release scroll_up_many, + // TODO rename in next release scroll_up_one, select_next_panel, select_previous_panel, @@ -84,11 +90,15 @@ config_struct!( log_scroll_back, quit, save_logs, + // TODO remove in next release scroll_down_many, + // TODO rename in next release scroll_down_one, scroll_end, scroll_start, + // TODO remove in next release scroll_up_many, + // TODO rename in next release scroll_up_one, select_next_panel, select_previous_panel, @@ -122,11 +132,16 @@ impl Keymap { log_scroll_forward: (KeyCode::Right, None), quit: (KeyCode::Char('q'), None), save_logs: (KeyCode::Char('s'), None), + // TODO remove in next release scroll_down_many: (KeyCode::PageDown, None), + // TODO rename in next release scroll_down_one: (KeyCode::Down, Some(KeyCode::Char('j'))), scroll_end: (KeyCode::End, None), scroll_start: (KeyCode::Home, None), + scroll_many: KeyModifiers::CONTROL, + // TODO remove in next release scroll_up_many: (KeyCode::PageUp, None), + // TODO rename in next release scroll_up_one: (KeyCode::Up, Some(KeyCode::Char('k'))), select_next_panel: (KeyCode::Tab, None), select_previous_panel: (KeyCode::BackTab, None), @@ -243,6 +258,10 @@ impl From> for Keymap { &mut keymap.toggle_mouse_capture, &mut clash, ); + // TODO need to check for clashes when using additional modifiers + if let Some(scroll_many) = Self::try_parse_modifier(ck.scroll_many) { + keymap.scroll_many = scroll_many; + } } // A very basic clash check, every key has been inserted into a hashset, and a counter has been increased // if the counter and hashet length don't match, then there's a clash, and we just return the default keymap @@ -255,6 +274,20 @@ impl From> for Keymap { } impl Keymap { + // Allowable key modifiers are only `shift`, `control`, `alt` + fn try_parse_modifier(input: Option>) -> Option { + input.and_then(|input| { + input + .first() + .and_then(|input| match input.to_lowercase().trim() { + "control" => Some(KeyModifiers::CONTROL), + "alt" => Some(KeyModifiers::ALT), + "shift" => Some(KeyModifiers::SHIFT), + _ => None, + }) + }) + } + /// Try to parse a &[String] into a Vec of keycodes, at most the output will have 2 entries /// This might fail on MacOS due to Backspace and Delete working in a different manner as to how they work on Linux & Windows /// I think that on MacOS `Del` becomes `Fwd Del`, and `Backspace` becomes `Delete` @@ -326,7 +359,7 @@ impl Keymap { #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { - use crossterm::event::KeyCode; + use crossterm::event::{KeyCode, KeyModifiers}; use crate::config::keymap_parser::ConfigKeymap; @@ -393,6 +426,7 @@ mod tests { scroll_down_one: None, scroll_end: None, scroll_start: None, + scroll_many: None, scroll_up_many: None, scroll_up_one: None, select_next_panel: None, @@ -423,78 +457,79 @@ mod tests { let input = ConfigKeymap { clear: gen_v(("a", "b")), - delete_confirm: gen_v(("e", "f")), - delete_deny: gen_v(("c", "d")), + delete_confirm: gen_v(("c", "d")), + delete_deny: gen_v(("e", "fd")), exec: gen_v(("g", "h")), filter_mode: gen_v(("i", "j")), - force_redraw: gen_v(("F1", "F2")), - log_section_height_decrease: gen_v(("-", "Z")), - log_section_height_increase: gen_v(("=", "X")), - log_scroll_forward: gen_v(("right", "R")), - log_scroll_back: gen_v(("left", "L")), - log_section_toggle: gen_v(("Y", "W")), - quit: gen_v(("k", "l")), - save_logs: gen_v(("m", "n")), - scroll_down_many: gen_v(("o", "p")), - scroll_down_one: gen_v(("q", "r")), - scroll_end: gen_v(("s", "t")), - scroll_start: gen_v(("u", "v")), - scroll_up_many: gen_v(("w", "x")), - scroll_up_one: gen_v(("y", "z")), - select_next_panel: gen_v(("0", "1")), - select_previous_panel: gen_v(("2", "3")), - sort_by_cpu: gen_v(("F11", "F12")), - sort_by_id: gen_v(("[", "]")), - sort_by_image: gen_v(("A", "B")), - sort_by_memory: gen_v(("/", "\\")), - sort_by_name: gen_v(("4", "5")), - sort_by_rx: gen_v(("C", "D")), - sort_by_state: gen_v(("6", "7")), - sort_by_status: gen_v(("8", "9")), - sort_by_tx: gen_v(("insert", "TAB")), - sort_reset: gen_v(("up", "down")), - toggle_help: gen_v(("home", "end")), - toggle_mouse_capture: gen_v(("pagedown", "PAGEUP")), + force_redraw: gen_v(("k", "l")), + log_section_height_decrease: gen_v(("m", "n")), + log_section_height_increase: gen_v(("o", "p")), + log_scroll_forward: gen_v(("q", "r")), + log_scroll_back: gen_v(("s", "t")), + log_section_toggle: gen_v(("u", "v")), + quit: gen_v(("w", "x")), + save_logs: gen_v(("y", "z")), + scroll_down_many: gen_v(("1", "2")), + scroll_down_one: gen_v(("3", "4")), + scroll_end: gen_v(("5", "6")), + scroll_many: Some(vec!["alt".to_owned()]), + scroll_start: gen_v(("7", "8")), + scroll_up_many: gen_v(("9", "0")), + scroll_up_one: gen_v(("F1", "F2")), + select_next_panel: gen_v(("F3", "F4")), + select_previous_panel: gen_v(("F5", "F6")), + sort_by_cpu: gen_v(("F7", "F8")), + sort_by_id: gen_v(("F9", "F10")), + sort_by_image: gen_v(("F11", "F12")), + sort_by_memory: gen_v(("HOME", "END")), + sort_by_name: gen_v(("UP", "DOWN")), + sort_by_rx: gen_v(("LEFT", "RIGHT")), + sort_by_state: gen_v(("[", "]")), + sort_by_status: gen_v(("INSERTt", "TAB")), + sort_by_tx: gen_v(("PAGEDOWN", "PAGEUP")), + sort_reset: gen_v((",", ".")), + toggle_help: gen_v(("-", "=")), + toggle_mouse_capture: gen_v(("\\", "/")), }; let result = Keymap::from(Some(input)); let expected = 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'))), - force_redraw: (KeyCode::F(1), Some(KeyCode::F(2))), - log_section_height_decrease: (KeyCode::Char('-'), Some(KeyCode::Char('Z'))), - log_section_height_increase: (KeyCode::Char('='), Some(KeyCode::Char('X'))), - log_section_toggle: (KeyCode::Char('Y'), Some(KeyCode::Char('W'))), - log_scroll_forward: (KeyCode::Right, Some(KeyCode::Char('R'))), - log_scroll_back: (KeyCode::Left, Some(KeyCode::Char('L'))), + delete_deny: (KeyCode::Char('e'), None), + delete_confirm: (KeyCode::Char('c'), Some(KeyCode::Char('d'))), exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))), 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(11), 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('A'), Some(KeyCode::Char('B'))), - sort_by_rx: (KeyCode::Char('C'), Some(KeyCode::Char('D'))), - sort_by_tx: (KeyCode::Insert, Some(KeyCode::Tab)), - sort_reset: (KeyCode::Up, Some(KeyCode::Down)), - toggle_help: (KeyCode::Home, Some(KeyCode::End)), - toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)), + force_redraw: (KeyCode::Char('k'), Some(KeyCode::Char('l'))), + log_section_height_increase: (KeyCode::Char('o'), Some(KeyCode::Char('p'))), + log_section_height_decrease: (KeyCode::Char('m'), Some(KeyCode::Char('n'))), + log_section_toggle: (KeyCode::Char('u'), Some(KeyCode::Char('v'))), + log_scroll_forward: (KeyCode::Char('q'), Some(KeyCode::Char('r'))), + log_scroll_back: (KeyCode::Char('s'), Some(KeyCode::Char('t'))), + quit: (KeyCode::Char('w'), Some(KeyCode::Char('x'))), + save_logs: (KeyCode::Char('y'), Some(KeyCode::Char('z'))), + scroll_down_many: (KeyCode::Char('1'), Some(KeyCode::Char('2'))), + scroll_down_one: (KeyCode::Char('3'), Some(KeyCode::Char('4'))), + scroll_end: (KeyCode::Char('5'), Some(KeyCode::Char('6'))), + scroll_start: (KeyCode::Char('7'), Some(KeyCode::Char('8'))), + scroll_up_many: (KeyCode::Char('9'), Some(KeyCode::Char('0'))), + scroll_up_one: (KeyCode::F(1), Some(KeyCode::F(2))), + select_next_panel: (KeyCode::F(3), Some(KeyCode::F(4))), + select_previous_panel: (KeyCode::F(5), Some(KeyCode::F(6))), + sort_by_name: (KeyCode::Up, Some(KeyCode::Down)), + sort_by_state: (KeyCode::Char('['), Some(KeyCode::Char(']'))), + sort_by_status: (KeyCode::Tab, None), + sort_by_cpu: (KeyCode::F(7), Some(KeyCode::F(8))), + sort_by_memory: (KeyCode::Home, Some(KeyCode::End)), + sort_by_id: (KeyCode::F(9), Some(KeyCode::F(10))), + sort_by_image: (KeyCode::F(11), Some(KeyCode::F(12))), + sort_by_rx: (KeyCode::Left, Some(KeyCode::Right)), + sort_by_tx: (KeyCode::PageDown, Some(KeyCode::PageUp)), + sort_reset: (KeyCode::Char(','), Some(KeyCode::Char('.'))), + toggle_help: (KeyCode::Char('-'), Some(KeyCode::Char('='))), + toggle_mouse_capture: (KeyCode::Char('\\'), Some(KeyCode::Char('/'))), + scroll_many: KeyModifiers::ALT, }; - assert_eq!(expected, result); } } diff --git a/src/input_handler/message.rs b/src/input_handler/message.rs index ba50101..1d5ab4a 100644 --- a/src/input_handler/message.rs +++ b/src/input_handler/message.rs @@ -3,5 +3,5 @@ use crossterm::event::{KeyCode, KeyModifiers, MouseEvent}; #[derive(Debug, Clone, Copy)] pub enum InputMessages { ButtonPress((KeyCode, KeyModifiers)), - MouseEvent(MouseEvent), + MouseEvent((MouseEvent, KeyModifiers)), } diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs index faa2d03..fcf098c 100644 --- a/src/input_handler/mod.rs +++ b/src/input_handler/mod.rs @@ -67,7 +67,7 @@ impl InputHandler { while let Some(message) = self.rx.recv().await { match message { InputMessages::ButtonPress(key) => self.button_press(key.0, key.1).await, - InputMessages::MouseEvent(mouse_event) => { + InputMessages::MouseEvent((mouse_event, modifider)) => { let status = self.gui_state.lock().get_status(); let contains = |s: Status| status.contains(&s); @@ -78,7 +78,7 @@ impl InputHandler { | !contains(Status::DeleteConfirm) | !contains(Status::Filter) { - self.mouse_press(mouse_event); + self.mouse_press(mouse_event, modifider); } } } @@ -285,20 +285,33 @@ impl InputHandler { } } + /// If keymap.scroll_modifier is pressed, return 10, else return 1, to speed up scrolling + fn get_modifier_total(&self, modifier: KeyModifiers) -> u8 { + if modifier == self.keymap.scroll_many { + 10 + } else { + 1 + } + } + /// Advance the "cursor" along the logs - fn logs_forward(&self) { + fn logs_forward(&self, modifier: KeyModifiers) { let panel = self.gui_state.lock().get_selected_panel(); if panel == SelectablePanel::Logs { - let width = self.gui_state.lock().get_screen_width(); - self.app_data.lock().log_forward(width); + for _ in 0..self.get_modifier_total(modifier) { + let width = self.gui_state.lock().get_screen_width(); + self.app_data.lock().log_forward(width); + } } } /// Retreat the "cursor" along the logs - fn logs_back(&self) { + fn logs_back(&self, modifier: KeyModifiers) { let panel = self.gui_state.lock().get_selected_panel(); if panel == SelectablePanel::Logs { - self.app_data.lock().log_back(); + for _ in 0..self.get_modifier_total(modifier) { + self.app_data.lock().log_back(); + } } } @@ -489,7 +502,7 @@ impl InputHandler { /// Handle button presses in all other scenarios #[allow(clippy::cognitive_complexity)] - async fn handle_others(&mut self, key_code: KeyCode) { + async fn handle_others(&mut self, key_code: KeyCode, modifier: KeyModifiers) { self.handle_sort(key_code); // shift key plus arrows match key_code { @@ -559,28 +572,28 @@ impl InputHandler { _ if self.keymap.scroll_up_one.0 == key_code || self.keymap.scroll_up_one.1 == Some(key_code) => { - self.scroll_up(); + self.scroll_up(modifier); } _ if self.keymap.scroll_up_many.0 == key_code || self.keymap.scroll_up_many.1 == Some(key_code) => { for _ in 0..=6 { - self.scroll_up(); + self.scroll_up(modifier); } } _ if self.keymap.scroll_down_one.0 == key_code || self.keymap.scroll_down_one.1 == Some(key_code) => { - self.scroll_down(); + self.scroll_down(modifier); } _ if self.keymap.scroll_down_many.0 == key_code || self.keymap.scroll_down_many.1 == Some(key_code) => { for _ in 0..=6 { - self.scroll_down(); + self.scroll_down(modifier); } } @@ -594,13 +607,13 @@ impl InputHandler { _ if self.keymap.log_scroll_back.0 == key_code || self.keymap.log_scroll_back.1 == Some(key_code) => { - self.logs_back(); + self.logs_back(modifier); } _ if self.keymap.log_scroll_forward.0 == key_code || self.keymap.log_scroll_forward.1 == Some(key_code) => { - self.logs_forward(); + self.logs_forward(modifier); } KeyCode::Enter => self.enter_key().await, @@ -637,7 +650,7 @@ impl InputHandler { } else if contains_delete { self.handle_delete(key_code).await; } else { - self.handle_others(key_code).await; + self.handle_others(key_code, key_modifier).await; } } } @@ -662,7 +675,7 @@ impl InputHandler { } /// Handle mouse button events - fn mouse_press(&self, mouse_event: MouseEvent) { + fn mouse_press(&self, mouse_event: MouseEvent, modifier: KeyModifiers) { let status = self.gui_state.lock().get_status(); if status.contains(&Status::Help) { let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1); @@ -672,8 +685,8 @@ impl InputHandler { } } else { match mouse_event.kind { - MouseEventKind::ScrollUp => self.scroll_up(), - MouseEventKind::ScrollDown => self.scroll_down(), + MouseEventKind::ScrollUp => self.scroll_up(modifier), + MouseEventKind::ScrollDown => self.scroll_down(modifier), MouseEventKind::Down(MouseButton::Left) => { let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1); let header = self.gui_state.lock().get_intersect_header(mouse_point); @@ -693,21 +706,37 @@ impl InputHandler { } /// Change state to next, depending which panel is currently in focus - fn scroll_down(&self) { + fn scroll_down(&self, modifier: KeyModifiers) { let selected_panel = self.gui_state.lock().get_selected_panel(); match selected_panel { - SelectablePanel::Containers => self.app_data.lock().containers_next(), - SelectablePanel::Logs => self.app_data.lock().log_next(), + SelectablePanel::Containers => { + for _ in 0..self.get_modifier_total(modifier) { + self.app_data.lock().containers_next(); + } + } + SelectablePanel::Logs => { + for _ in 0..self.get_modifier_total(modifier) { + self.app_data.lock().log_next(); + } + } SelectablePanel::Commands => self.app_data.lock().docker_controls_next(), } } /// Change state to previous, depending which panel is currently in focus - fn scroll_up(&self) { + fn scroll_up(&self, modifier: KeyModifiers) { let selected_panel = self.gui_state.lock().get_selected_panel(); match selected_panel { - SelectablePanel::Containers => self.app_data.lock().containers_previous(), - SelectablePanel::Logs => self.app_data.lock().log_previous(), + SelectablePanel::Containers => { + for _ in 0..self.get_modifier_total(modifier) { + self.app_data.lock().containers_previous(); + } + } + SelectablePanel::Logs => { + for _ in 0..self.get_modifier_total(modifier) { + self.app_data.lock().log_previous(); + } + } SelectablePanel::Commands => self.app_data.lock().docker_controls_previous(), } } diff --git a/src/ui/draw_blocks/help.rs b/src/ui/draw_blocks/help.rs index 0694ddd..83a3051 100644 --- a/src/ui/draw_blocks/help.rs +++ b/src/ui/draw_blocks/help.rs @@ -109,13 +109,18 @@ impl HelpInfo { button_item("PgUp PgDown"), or(), button_item("Home End"), - button_desc("change selected line"), + button_desc("scroll vertically"), ]), Line::from(vec![ space(), button_item("← →"), button_desc("horizontal scroll across logs"), ]), + Line::from(vec![ + space(), + button_item("ctrl"), + button_desc("increase scroll speed, used in conjuction scroll keys"), + ]), Line::from(vec![ space(), button_item("enter"), @@ -280,6 +285,11 @@ impl HelpInfo { 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(km.scroll_many.to_string().as_str()), + button_desc("increase scroll speed, used in conjuction scroll keys"), + ]), Line::from(vec![ space(), button_item("enter"), @@ -440,7 +450,7 @@ pub fn draw( #[allow(clippy::unwrap_used, clippy::too_many_lines)] mod tests { use crate::config::{AppColors, Keymap}; - use crossterm::event::KeyCode; + use crossterm::event::{KeyCode, KeyModifiers}; use insta::assert_snapshot; use jiff::tz::TimeZone; use ratatui::style::{Color, Modifier}; @@ -449,9 +459,10 @@ mod tests { #[test] /// This will cause issues once the version has more than the current 5 chars (0.5.0) + /// This test is incredibly annoying /// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg); fn test_draw_blocks_help() { - let mut setup = test_setup(87, 36, true, true); + let mut setup = test_setup(87, 37, true, true); let tz = setup.app_data.lock().config.timezone.clone(); setup @@ -471,9 +482,17 @@ mod tests { for (row_index, result_row) in get_result(&setup) { for (result_cell_index, result_cell) in result_row.iter().enumerate() { + println!( + "{} {} {} {} {}", + row_index, + result_cell_index, + result_cell.symbol(), + result_cell.bg, + result_cell.fg + ); match (row_index, result_cell_index) { // first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area - (0 | 35, _) | (0..=34, 0 | 86) => { + (0 | 36, _) | (0..=35, 0 | 86) => { assert_eq!(result_cell.bg, Color::Reset); assert_eq!(result_cell.fg, Color::Reset); } @@ -487,15 +506,16 @@ mod tests { | (12, 19..=66) | (14, 2..=10 | 13..=27) | (15, 2..=10 | 13..=21 | 24..=40 | 43..=56) - | (16 | 26 | 28, 2..=10) - | (17 | 25, 2..=12) - | (18 | 19 | 20 | 21 | 22 | 24 | 27 | 29, 2..=8) - | (23, 2..=9 | 12..=18) => { + | (16 | 27 | 29, 2..=10) + | (17, 2..=11) + | (18 | 26, 2..=12) + | (19 | 20 | 21 | 22 | 24 | 25 | 28 | 23 | 30, 2..=8) + | (24, 2..=9 | 12..=18) => { assert_eq!(result_cell.bg, Color::Magenta); assert_eq!(result_cell.fg, Color::White); } // The URL is yellow and underlined - (32, 25..=60) => { + (33, 25..=60) => { assert_eq!(result_cell.bg, Color::Magenta); assert_eq!(result_cell.fg, Color::White); assert_eq!(result_cell.modifier, Modifier::UNDERLINED); @@ -512,9 +532,10 @@ mod tests { #[test] /// Test that the help panel gets drawn with custom colors + /// This test is incredibly 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, 36, true, true); + let mut setup = test_setup(87, 37, true, true); let mut colors = AppColors::new(); let tz = setup.app_data.lock().config.timezone.clone(); @@ -540,7 +561,7 @@ mod tests { for (result_cell_index, result_cell) in result_row.iter().enumerate() { match (row_index, result_cell_index) { // first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area - (0 | 35, _) | (0..=34, 0 | 86) => { + (0 | 36, _) | (0..=35, 0 | 86) => { assert_eq!(result_cell.bg, Color::Reset); assert_eq!(result_cell.fg, Color::Reset); } @@ -554,15 +575,16 @@ mod tests { | (12, 19..=66) | (14, 2..=10 | 13..=27) | (15, 2..=10 | 13..=21 | 24..=40 | 43..=56) - | (16 | 26 | 28, 2..=10) - | (17 | 25, 2..=12) - | (18 | 19 | 20 | 21 | 22 | 24 | 27 | 29, 2..=8) - | (23, 2..=9 | 12..=18) => { + | (16 | 27 | 29, 2..=10) + | (17, 2..=11) + | (18 | 26, 2..=12) + | (19 | 20 | 21 | 22 | 24 | 25 | 28 | 23 | 30, 2..=8) + | (24, 2..=9 | 12..=18) => { assert_eq!(result_cell.bg, Color::Black); assert_eq!(result_cell.fg, Color::Yellow); } // The URL is yellow and underlined - (32, 25..=60) => { + (33, 25..=60) => { assert_eq!(result_cell.bg, Color::Black); assert_eq!(result_cell.fg, Color::Yellow); assert_eq!(result_cell.modifier, Modifier::UNDERLINED); @@ -599,6 +621,7 @@ mod tests { scroll_down_many: (KeyCode::Char('n'), None), scroll_down_one: (KeyCode::Char('o'), None), scroll_end: (KeyCode::Char('p'), None), + scroll_many: KeyModifiers::ALT, scroll_start: (KeyCode::Char('q'), None), scroll_up_many: (KeyCode::Char('r'), None), scroll_up_one: (KeyCode::Char('s'), None), @@ -650,6 +673,7 @@ mod tests { 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_many: KeyModifiers::ALT, 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'))), @@ -701,6 +725,7 @@ mod tests { scroll_down_many: (KeyCode::Char('n'), None), scroll_down_one: (KeyCode::Char('o'), Some(KeyCode::Char('O'))), scroll_end: (KeyCode::Char('p'), None), + scroll_many: KeyModifiers::ALT, scroll_start: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))), scroll_up_many: (KeyCode::Char('r'), None), scroll_up_one: (KeyCode::Char('s'), Some(KeyCode::Char('S'))), diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help.snap index de059d4..ad841ca 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help.snap @@ -17,8 +17,9 @@ expression: setup.terminal.backend() " │ A simple tui to view & control docker containers │ " " │ │ " " │ ( tab ) or ( shift+tab ) change panels │ " -" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ " +" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ " " │ ( ← → ) horizontal scroll across logs │ " +" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( e ) exec into a container │ " " │ ( f ) force clear the screen & redraw the gui │ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_colors.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_colors.snap index de059d4..ad841ca 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_colors.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_colors.snap @@ -17,8 +17,9 @@ expression: setup.terminal.backend() " │ A simple tui to view & control docker containers │ " " │ │ " " │ ( tab ) or ( shift+tab ) change panels │ " -" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ " +" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ " " │ ( ← → ) horizontal scroll across logs │ " +" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( e ) exec into a container │ " " │ ( f ) force clear the screen & redraw the gui │ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_one_definition.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_one_definition.snap index eee704c..f8933a4 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_one_definition.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_one_definition.snap @@ -25,6 +25,7 @@ expression: setup.terminal.backend() " │ ( q ) scroll list to start │ " " │ ( h ) horizontal scroll logs right │ " " │ ( g ) horizontal scroll logs left │ " +" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( d ) exec into a container │ " " │ ( f ) force clear the screen & redraw the gui │ " @@ -50,5 +51,4 @@ expression: setup.terminal.backend() " │ │ " " │ currently an early work in progress, all and any input appreciated │ " " │ https://github.com/mrjackwills/oxker │ " -" │ │ " " ╰────────────────────────────────────────────────────────────────────────────────────╯ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_two_definitions.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_two_definitions.snap index 418e684..40866fb 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_two_definitions.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_custom_keymap_two_definitions.snap @@ -25,6 +25,7 @@ expression: setup.terminal.backend() " │ ( p ) or ( P ) scroll list to start │ " " │ ( g ) or ( G ) horizontal scroll logs right │ " " │ ( f ) or ( F ) horizontal scroll logs left │ " +" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( d ) or ( D ) exec into a container │ " " │ ( f ) or ( F ) force clear the screen & redraw the gui │ " @@ -50,5 +51,4 @@ expression: setup.terminal.backend() " │ │ " " │ currently an early work in progress, all and any input appreciated │ " " │ https://github.com/mrjackwills/oxker │ " -" │ │ " " ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_one_and_two_definitions.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_one_and_two_definitions.snap index 15f2de0..3694cac 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_one_and_two_definitions.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_one_and_two_definitions.snap @@ -25,6 +25,7 @@ expression: setup.terminal.backend() " │ ( q ) or ( Q ) scroll list to start │ " " │ ( h ) horizontal scroll logs right │ " " │ ( g ) or ( G ) horizontal scroll logs left │ " +" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( d ) exec into a container │ " " │ ( f ) force clear the screen & redraw the gui │ " @@ -50,5 +51,4 @@ expression: setup.terminal.backend() " │ │ " " │ currently an early work in progress, all and any input appreciated │ " " │ https://github.com/mrjackwills/oxker │ " -" │ │ " " ╰────────────────────────────────────────────────────────────────────────────────────────────╯ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_show_timezone.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_show_timezone.snap index 82193cb..67b6242 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_show_timezone.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__help__tests__draw_blocks_help_show_timezone.snap @@ -18,8 +18,9 @@ expression: setup.terminal.backend() " │ logs timezone: Asia/Tokyo │ " " │ │ " " │ ( tab ) or ( shift+tab ) change panels │ " -" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ " +" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ " " │ ( ← → ) horizontal scroll across logs │ " +" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ " " │ ( enter ) send docker container command │ " " │ ( e ) exec into a container │ " " │ ( f ) force clear the screen & redraw the gui │ " @@ -37,5 +38,4 @@ expression: setup.terminal.backend() " │ currently an early work in progress, all and any input appreciated │ " " │ https://github.com/mrjackwills/oxker │ " " │ │ " -" │ │ " " ╰───────────────────────────────────────────────────────────────────────────────────╯ " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__tests__draw_blocks_whole_layout_help_panel.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__tests__draw_blocks_whole_layout_help_panel.snap index 65aed11..f6603f1 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__tests__draw_blocks_whole_layout_help_panel.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__tests__draw_blocks_whole_layout_help_panel.snap @@ -4,23 +4,23 @@ expression: setup.terminal.backend() --- " name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) exit help " "╭ Containers 1/3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭──────────────╮" -"│⚪ container_1 ✓ running Up 1 hour 03.00% 30.00 kB / 30.00 kB 1 image_1 0.00 kB 0.00 kB ││▶ pause │" Hidden by multi-width symbols: [(2, " ")] -"│ container_2 ✓ running Up 2 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││ restart │" -"│ container_3 ✓ running Up 3 ho│ │ ││ stop │" +"│⚪ container_1 ✓ running Up 1 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││▶ pause │" Hidden by multi-width symbols: [(2, " ")] +"│ container_2 ✓ running Up 2 ho│ │ ││ restart │" +"│ container_3 ✓ running Up 3 ho│ 88 │ ││ stop │" "│ │ 88 │ ││ delete │" "│ │ 88 │ ││ │" -"╰────────────────────────────────────│ 88 │────────────────────╯╰──────────────╯" -"╭ Logs 3/3 - container_1 - image_1 ──│ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │────────────────────────────────────╮" -"│ line 1 │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ │" -"│ line 2 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │" -"│▶ line 3 │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │" -"│ │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │" +"╰────────────────────────────────────│ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │────────────────────╯╰──────────────╯" +"╭ Logs 3/3 - container_1 - image_1 ──│ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │────────────────────────────────────╮" +"│ line 1 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │" +"│ line 2 │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │" +"│▶ line 3 │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │" "│ │ │ │" "│ │ A simple tui to view & control docker containers │ │" "│ │ │ │" "│ │ ( tab ) or ( shift+tab ) change panels │ │" -"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ │" +"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ │" "│ │ ( ← → ) horizontal scroll across logs │ │" +"│ │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ │" "│ │ ( enter ) send docker container command │ │" "│ │ ( e ) exec into a container │ │" "│ │ ( f ) force clear the screen & redraw the gui │ │" @@ -38,7 +38,7 @@ expression: setup.terminal.backend() "│ │ •• • │ currently an early work in progress, all and any input appreciated │ ││127.0.0.1 8003 8003│" "│ │ • • │ https://github.com/mrjackwills/oxker │ ││ │" "│ │ •• • • │ │ ││ │" -"│ │• •• ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │" -"│ │• • ││ │• • ││ │" +"│ │• •• │ │ ││ │" +"│ │• • ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │" "│ │ ││ │ ││ │" "╰───────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────╯╰────────────────────────────╯" diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 3ee8d15..c46dacf 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -255,7 +255,10 @@ impl Ui { event::MouseEventKind::Down(_) | event::MouseEventKind::ScrollDown | event::MouseEventKind::ScrollUp => { - self.input_tx.send(InputMessages::MouseEvent(m)).await.ok(); + self.input_tx + .send(InputMessages::MouseEvent((m, m.modifiers))) + .await + .ok(); } _ => (), }