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::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 @@ fn completion_try_print(
}
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 @@ fn measure_completion_infos(&mut self) {
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 @@ pub fn append_line(&mut self, line: &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 @@ pub fn write(
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 @@ fn s_line(zelf: &Screen, i: usize) -> &Line {
// 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 @@ fn s_line(zelf: &Screen, i: usize) -> &Line {
// 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 @@ fn s_line(zelf: &Screen, i: usize) -> &Line {
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 @@ macro_rules! validate {
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")); // }
}