mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-02 05:41:16 -03:00
Stop using wcwidth entirely
wcwidth isn't a great idea - it returns "-1" for anything it doesn't know and non-printables, which can easily break text. It is also unclear that it would be accurate to the system console, and that's a minority use-case over using ssh to access older systems. Additionally, it means we use one less function from libc and simplifies the code. Closes #12562
This commit is contained in:
committed by
Johannes Altmanninger
parent
8561008513
commit
146384abc6
@@ -29,32 +29,9 @@
|
|||||||
|
|
||||||
static WC_LOOKUP_TABLE: LazyLock<WcLookupTable> = LazyLock::new(WcLookupTable::new);
|
static WC_LOOKUP_TABLE: LazyLock<WcLookupTable> = LazyLock::new(WcLookupTable::new);
|
||||||
|
|
||||||
/// A safe wrapper around the system `wcwidth()` function
|
|
||||||
#[cfg(not(cygwin))]
|
|
||||||
pub fn wcwidth(c: char) -> isize {
|
|
||||||
unsafe extern "C" {
|
|
||||||
pub unsafe fn wcwidth(c: libc::wchar_t) -> libc::c_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
assert!(size_of::<libc::wchar_t>() >= size_of::<char>());
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = unsafe { wcwidth(c as libc::wchar_t) };
|
|
||||||
isize::try_from(width).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Big hack to use our versions of wcswidth where we know them to be broken, which is
|
// Big hack to use our versions of wcswidth where we know them to be broken, which is
|
||||||
// EVERYWHERE (https://github.com/fish-shell/fish-shell/issues/2199)
|
// EVERYWHERE (https://github.com/fish-shell/fish-shell/issues/2199)
|
||||||
pub fn fish_wcwidth(c: char) -> isize {
|
pub fn fish_wcwidth(c: char) -> isize {
|
||||||
// The system version of wcwidth should accurately reflect the ability to represent characters
|
|
||||||
// in the console session, but knows nothing about the capabilities of other terminal emulators
|
|
||||||
// or ttys. Use it from the start only if we are logged in to the physical console.
|
|
||||||
#[cfg(not(cygwin))]
|
|
||||||
if fish_common::is_console_session() {
|
|
||||||
return wcwidth(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for VS16 which selects emoji presentation. This "promotes" a character like U+2764
|
// Check for VS16 which selects emoji presentation. This "promotes" a character like U+2764
|
||||||
// (width 1) to an emoji (probably width 2). So treat it as width 1 so the sums work. See #2652.
|
// (width 1) to an emoji (probably width 2). So treat it as width 1 so the sums work. See #2652.
|
||||||
// VS15 selects text presentation.
|
// VS15 selects text presentation.
|
||||||
@@ -75,18 +52,7 @@ pub fn fish_wcwidth(c: char) -> isize {
|
|||||||
|
|
||||||
let width = WC_LOOKUP_TABLE.classify(c);
|
let width = WC_LOOKUP_TABLE.classify(c);
|
||||||
match width {
|
match width {
|
||||||
WcWidth::NonCharacter | WcWidth::NonPrint | WcWidth::Combining | WcWidth::Unassigned => {
|
WcWidth::NonCharacter | WcWidth::NonPrint | WcWidth::Combining | WcWidth::Unassigned => 0,
|
||||||
#[cfg(not(cygwin))]
|
|
||||||
{
|
|
||||||
// Fall back to system wcwidth in this case.
|
|
||||||
wcwidth(c)
|
|
||||||
}
|
|
||||||
#[cfg(cygwin)]
|
|
||||||
{
|
|
||||||
// No system wcwidth for UTF-32 on cygwin.
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WcWidth::Ambiguous | WcWidth::PrivateUse => {
|
WcWidth::Ambiguous | WcWidth::PrivateUse => {
|
||||||
// TR11: "All private-use characters are by default classified as Ambiguous".
|
// TR11: "All private-use characters are by default classified as Ambiguous".
|
||||||
FISH_AMBIGUOUS_WIDTH.load(Ordering::Relaxed)
|
FISH_AMBIGUOUS_WIDTH.load(Ordering::Relaxed)
|
||||||
@@ -97,8 +63,7 @@ pub fn fish_wcwidth(c: char) -> isize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// fish's internal versions of wcwidth and wcswidth, which can use an internal implementation if
|
/// fish's internal versions of wcwidth and wcswidth
|
||||||
/// the system one is busted.
|
|
||||||
pub fn fish_wcswidth(s: &wstr) -> isize {
|
pub fn fish_wcswidth(s: &wstr) -> isize {
|
||||||
// ascii fast path; empty iterator returns true for .all()
|
// ascii fast path; empty iterator returns true for .all()
|
||||||
if s.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) {
|
if s.chars().all(|c| c.is_ascii() && !c.is_ascii_control()) {
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ pub unsafe fn set_libc_locales(log_ok: bool) -> bool {
|
|||||||
}
|
}
|
||||||
ok &= locale_string.is_some();
|
ok &= locale_string.is_some();
|
||||||
};
|
};
|
||||||
// For wcwidth(3p)
|
|
||||||
set("LC_CTYPE", libc::LC_CTYPE, from_environment);
|
|
||||||
set("LC_CTYPE", libc::LC_CTYPE, c"C.UTF-8");
|
|
||||||
// For strerror(3p) and strsignal(3p)
|
// For strerror(3p) and strsignal(3p)
|
||||||
set("LC_MESSAGES", libc::LC_MESSAGES, from_environment);
|
set("LC_MESSAGES", libc::LC_MESSAGES, from_environment);
|
||||||
// For builtin printf
|
// For builtin printf
|
||||||
|
|||||||
Reference in New Issue
Block a user