Also use control pictures for pager prefix

The test case shows that the pager rendering is not quite right.  It renders
'{\', leaving out the newline.  This rendering is ambiguous.

Let's fix it by rendering \n as control picture, like we do for other control
characters in the pager.
This commit is contained in:
Johannes Altmanninger 2024-10-19 15:45:33 +02:00
parent f5c6829670
commit c41dbe4551
3 changed files with 37 additions and 21 deletions

View file

@ -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;
}

View file

@ -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()
}

View file

@ -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")); // }
}