shell: accept unicode input
This commit is contained in:
parent
771c553571
commit
c4e3128528
@ -9,9 +9,43 @@ enum Outcome {
|
|||||||
Data(usize),
|
Data(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readline_inner(stdin: &mut RawStdin, stdout: &mut Stdout, buffer: &mut String) -> Result<Outcome, Error> {
|
struct Utf8Decoder {
|
||||||
|
buffer: [u8; 4],
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Utf8Decoder {
|
||||||
|
fn push(&mut self, byte: u8) -> Option<char> {
|
||||||
|
self.buffer[self.len] = byte;
|
||||||
|
self.len += 1;
|
||||||
|
if let Ok(str) = std::str::from_utf8(&self.buffer[..self.len]) {
|
||||||
|
let ch = str.chars().next().unwrap();
|
||||||
|
self.len = 0;
|
||||||
|
Some(ch)
|
||||||
|
} else {
|
||||||
|
if self.len == 4 {
|
||||||
|
// Got 4 bytes and could not decode a single character
|
||||||
|
self.len = 0;
|
||||||
|
Some('\u{25A1}')
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readline_inner(
|
||||||
|
stdin: &mut RawStdin,
|
||||||
|
stdout: &mut Stdout,
|
||||||
|
buffer: &mut String,
|
||||||
|
) -> Result<Outcome, Error> {
|
||||||
|
let mut ch_buffer = [0; 8];
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let mut ch = [0];
|
let mut ch = [0];
|
||||||
|
let mut decoder = Utf8Decoder {
|
||||||
|
buffer: [0; 4],
|
||||||
|
len: 0,
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let len = stdin.read(&mut ch)?;
|
let len = stdin.read(&mut ch)?;
|
||||||
@ -20,10 +54,13 @@ fn readline_inner(stdin: &mut RawStdin, stdout: &mut Stdout, buffer: &mut String
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ch = ch[0];
|
let ch = ch[0];
|
||||||
|
let Some(ch) = decoder.push(ch) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
match ch {
|
match ch {
|
||||||
// ^D
|
// ^D
|
||||||
0x04 => {
|
c if c as u32 == 0x04 => {
|
||||||
if pos == 0 {
|
if pos == 0 {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -31,10 +68,10 @@ fn readline_inner(stdin: &mut RawStdin, stdout: &mut Stdout, buffer: &mut String
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ^C
|
// ^C
|
||||||
0x03 => return Ok(Outcome::Interrupt),
|
c if c as u32 == 0x03 => return Ok(Outcome::Interrupt),
|
||||||
// TODO completion
|
// TODO completion
|
||||||
b'\t' => (),
|
'\t' => (),
|
||||||
0x7F => {
|
c if c as u32 == 0x7F => {
|
||||||
if pos != 0 {
|
if pos != 0 {
|
||||||
stdout.write_all(b"\x1B[D \x1B[D").ok();
|
stdout.write_all(b"\x1B[D \x1B[D").ok();
|
||||||
stdout.flush().ok();
|
stdout.flush().ok();
|
||||||
@ -42,18 +79,19 @@ fn readline_inner(stdin: &mut RawStdin, stdout: &mut Stdout, buffer: &mut String
|
|||||||
pos -= 1;
|
pos -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ch if ch.is_ascii_graphic() || ch.is_ascii_whitespace() => {
|
ch if ch.is_whitespace() || ch.is_alphanumeric() || ch.is_ascii_graphic() => {
|
||||||
stdout.write_all(&[ch]).ok();
|
let bytes = ch.encode_utf8(&mut ch_buffer);
|
||||||
|
stdout.write_all(bytes.as_bytes()).ok();
|
||||||
stdout.flush().ok();
|
stdout.flush().ok();
|
||||||
|
|
||||||
buffer.push(ch as char);
|
buffer.push(ch);
|
||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch == b'\n' || ch == b'\r' {
|
if ch == '\n' || ch == '\r' {
|
||||||
if ch == b'\r' {
|
if ch == '\r' {
|
||||||
stdout.write_all(b"\n").ok();
|
stdout.write_all(b"\n").ok();
|
||||||
stdout.flush().ok();
|
stdout.flush().ok();
|
||||||
}
|
}
|
||||||
@ -68,7 +106,7 @@ pub fn readline<P: Fn(&mut Stdout)>(
|
|||||||
stdin: &mut Stdin,
|
stdin: &mut Stdin,
|
||||||
stdout: &mut Stdout,
|
stdout: &mut Stdout,
|
||||||
buffer: &mut String,
|
buffer: &mut String,
|
||||||
prompt: P
|
prompt: P,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
let mut stdin = RawStdin::new(stdin)?;
|
let mut stdin = RawStdin::new(stdin)?;
|
||||||
|
|
||||||
@ -80,7 +118,7 @@ pub fn readline<P: Fn(&mut Stdout)>(
|
|||||||
Outcome::Data(n) => break Ok(n),
|
Outcome::Data(n) => break Ok(n),
|
||||||
Outcome::Interrupt => {
|
Outcome::Interrupt => {
|
||||||
stdout.write_all(b"\r\n").ok();
|
stdout.write_all(b"\r\n").ok();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user