Reuse wcswidth logic for rendered characters

This commit is contained in:
Johannes Altmanninger
2026-03-29 11:11:52 +08:00
parent 8194c6eb79
commit 93cbf2a0e8
3 changed files with 17 additions and 13 deletions

View File

@@ -63,15 +63,19 @@ pub fn fish_wcwidth(c: char) -> isize {
}
}
/// fish's internal versions of wcwidth and wcswidth
pub fn fish_wcswidth(s: &wstr) -> isize {
// ascii fast path; empty iterator returns true for .all()
if s.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) {
fish_wcswidth_canonicalizing(s, std::convert::identity)
}
pub fn fish_wcswidth_canonicalizing(s: &wstr, canonicalize: fn(char) -> char) -> isize {
// ascii fast path
let chars = s.chars().map(canonicalize);
if chars.clone().all(|c| c.is_ascii() && !c.is_ascii_control()) {
return s.len() as isize;
}
let mut result = 0;
for c in s.chars() {
for c in chars {
let w = fish_wcwidth(c);
if w < 0 {
return -1;

View File

@@ -358,17 +358,14 @@ fn measure_completion_infos(&mut self) {
comp.comp_width += 2;
}
// This can return -1 if it can't calculate the width. So be cautious.
let comp_width = wcswidth_rendered(comp_string);
if show_prefix {
comp.comp_width += usize::try_from(prefix_len).unwrap_or_default();
comp.comp_width += prefix_len;
}
comp.comp_width += usize::try_from(comp_width).unwrap_or_default();
comp.comp_width += wcswidth_rendered(comp_string);
}
// 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();
comp.desc_width = wcswidth_rendered(&comp.desc);
}
}

View File

@@ -24,7 +24,7 @@
use crate::terminal::{BufferedOutputter, CardinalDirection, Outputter};
use crate::termsize::Termsize;
use crate::wutil::fstat;
use fish_fallback::fish_wcwidth;
use fish_fallback::{fish_wcswidth_canonicalizing, fish_wcwidth};
use fish_wcstringutil::{fish_wcwidth_visible, string_prefixes_string, wcs2bytes};
use fish_widestring::ELLIPSIS_CHAR;
use libc::{STDERR_FILENO, STDOUT_FILENO};
@@ -2065,8 +2065,11 @@ fn wcwidth_rendered_min_0(c: char) -> usize {
pub fn wcwidth_rendered(c: char) -> isize {
fish_wcwidth(rendered_character(c))
}
pub fn wcswidth_rendered(s: &wstr) -> isize {
s.chars().map(wcwidth_rendered).sum()
pub fn wcswidth_rendered(s: &wstr) -> usize {
fish_wcswidth_canonicalizing(s, rendered_character)
.max(0)
.try_into()
.unwrap()
}
#[cfg(test)]