From 939c9a227d02eb9c9f35c579f66b2ee4bc6ea85e Mon Sep 17 00:00:00 2001 From: ClementTsang <34804052+ClementTsang@users.noreply.github.com> Date: Thu, 10 Nov 2022 00:15:06 -0500 Subject: [PATCH] fix issues with cjk/flag characters --- src/app.rs | 25 ++++++------ src/app/widgets/process_table.rs | 66 ++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/app.rs b/src/app.rs index 2b2c9998d..ea34f2596 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,7 +5,7 @@ use std::{ }; use concat_string::concat_string; -use unicode_segmentation::GraphemeCursor; +use unicode_segmentation::{GraphemeCursor, UnicodeSegmentation}; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; use typed_builder::*; @@ -2734,13 +2734,15 @@ impl App { .as_str(), ); let paste_width = UnicodeWidthStr::width(paste.as_str()); + let num_runes = UnicodeSegmentation::graphemes(paste.as_str(), true).count(); if is_in_search_widget && proc_widget_state.is_search_enabled() && curr_width + paste_width <= MAX_SEARCH_LENGTH { + let paste_char_width = paste.len(); let left_bound = proc_widget_state.get_search_cursor_position(); - let new_left_bound = (left_bound + paste_width).saturating_sub(1); + let curr_query = &mut proc_widget_state .proc_search .search_state @@ -2748,21 +2750,18 @@ impl App { let (left, right) = curr_query.split_at(left_bound); *curr_query = concat_string!(left, paste, right); - proc_widget_state.proc_search.search_state.grapheme_cursor = GraphemeCursor::new( - new_left_bound, - proc_widget_state - .proc_search - .search_state - .current_search_query - .len(), - true, - ); - proc_widget_state.search_walk_forward(new_left_bound); + proc_widget_state.proc_search.search_state.grapheme_cursor = + GraphemeCursor::new(left_bound, curr_query.len(), true); + + for _ in 0..num_runes { + let cursor = proc_widget_state.get_search_cursor_position(); + proc_widget_state.search_walk_forward(cursor); + } proc_widget_state .proc_search .search_state - .char_cursor_position += paste_width; + .char_cursor_position += paste_char_width; proc_widget_state.update_query(); proc_widget_state.proc_search.search_state.cursor_direction = diff --git a/src/app/widgets/process_table.rs b/src/app/widgets/process_table.rs index bb2683567..48cd28e92 100644 --- a/src/app/widgets/process_table.rs +++ b/src/app/widgets/process_table.rs @@ -26,6 +26,7 @@ pub use proc_widget_data::*; mod sort_table; use sort_table::SortTableColumn; +use unicode_segmentation::GraphemeIncomplete; /// ProcessSearchState only deals with process' search's current settings and state. pub struct ProcessSearchState { @@ -775,25 +776,66 @@ impl ProcWidget { } pub fn search_walk_forward(&mut self, start_position: usize) { - self.proc_search + let chunk = &self.proc_search.search_state.current_search_query[start_position..]; + + match self + .proc_search .search_state .grapheme_cursor - .next_boundary( - &self.proc_search.search_state.current_search_query[start_position..], - start_position, - ) - .unwrap(); + .next_boundary(chunk, start_position) + { + Ok(_) => {} + Err(err) => match err { + GraphemeIncomplete::PreContext(ctx) => { + // Provide the entire string as context. Not efficient but should resolve failures. + self.proc_search + .search_state + .grapheme_cursor + .provide_context( + &self.proc_search.search_state.current_search_query[0..ctx], + 0, + ); + + self.proc_search + .search_state + .grapheme_cursor + .next_boundary(chunk, start_position) + .unwrap(); + } + _ => Err(err).unwrap(), + }, + } } pub fn search_walk_back(&mut self, start_position: usize) { - self.proc_search + let chunk = &self.proc_search.search_state.current_search_query[..start_position]; + match self + .proc_search .search_state .grapheme_cursor - .prev_boundary( - &self.proc_search.search_state.current_search_query[..start_position], - 0, - ) - .unwrap(); + .prev_boundary(chunk, 0) + { + Ok(_) => {} + Err(err) => match err { + GraphemeIncomplete::PreContext(ctx) => { + // Provide the entire string as context. Not efficient but should resolve failures. + self.proc_search + .search_state + .grapheme_cursor + .provide_context( + &self.proc_search.search_state.current_search_query[0..ctx], + 0, + ); + + self.proc_search + .search_state + .grapheme_cursor + .prev_boundary(chunk, 0) + .unwrap(); + } + _ => Err(err).unwrap(), + }, + } } /// Returns the number of columns *enabled*. Note this differs from *visible* - a column may be enabled but not