From 49628613bc27f8b455153894700db72603de44e7 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Tue, 25 Feb 2020 23:28:56 -0500 Subject: [PATCH 1/9] [skip travis] tweak documentation regarding 32-bit --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 661cdfe4..d71dafb0 100644 --- a/README.md +++ b/README.md @@ -38,17 +38,23 @@ For information about config files, see [this document](./docs/config.md) for mo In all cases you can install the in-development version by cloning from this repo and using `cargo build --release`. This is built and tested with Rust Stable (1.41.0 as of writing). -In addition to the below methods, you can also get release versions using `cargo install bottom`, or manually building from the [Releases](https://github.com/ClementTsang/bottom/releases) page by downloading and building. +In addition to the below methods, you can manually build from the [Releases](https://github.com/ClementTsang/bottom/releases) page by downloading and building. -I officially support and test 64-bit variants. I will also build and release 32-bit variants for Linux and Windows, but I'm (currently) not testing whether they work. +I officially support and test 64-bit versions of [Tier 1](https://forge.rust-lang.org/release/platform-support.html) Rust targets. I will try to build and release 32-bit versions for Linux and Windows, but as of now, I will not be testing 32-bit for validity beyond building. + +### Cargo + +```bash +cargo install bottom +``` ### Linux -Other installation methods based on distros are as follows: +Installation methods on a per-distro basis: #### Arch Linux -You can get the release versions from the [AUR](https://aur.archlinux.org/packages/bottom/) by installing `bottom`. For example: +You can get the release versions from the [AUR](https://aur.archlinux.org/packages/bottom/) by installing `bottom`. For example, using `yay`: ```bash yay bottom @@ -56,7 +62,7 @@ yay bottom #### Debian (and anything based on it, like Ubuntu) -A `.deb` file is provided on each [release](https://github.com/ClementTsang/bottom/releases/latest). For example: +A `.deb` file is provided on each [release](https://github.com/ClementTsang/bottom/releases/latest): ```bash curl -LO https://github.com/ClementTsang/bottom/releases/download/0.2.2/bottom_0.2.2_amd64.deb From 088f9fbb07e4fba15774f9b6d8c4b82c8434af1e Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Wed, 26 Feb 2020 08:09:03 -0500 Subject: [PATCH 2/9] [skip travis] add contribution to readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index d71dafb0..bcd6ee54 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,12 @@ Note that `q` is disabled while in the search widget. - Scrolling with the mouse will scroll through the currently selected list if the widget is a scrollable table. +## Contribution + +Contribution is welcome! Just submit a PR. + +If you spot any issue with nobody assigned to it, or it seems like no work has started on it, feel free to try and do it! + ## Thanks, kudos, and all the like - This project is very much inspired by both [gotop](https://github.com/cjbassi/gotop) and [gtop](https://github.com/aksakalli/gtop). From 66a0b2ac1026c24066b509d8159b96476d01b1e7 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Wed, 26 Feb 2020 08:13:30 -0500 Subject: [PATCH 3/9] [skip travis] update github files once more --- .github/pull_request_template.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f9f599aa..cb2bf934 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,11 +23,11 @@ _Please state how this was tested:_ _Please ensure all are ticked (and actually done):_ -- [ ] Feature itself has been tested and verified to work -- [ ] Code has been linted +- [ ] Change has been tested to work +- [ ] Code has been linted using rustfmt - [ ] Code has been self-reviewed - [ ] Code has been tested and no new breakage is introduced -- [ ] Documentation has been added +- [ ] Documentation has been added/updated if needed ## Other information From 67f8baa0560f8e9fd493eca29dd203e48dedf2f3 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Tue, 25 Feb 2020 22:23:17 -0500 Subject: [PATCH 4/9] Fix unicode causing problems with search. --- Cargo.toml | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index fc7bc7d1..5b165446 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ lazy_static = "1.4.0" backtrace = "0.3" toml = "0.5.6" serde = {version = "1.0", features = ["derive"] } +unicode-segmentation = "1.6.0" [dev-dependencies] assert_cmd = "0.12" diff --git a/README.md b/README.md index bcd6ee54..aa47c58d 100644 --- a/README.md +++ b/README.md @@ -229,4 +229,5 @@ If you spot any issue with nobody assigned to it, or it seems like no work has s - [tokio](https://github.com/tokio-rs/tokio) - [toml-rs](https://github.com/alexcrichton/toml-rs) - [tui-rs](https://github.com/fdehau/tui-rs) + - [unicode-segmentation](https://github.com/unicode-rs/unicode-segmentation) - [winapi](https://github.com/retep998/winapi-rs) From d96751b786dd9a3122d1e26a889b83b0863a857b Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 10:21:03 -0500 Subject: [PATCH 5/9] [skip travis] Updated README to use 1.41 in general --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa47c58d..5f12fc52 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ For information about config files, see [this document](./docs/config.md) for mo ## Installation -In all cases you can install the in-development version by cloning from this repo and using `cargo build --release`. This is built and tested with Rust Stable (1.41.0 as of writing). +In all cases you can install the in-development version by cloning from this repo and using `cargo build --release`. This is built and tested with Rust Stable (1.41 as of writing). In addition to the below methods, you can manually build from the [Releases](https://github.com/ClementTsang/bottom/releases) page by downloading and building. @@ -230,4 +230,5 @@ If you spot any issue with nobody assigned to it, or it seems like no work has s - [toml-rs](https://github.com/alexcrichton/toml-rs) - [tui-rs](https://github.com/fdehau/tui-rs) - [unicode-segmentation](https://github.com/unicode-rs/unicode-segmentation) + - [unicode-width](https://github.com/unicode-rs/unicode-width) - [winapi](https://github.com/retep998/winapi-rs) From a755a5d41ce2dae03bb4ad952ac3587af22136b8 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 16:02:53 -0500 Subject: [PATCH 6/9] Switch to using unicode_segmentation's cursor as a basis on how we do cursor movement in search. --- Cargo.toml | 1 + src/app.rs | 182 ++++++++++++++++++++++++++++---------------------- src/canvas.rs | 99 ++++++++++++++------------- src/main.rs | 8 ++- 4 files changed, 162 insertions(+), 128 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5b165446..5d6bbf1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ backtrace = "0.3" toml = "0.5.6" serde = {version = "1.0", features = ["derive"] } unicode-segmentation = "1.6.0" +unicode-width = "0.1.7" [dev-dependencies] assert_cmd = "0.12" diff --git a/src/app.rs b/src/app.rs index d54fce76..1f983e32 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,9 +6,12 @@ pub mod data_farmer; use data_farmer::*; use crate::{canvas, constants, utils::error::Result}; - mod process_killer; +use unicode_segmentation::GraphemeCursor; + +const MAX_SEARCH_LENGTH: usize = 200; + #[derive(Debug, Clone, Copy)] pub enum WidgetPosition { Cpu, @@ -60,9 +63,9 @@ pub struct AppSearchState { pub is_enabled: bool, current_search_query: String, current_regex: Option>, - current_cursor_position: usize, pub is_blank_search: bool, pub is_invalid_search: bool, + pub grapheme_cursor: GraphemeCursor, } impl Default for AppSearchState { @@ -71,9 +74,9 @@ impl Default for AppSearchState { is_enabled: false, current_search_query: String::default(), current_regex: None, - current_cursor_position: 0, is_invalid_search: false, is_blank_search: true, + grapheme_cursor: GraphemeCursor::new(0, 0, true), } } } @@ -535,7 +538,8 @@ impl App { pub fn get_cursor_position(&self) -> usize { self.process_search_state .search_state - .current_cursor_position + .grapheme_cursor + .cur_cursor() } /// One of two functions allowed to run while in a dialog... @@ -576,23 +580,26 @@ impl App { WidgetPosition::Process => self.start_dd(), WidgetPosition::ProcessSearch => { if self.process_search_state.search_state.is_enabled - && self - .process_search_state - .search_state - .current_cursor_position < self - .process_search_state - .search_state - .current_search_query - .len() + && self.get_cursor_position() + < self + .process_search_state + .search_state + .current_search_query + .len() { self.process_search_state .search_state .current_search_query - .remove( - self.process_search_state - .search_state - .current_cursor_position, - ); + .remove(self.get_cursor_position()); + + self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new( + self.get_cursor_position(), + self.process_search_state + .search_state + .current_search_query + .len(), + true, + ); self.update_regex(); self.update_process_gui = true; @@ -619,9 +626,8 @@ impl App { pub fn clear_search(&mut self) { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - self.process_search_state - .search_state - .current_cursor_position = 0; + self.process_search_state.search_state.grapheme_cursor = + GraphemeCursor::new(0, 0, true); self.process_search_state.search_state.current_search_query = String::default(); self.process_search_state.search_state.is_blank_search = true; self.process_search_state.search_state.is_invalid_search = false; @@ -629,26 +635,46 @@ impl App { } } + pub fn search_walk_forward(&mut self, start_position: usize) { + self.process_search_state + .search_state + .grapheme_cursor + .next_boundary( + &self.process_search_state.search_state.current_search_query[start_position..], + start_position, + ) + .unwrap(); + } + + pub fn search_walk_back(&mut self, start_position: usize) { + self.process_search_state + .search_state + .grapheme_cursor + .prev_boundary( + &self.process_search_state.search_state.current_search_query[..start_position], + 0, + ) + .unwrap(); + } + pub fn on_backspace(&mut self) { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if self.process_search_state.search_state.is_enabled - && self - .process_search_state - .search_state - .current_cursor_position - > 0 - { - self.process_search_state - .search_state - .current_cursor_position -= 1; + if self.process_search_state.search_state.is_enabled && self.get_cursor_position() > 0 { + self.search_walk_back(self.get_cursor_position()); + self.process_search_state .search_state .current_search_query - .remove( - self.process_search_state - .search_state - .current_cursor_position, - ); + .remove(self.get_cursor_position()); + + self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new( + self.get_cursor_position(), + self.process_search_state + .search_state + .current_search_query + .len(), + true, + ); self.update_regex(); self.update_process_gui = true; @@ -683,16 +709,7 @@ impl App { pub fn on_left_key(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if self - .process_search_state - .search_state - .current_cursor_position - > 0 - { - self.process_search_state - .search_state - .current_cursor_position -= 1; - } + self.search_walk_back(self.get_cursor_position()); } } else if self.delete_dialog_state.is_showing_dd && !self.delete_dialog_state.is_on_yes { self.delete_dialog_state.is_on_yes = true; @@ -702,20 +719,7 @@ impl App { pub fn on_right_key(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if self - .process_search_state - .search_state - .current_cursor_position - < self - .process_search_state - .search_state - .current_search_query - .len() - { - self.process_search_state - .search_state - .current_cursor_position += 1; - } + self.search_walk_forward(self.get_cursor_position()); } } else if self.delete_dialog_state.is_showing_dd && self.delete_dialog_state.is_on_yes { self.delete_dialog_state.is_on_yes = false; @@ -725,9 +729,14 @@ impl App { pub fn skip_cursor_beginning(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - self.process_search_state - .search_state - .current_cursor_position = 0; + self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new( + 0, + self.process_search_state + .search_state + .current_search_query + .len(), + true, + ); } } } @@ -735,13 +744,17 @@ impl App { pub fn skip_cursor_end(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - self.process_search_state - .search_state - .current_cursor_position = self - .process_search_state - .search_state - .current_search_query - .len(); + self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new( + self.process_search_state + .search_state + .current_search_query + .len(), + self.process_search_state + .search_state + .current_search_query + .len(), + true, + ); } } } @@ -788,13 +801,12 @@ impl App { } pub fn on_char_key(&mut self, caught_char: char) { - // Forbid any char key presses when showing a dialog box... - // Skip control code chars if caught_char.is_control() { return; } + // Forbid any char key presses when showing a dialog box... if !self.is_in_dialog() { let current_key_press_inst = Instant::now(); if current_key_press_inst @@ -806,21 +818,29 @@ impl App { self.last_key_press = current_key_press_inst; if let WidgetPosition::ProcessSearch = self.current_widget_selected { - self.process_search_state + if self + .process_search_state .search_state .current_search_query - .insert( + .len() <= MAX_SEARCH_LENGTH + { + self.process_search_state + .search_state + .current_search_query + .insert(self.get_cursor_position(), caught_char); + + self.process_search_state.search_state.grapheme_cursor = GraphemeCursor::new( + self.get_cursor_position(), self.process_search_state .search_state - .current_cursor_position, - caught_char, + .current_search_query + .len(), + true, ); - self.process_search_state - .search_state - .current_cursor_position += 1; - - self.update_regex(); - self.update_process_gui = true; + self.search_walk_forward(self.get_cursor_position()); + self.update_regex(); + self.update_process_gui = true; + } } else { match caught_char { '/' => { diff --git a/src/canvas.rs b/src/canvas.rs index 82a117f8..02ea3ab5 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -4,7 +4,7 @@ use crate::{ data_conversion::{ConvertedCpuData, ConvertedProcessData}, utils::error, }; -use std::cmp::max; +use std::cmp::{max, min}; use std::collections::HashMap; use tui::{ backend, @@ -14,6 +14,8 @@ use tui::{ widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget}, Terminal, }; +use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; mod canvas_colours; use canvas_colours::*; @@ -1155,55 +1157,60 @@ impl Painter { fn draw_search_field( &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, ) { - let width = max(0, draw_loc.width as i64 - 34) as u64; - let query = app_state.get_current_search_query(); - let shrunk_query = if query.len() < width as usize { - query - } else { - &query[(query.len() - width as usize)..] - }; - + let width = max(0, draw_loc.width as i64 - 34) as u64; // TODO: [REFACTOR] Hard coding this is terrible. + let query = app_state.get_current_search_query().as_str(); + let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true) + .rev() + .enumerate(); // Reverse due to us wanting to draw from back -> front + let num_graphemes = min(UnicodeWidthStr::width_cjk(query), width as usize); let cursor_position = app_state.get_cursor_position(); - let query_with_cursor: Vec> = - if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected { - if cursor_position >= query.len() { - let mut q = vec![Text::styled( - shrunk_query.to_string(), - self.colours.text_style, - )]; + let mut query_with_cursor: Vec> = if let app::WidgetPosition::ProcessSearch = + app_state.current_widget_selected + { + let mut res = Vec::new(); + if cursor_position >= query.len() { + res.push(Text::styled( + " ", + self.colours.currently_selected_text_style, + )) + } - q.push(Text::styled( - " ".to_string(), - self.colours.currently_selected_text_style, - )); + res.extend( + grapheme_indices + .filter_map(|(itx, grapheme)| { + if itx >= num_graphemes { + None + } else { + let styled = if grapheme.0 == cursor_position { + Text::styled(grapheme.1, self.colours.currently_selected_text_style) + } else { + Text::styled(grapheme.1, self.colours.text_style) + }; + Some(styled) + } + }) + .collect::>(), + ); - q - } else { - shrunk_query - .chars() - .enumerate() - .map(|(itx, c)| { - if let app::WidgetPosition::ProcessSearch = - app_state.current_widget_selected - { - if itx == cursor_position { - return Text::styled( - c.to_string(), - self.colours.currently_selected_text_style, - ); - } - } - Text::styled(c.to_string(), self.colours.text_style) - }) - .collect::>() - } - } else { - vec![Text::styled( - shrunk_query.to_string(), - self.colours.text_style, - )] - }; + res + } else { + // This is easier - we just need to get a range of graphemes, rather than + // dealing with possibly inserting a cursor (as none is shown!) + grapheme_indices + .filter_map(|(itx, grapheme)| { + if itx >= num_graphemes { + None + } else { + let styled = Text::styled(grapheme.1, self.colours.text_style); + Some(styled) + } + }) + .collect::>() + }; + + // I feel like this is most definitely not the efficient way of doing this but eh + query_with_cursor.reverse(); let mut search_text = vec![if app_state.is_grouped() { Text::styled("Search by Name: ", self.colours.table_header_style) diff --git a/src/main.rs b/src/main.rs index da47da1f..e1c80dcd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -315,12 +315,18 @@ fn handle_mouse_event(event: MouseEvent, app: &mut App) { fn handle_key_event_or_break( event: KeyEvent, app: &mut App, rtx: &std::sync::mpsc::Sender, ) -> bool { + //debug!("KeyEvent: {:?}", event); + + // TODO: [PASTE] Note that this does NOT support some emojis like flags. This is due to us + // catching PER CHARACTER right now WITH A forced throttle! This means multi-char will not work. + // We can solve this (when we do paste probably) while keeping the throttle (mainly meant for movement) + // by throttling after *bulk+singular* actions, not just singular ones. + if event.modifiers.is_empty() { // Required catch for searching - otherwise you couldn't search with q. if event.code == KeyCode::Char('q') && !app.is_in_search_widget() { return true; } - match event.code { KeyCode::End => app.skip_to_last(), KeyCode::Home => app.skip_to_first(), From ce9b5372d9ffffbc7ee133292172d31a65dfe72b Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 16:15:21 -0500 Subject: [PATCH 7/9] Use max grapheme length rather than max "string" length. --- src/app.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app.rs b/src/app.rs index 1f983e32..3ab99662 100644 --- a/src/app.rs +++ b/src/app.rs @@ -9,6 +9,7 @@ use crate::{canvas, constants, utils::error::Result}; mod process_killer; use unicode_segmentation::GraphemeCursor; +use unicode_width::UnicodeWidthStr; const MAX_SEARCH_LENGTH: usize = 200; @@ -818,11 +819,12 @@ impl App { self.last_key_press = current_key_press_inst; if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if self - .process_search_state - .search_state - .current_search_query - .len() <= MAX_SEARCH_LENGTH + if UnicodeWidthStr::width_cjk( + self.process_search_state + .search_state + .current_search_query + .as_str(), + ) <= MAX_SEARCH_LENGTH { self.process_search_state .search_state From 2d02c53296eab133815b4865ebe145a8caf7ffe4 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 16:28:08 -0500 Subject: [PATCH 8/9] [skip travis] Update github bug report template again. --- .github/ISSUE_TEMPLATE/bug_report.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index aee93b59..1d00418a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,12 +23,14 @@ _If applicable, add screenshots to help explain your problem:_ ## Platform -_Provide information on:_ +_If relevant, please provide information on:_ **Operating System:** **Terminal:** +**Shell:** + **Any other relevant information (more details are always good!):** ## Additional context From cc751e19aec4252cd280f35172e3263bef9c938d Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 17:15:09 -0500 Subject: [PATCH 9/9] Fix issue with cursor on canvas due to not incrementing by the SIZE of the grapheme. --- src/app.rs | 10 ++++++++-- src/canvas.rs | 22 ++++++++++++++-------- src/canvas/drawing_utils.rs | 9 +++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/app.rs b/src/app.rs index 3ab99662..c2a3f6cb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -32,6 +32,12 @@ pub enum ScrollDirection { DOWN, } +#[derive(Debug)] +pub enum SearchDirection { + LEFT, + RIGHT, +} + /// AppScrollWidgetState deals with fields for a scrollable app's current state. #[derive(Default)] pub struct AppScrollWidgetState { @@ -644,7 +650,7 @@ impl App { &self.process_search_state.search_state.current_search_query[start_position..], start_position, ) - .unwrap(); + .unwrap(); // TODO: [UNWRAP] unwrap in this and walk_back seem sketch } pub fn search_walk_back(&mut self, start_position: usize) { @@ -819,7 +825,7 @@ impl App { self.last_key_press = current_key_press_inst; if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if UnicodeWidthStr::width_cjk( + if UnicodeWidthStr::width( self.process_search_state .search_state .current_search_query diff --git a/src/canvas.rs b/src/canvas.rs index 02ea3ab5..24644a27 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1159,12 +1159,16 @@ impl Painter { ) { let width = max(0, draw_loc.width as i64 - 34) as u64; // TODO: [REFACTOR] Hard coding this is terrible. let query = app_state.get_current_search_query().as_str(); - let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true) - .rev() - .enumerate(); // Reverse due to us wanting to draw from back -> front - let num_graphemes = min(UnicodeWidthStr::width_cjk(query), width as usize); + let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true).rev(); // Reverse due to us wanting to draw from back -> front let cursor_position = app_state.get_cursor_position(); + let right_border = min(UnicodeWidthStr::width(query), width as usize); + debug!( + "Width: {}, query length: {}", + width, + UnicodeWidthStr::width(query) + ); + let mut itx = 0; let mut query_with_cursor: Vec> = if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected { @@ -1178,8 +1182,8 @@ impl Painter { res.extend( grapheme_indices - .filter_map(|(itx, grapheme)| { - if itx >= num_graphemes { + .filter_map(|grapheme| { + if itx >= right_border { None } else { let styled = if grapheme.0 == cursor_position { @@ -1187,6 +1191,7 @@ impl Painter { } else { Text::styled(grapheme.1, self.colours.text_style) }; + itx += UnicodeWidthStr::width(grapheme.1); Some(styled) } }) @@ -1198,11 +1203,12 @@ impl Painter { // This is easier - we just need to get a range of graphemes, rather than // dealing with possibly inserting a cursor (as none is shown!) grapheme_indices - .filter_map(|(itx, grapheme)| { - if itx >= num_graphemes { + .filter_map(|grapheme| { + if itx >= right_border { None } else { let styled = Text::styled(grapheme.1, self.colours.text_style); + itx += UnicodeWidthStr::width(grapheme.1); Some(styled) } }) diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index ef4a441f..5fb67373 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -70,6 +70,15 @@ pub fn get_variable_intrinsic_widths( (resulting_widths, last_index) } +#[allow(dead_code, unused_variables)] +pub fn get_search_start_position( + num_rows: u64, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut u64, + currently_selected_position: u64, is_resized: bool, +) -> u64 { + //TODO: [Scroll] Gotta fix this too lol + 0 +} + pub fn get_start_position( num_rows: u64, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut u64, currently_selected_position: u64, is_resized: bool,