diff --git a/src/pager.rs b/src/pager.rs index 1ef287ece..8a4d836fd 100644 --- a/src/pager.rs +++ b/src/pager.rs @@ -8,13 +8,12 @@ use crate::common::{ }; use crate::complete::Completion; use crate::editable_line::EditableLine; -use crate::fallback::{fish_wcswidth, fish_wcwidth}; #[allow(unused_imports)] use crate::future::IsSomeAnd; use crate::highlight::{highlight_shell, HighlightRole, HighlightSpec}; use crate::libc::MB_CUR_MAX; use crate::operation_context::OperationContext; -use crate::screen::{Line, ScreenData}; +use crate::screen::{wcswidth_rendered, wcwidth_rendered, Line, ScreenData}; use crate::termsize::Termsize; use crate::wchar::prelude::*; use crate::wcstringutil::string_fuzzy_match_string; @@ -344,7 +343,7 @@ impl Pager { } fn measure_completion_infos(&mut self) { - let prefix_len = usize::try_from(fish_wcswidth(&self.prefix)); + let prefix_len = wcswidth_rendered(&self.prefix); for comp in &mut self.unfiltered_completion_infos { let comp_strings = &mut comp.comp; @@ -354,14 +353,14 @@ impl Pager { comp.comp_width += 2; } - // fish_wcswidth() can return -1 if it can't calculate the width. So be cautious. - let comp_width = fish_wcswidth(comp_string); - comp.comp_width += prefix_len.unwrap_or_default(); + // This can return -1 if it can't calculate the width. So be cautious. + let comp_width = wcswidth_rendered(comp_string); + comp.comp_width += usize::try_from(prefix_len).unwrap_or_default(); comp.comp_width += usize::try_from(comp_width).unwrap_or_default(); } - // fish_wcswidth() can return -1 if it can't calculate the width. So be cautious. - let desc_width = fish_wcswidth(&comp.desc); + // This can return -1 if it can't calculate the width. So be cautious. + let desc_width = wcswidth_rendered(&comp.desc); comp.desc_width = usize::try_from(desc_width).unwrap_or_default(); } } @@ -1071,7 +1070,7 @@ fn print_max_impl( ) -> usize { let mut remaining = max; for (i, c) in s.chars().enumerate() { - let iwidth_c = fish_wcwidth(c); + let iwidth_c = wcwidth_rendered(c); let Ok(width_c) = usize::try_from(iwidth_c) else { // skip non-printable characters continue; @@ -1084,7 +1083,7 @@ fn print_max_impl( let ellipsis = get_ellipsis_char(); if (width_c == remaining) && (has_more || i + 1 < s.len()) { line.append(ellipsis, color(i)); - let ellipsis_width = fish_wcwidth(ellipsis); + let ellipsis_width = wcwidth_rendered(ellipsis); remaining = remaining.saturating_sub(usize::try_from(ellipsis_width).unwrap()); break; } diff --git a/src/screen.rs b/src/screen.rs index cda33cebd..62ab5a5b4 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -103,7 +103,7 @@ impl Line { pub fn wcswidth_min_0(&self, max: usize /* = usize::MAX */) -> usize { let mut result: usize = 0; for c in &self.text[..max.min(self.text.len())] { - result += wcwidth_rendered(c.character); + result += wcwidth_rendered_min_0(c.character); } result } @@ -327,7 +327,7 @@ impl Screen { colors[i], usize::try_from(indent[i]).unwrap(), first_line_prompt_space, - wcwidth_rendered(effective_commandline.as_char_slice()[i]), + wcwidth_rendered_min_0(effective_commandline.as_char_slice()[i]), ); i += 1; } @@ -925,7 +925,7 @@ impl Screen { // Skip over skip_remaining width worth of characters. let mut j = 0; while j < o_line(&zelf, i).len() { - let width = wcwidth_rendered(o_line(&zelf, i).char_at(j)); + let width = wcwidth_rendered_min_0(o_line(&zelf, i).char_at(j)); if skip_remaining < width { break; } @@ -936,7 +936,7 @@ impl Screen { // Skip over zero-width characters (e.g. combining marks at the end of the prompt). while j < o_line(&zelf, i).len() { - let width = wcwidth_rendered(o_line(&zelf, i).char_at(j)); + let width = wcwidth_rendered_min_0(o_line(&zelf, i).char_at(j)); if width > 0 { break; } @@ -969,7 +969,7 @@ impl Screen { let color = o_line(&zelf, i).color_at(j); set_color(&mut zelf, color); let ch = o_line(&zelf, i).char_at(j); - let width = wcwidth_rendered(ch); + let width = wcwidth_rendered_min_0(ch); zelf.write_char(ch, isize::try_from(width).unwrap()); current_width += width; j += 1; @@ -1524,7 +1524,7 @@ fn measure_run_from( width = next_tab_stop(width); } else { // Ordinary char. Add its width with care to ignore control chars which have width -1. - width += wcwidth_rendered(input.char_at(idx)); + width += wcwidth_rendered_min_0(input.char_at(idx)); } idx += 1; } @@ -1570,7 +1570,7 @@ fn truncate_run( curr_width = measure_run_from(run, 0, None, cache); idx = 0; } else { - let char_width = wcwidth_rendered(c); + let char_width = wcwidth_rendered_min_0(c); curr_width -= std::cmp::min(curr_width, char_width); run.remove(idx); } @@ -1719,7 +1719,7 @@ fn compute_layout( multiline = true; break; } else { - first_line_width += wcwidth_rendered(c); + first_line_width += wcwidth_rendered_min_0(c); } } let first_command_line_width = first_line_width; @@ -1734,7 +1734,7 @@ fn compute_layout( autosuggest_truncated_widths.reserve(1 + autosuggestion_str.len()); for c in autosuggestion.chars() { autosuggest_truncated_widths.push(autosuggest_total_width); - autosuggest_total_width += wcwidth_rendered(c); + autosuggest_total_width += wcwidth_rendered_min_0(c); } } @@ -1839,6 +1839,12 @@ fn rendered_character(c: char) -> char { } } -fn wcwidth_rendered(c: char) -> usize { - usize::try_from(fish_wcwidth(rendered_character(c))).unwrap_or_default() +fn wcwidth_rendered_min_0(c: char) -> usize { + usize::try_from(wcwidth_rendered(c)).unwrap() +} +pub fn wcwidth_rendered(c: char) -> isize { + fish_wcwidth(rendered_character(c)) +} +pub fn wcswidth_rendered(s: &wstr) -> isize { + s.chars().map(|c| fish_wcwidth(rendered_character(c))).sum() } diff --git a/src/tests/pager.rs b/src/tests/pager.rs index d001426a6..6a0ebb181 100644 --- a/src/tests/pager.rs +++ b/src/tests/pager.rs @@ -194,4 +194,15 @@ fn test_pager_layout() { validate!(&mut pager, 18, L!("abcdefghijklmnopq…")); validate!(&mut pager, 17, L!("abcdefghijklmnop…")); validate!(&mut pager, 16, L!("abcdefghijklmno…")); + + // Newlines in prefix + let c4s = vec![Completion::new( + L!("Hello").to_owned(), + L!("").to_owned(), + StringFuzzyMatch::exact_match(), + CompleteFlags::default(), + )]; + pager.set_prefix(L!("{\\\n"), false); // } + pager.set_completions(&c4s, true); + validate!(&mut pager, 30, L!("{\\␊Hello")); // } }