Fix decoding mulitbyte characters after escape prefix

Fixes #10457
This commit is contained in:
Johannes Altmanninger 2024-04-23 00:04:05 +02:00
parent 10a1458dea
commit 24f0abe780
2 changed files with 34 additions and 11 deletions

View File

@ -162,9 +162,9 @@ Completions
Improved terminal support Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
- Fish now marks the prompt and command-output regions (via OSC 133) to enable terminal shell integration (:issue:`10352`). - Fish now marks the prompt and command-output regions (via OSC 133) to enable terminal shell integration (:issue:`10352`).
Shell integration shortcuts can scroll to the next/previous prompt or show the last command output in a pager.
- Fish now reports the working directory (via OSC 7) unconditionally instead of only for some terminals (:issue:`9955`). - Fish now reports the working directory (via OSC 7) unconditionally instead of only for some terminals (:issue:`9955`).
- Fish now sets the terminal window title (via OSC 0) unconditionally instead of only for some terminals (:issue:`10037`). - Fish now sets the terminal window title (via OSC 0) unconditionally instead of only for some terminals (:issue:`10037`).
Shell integration shortcuts can scroll to the next/previous prompt or show the last command output in a pager.
- Focus reporting in tmux is no longer disabled on the first prompt. - Focus reporting in tmux is no longer disabled on the first prompt.
Other improvements Other improvements

View File

@ -21,6 +21,7 @@ use crate::wutil::encoding::{mbrtowc, mbstate_t, zero_mbstate};
use crate::wutil::{fish_wcstol, write_to_fd}; use crate::wutil::{fish_wcstol, write_to_fd};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::ControlFlow;
use std::os::fd::RawFd; use std::os::fd::RawFd;
use std::ptr; use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
@ -363,6 +364,7 @@ fn readb(in_fd: RawFd, blocking: bool) -> ReadbResult {
// The terminal has been closed. // The terminal has been closed.
return ReadbResult::Eof; return ReadbResult::Eof;
} }
FLOG!(reader, "Read byte {}", arr[0]);
// The common path is to return a u8. // The common path is to return a u8.
return ReadbResult::Byte(arr[0]); return ReadbResult::Byte(arr[0]);
} }
@ -557,7 +559,6 @@ pub trait InputEventQueuer {
/// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously /// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously
/// been read and then 'unread' using \c input_common_unreadch, that character is returned. /// been read and then 'unread' using \c input_common_unreadch, that character is returned.
fn readch(&mut self) -> CharEvent { fn readch(&mut self) -> CharEvent {
let mut state = zero_mbstate();
loop { loop {
// Do we have something enqueued already? // Do we have something enqueued already?
// Note this may be initially true, or it may become true through calls to // Note this may be initially true, or it may become true through calls to
@ -610,8 +611,16 @@ pub trait InputEventQueuer {
continue; continue;
} }
let mut consumed = 0; let mut consumed = 0;
for i in 0..buffer.len() { let mut state = zero_mbstate();
self.parse_codepoint( let mut i = 0;
let ok = loop {
if i == buffer.len() {
buffer.push(match readb(self.get_in_fd(), /*blocking=*/ true) {
ReadbResult::Byte(b) => b,
_ => 0,
});
}
match self.parse_codepoint(
&mut state, &mut state,
&mut key, &mut key,
&mut seq, &mut seq,
@ -619,7 +628,20 @@ pub trait InputEventQueuer {
i, i,
&mut consumed, &mut consumed,
&mut have_escape_prefix, &mut have_escape_prefix,
); ) {
ControlFlow::Continue(codepoint_complete) => {
if codepoint_complete && i + 1 == buffer.len() {
break true;
}
}
ControlFlow::Break(()) => {
break false;
}
}
i += 1;
};
if !ok {
continue;
} }
return if let Some(key) = key { return if let Some(key) = key {
CharEvent::from_key_seq(key, seq) CharEvent::from_key_seq(key, seq)
@ -684,7 +706,7 @@ pub trait InputEventQueuer {
i: usize, i: usize,
consumed: &mut usize, consumed: &mut usize,
have_escape_prefix: &mut bool, have_escape_prefix: &mut bool,
) { ) -> ControlFlow<(), bool> {
let mut res: char = '\0'; let mut res: char = '\0';
let read_byte = buffer[i]; let read_byte = buffer[i];
if crate::libc::MB_CUR_MAX() == 1 { if crate::libc::MB_CUR_MAX() == 1 {
@ -693,7 +715,7 @@ pub trait InputEventQueuer {
// the single-byte locale is compatible with Unicode upper-ASCII. // the single-byte locale is compatible with Unicode upper-ASCII.
res = read_byte.into(); res = read_byte.into();
out_seq.push(res); out_seq.push(res);
return; return ControlFlow::Continue(true);
} }
let mut codepoint = u32::from(res); let mut codepoint = u32::from(res);
let sz = unsafe { let sz = unsafe {
@ -709,17 +731,17 @@ pub trait InputEventQueuer {
FLOG!(reader, "Illegal input"); FLOG!(reader, "Illegal input");
*consumed += 1; *consumed += 1;
self.push_front(CharEvent::from_check_exit()); self.push_front(CharEvent::from_check_exit());
return; return ControlFlow::Break(());
} }
-2 => { -2 => {
// Sequence not yet complete. // Sequence not yet complete.
return; return ControlFlow::Continue(false);
} }
0 => { 0 => {
// Actual nul char. // Actual nul char.
*consumed += 1; *consumed += 1;
out_seq.push('\0'); out_seq.push('\0');
return; return ControlFlow::Continue(true);
} }
_ => (), _ => (),
} }
@ -732,13 +754,14 @@ pub trait InputEventQueuer {
} }
*consumed += 1; *consumed += 1;
out_seq.push(res); out_seq.push(res);
return; return ControlFlow::Continue(true);
} }
} }
for &b in &buffer[*consumed..i] { for &b in &buffer[*consumed..i] {
out_seq.push(encode_byte_to_char(b)); out_seq.push(encode_byte_to_char(b));
*consumed += 1; *consumed += 1;
} }
ControlFlow::Continue(true)
} }
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> { fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {