embed test #4
parent
41c1f67e7a
commit
2c7f9fe9a9
|
@ -305,7 +305,8 @@ fn main() -> std::result::Result<(), std::io::Error> {
|
|||
},
|
||||
}
|
||||
},
|
||||
UIMode::Embed => {},
|
||||
UIMode::Embed => state.redraw(),
|
||||
|
||||
UIMode::Fork => {
|
||||
break 'inner; // `goto` 'reap loop, and wait on child.
|
||||
},
|
||||
|
|
|
@ -546,38 +546,34 @@ impl Component for Composer {
|
|||
/* Regardless of view mode, do the following */
|
||||
self.form.draw(grid, header_area, context);
|
||||
if let Some(ref mut embed_pty) = self.embed {
|
||||
if self.dirty {
|
||||
clear_area(grid, body_area);
|
||||
match embed_pty {
|
||||
EmbedStatus::Running(_, _) => {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
copy_area(
|
||||
grid,
|
||||
&guard.grid,
|
||||
body_area,
|
||||
((0, 0), pos_dec(guard.terminal_size, (1, 1))),
|
||||
);
|
||||
if body_area != self.body_area {
|
||||
guard.set_terminal_size((width!(body_area), height!(body_area)));
|
||||
}
|
||||
context.dirty_areas.push_back(body_area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
EmbedStatus::Stopped(_, _) => {
|
||||
write_string_to_grid(
|
||||
"process has stopped, press 'e' to re-activate",
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
Attr::Default,
|
||||
body_area,
|
||||
false,
|
||||
);
|
||||
context.dirty_areas.push_back(body_area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
clear_area(grid, body_area);
|
||||
match embed_pty {
|
||||
EmbedStatus::Running(_, _) => {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
copy_area(
|
||||
grid,
|
||||
&guard.grid,
|
||||
body_area,
|
||||
((0, 0), pos_dec(guard.terminal_size, (1, 1))),
|
||||
);
|
||||
guard.set_terminal_size((width!(body_area), height!(body_area)));
|
||||
context.dirty_areas.push_back(body_area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
EmbedStatus::Stopped(_, _) => {
|
||||
write_string_to_grid(
|
||||
"process has stopped, press 'e' to re-activate",
|
||||
grid,
|
||||
Color::Default,
|
||||
Color::Default,
|
||||
Attr::Default,
|
||||
body_area,
|
||||
false,
|
||||
);
|
||||
context.dirty_areas.push_back(body_area);
|
||||
self.dirty = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -766,6 +762,15 @@ impl Component for Composer {
|
|||
match *event {
|
||||
UIEvent::Resize => {
|
||||
self.set_dirty();
|
||||
if let Some(ref mut embed_pty) = self.embed {
|
||||
match embed_pty {
|
||||
EmbedStatus::Running(_, _) => {
|
||||
let mut guard = embed_pty.lock().unwrap();
|
||||
guard.grid.clear(Cell::default());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
/* Switch e-mail From: field to the `left` configured account. */
|
||||
|
@ -825,7 +830,7 @@ impl Component for Composer {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
UIEvent::ChildStatusExited(ref pid, ref exit_code)
|
||||
UIEvent::ChildStatusExited(ref pid, _)
|
||||
if self.embed.is_some()
|
||||
&& *pid
|
||||
== self
|
||||
|
@ -835,6 +840,7 @@ impl Component for Composer {
|
|||
.unwrap() =>
|
||||
{
|
||||
self.embed = None;
|
||||
self.set_dirty();
|
||||
self.mode = ViewMode::Edit;
|
||||
context
|
||||
.replies
|
||||
|
@ -855,6 +861,7 @@ impl Component for Composer {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.set_dirty();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Normal));
|
||||
|
@ -874,6 +881,7 @@ impl Component for Composer {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
self.set_dirty();
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Embed));
|
||||
|
@ -884,6 +892,7 @@ impl Component for Composer {
|
|||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Normal));
|
||||
self.dirty = true;
|
||||
}
|
||||
UIEvent::EmbedInput((ref k, ref b)) => {
|
||||
use std::io::Write;
|
||||
|
@ -965,7 +974,7 @@ impl Component for Composer {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.dirty = true;
|
||||
self.set_dirty();
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char('e')) if self.mode.is_embed() => {
|
||||
|
@ -973,6 +982,7 @@ impl Component for Composer {
|
|||
context
|
||||
.replies
|
||||
.push_back(UIEvent::ChangeMode(UIMode::Embed));
|
||||
self.set_dirty();
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char('e')) => {
|
||||
|
@ -1114,14 +1124,19 @@ impl Component for Composer {
|
|||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.dirty
|
||||
|| self.pager.is_dirty()
|
||||
|| self
|
||||
.reply_context
|
||||
.as_ref()
|
||||
.map(|(_, p)| p.is_dirty())
|
||||
.unwrap_or(false)
|
||||
|| self.form.is_dirty()
|
||||
match self.mode {
|
||||
ViewMode::Embed => true,
|
||||
_ => {
|
||||
self.dirty
|
||||
|| self.pager.is_dirty()
|
||||
|| self
|
||||
.reply_context
|
||||
.as_ref()
|
||||
.map(|(_, p)| p.is_dirty())
|
||||
.unwrap_or(false)
|
||||
|| self.form.is_dirty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_dirty(&mut self) {
|
||||
|
|
|
@ -8,34 +8,26 @@ use nix::fcntl::{open, OFlag};
|
|||
use nix::ioctl_write_ptr_bad;
|
||||
use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||
use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt, Winsize};
|
||||
use nix::sys::stat::Mode;
|
||||
use nix::sys::{
|
||||
stat,
|
||||
wait::{self, waitpid},
|
||||
};
|
||||
use nix::unistd::{dup2, fork, setsid, ForkResult, Pid};
|
||||
use nix::sys::{stat, wait::waitpid};
|
||||
use nix::unistd::{dup2, fork, ForkResult};
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
|
||||
|
||||
mod grid;
|
||||
|
||||
use crate::terminal::cells::{Cell, CellBuffer};
|
||||
pub use grid::EmbedGrid;
|
||||
use grid::*;
|
||||
|
||||
// ioctl command to set window size of pty:
|
||||
use libc::TIOCSWINSZ;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
// Macro generated function that calls ioctl to set window size of slave pty end
|
||||
ioctl_write_ptr_bad!(set_window_size, TIOCSWINSZ, Winsize);
|
||||
|
||||
static SWITCHALTERNATIVE_1049: &'static [u8] = &[b'1', b'0', b'4', b'9'];
|
||||
|
||||
pub fn create_pty(area: Area, command: String) -> nix::Result<Arc<Mutex<EmbedGrid>>> {
|
||||
// Open a new PTY master
|
||||
let master_fd = posix_openpt(OFlag::O_RDWR)?;
|
||||
|
@ -68,7 +60,7 @@ pub fn create_pty(area: Area, command: String) -> nix::Result<Arc<Mutex<EmbedGri
|
|||
|
||||
let child_pid = match fork() {
|
||||
Ok(ForkResult::Child) => {
|
||||
// assign stdin, stdout, stderr to the tty, just like a terminal does
|
||||
// assign stdin, stdout, stderr to the tty
|
||||
dup2(slave_fd, STDIN_FILENO).unwrap();
|
||||
dup2(slave_fd, STDOUT_FILENO).unwrap();
|
||||
dup2(slave_fd, STDERR_FILENO).unwrap();
|
||||
|
@ -136,6 +128,7 @@ pub enum State {
|
|||
Normal,
|
||||
}
|
||||
|
||||
/* Used for debugging */
|
||||
struct EscCode<'a>(&'a State, u8);
|
||||
|
||||
impl<'a> From<(&'a mut State, u8)> for EscCode<'a> {
|
||||
|
@ -317,7 +310,9 @@ impl std::fmt::Display for EscCode<'_> {
|
|||
EscCode(CsiQ(ref buf), c) => {
|
||||
write!(f, "ESC[?{}{}\t\tCSI [UNKNOWN]", unsafestr!(buf), *c as char)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
EscCode(unknown, c) => {
|
||||
write!(f, "{:?}{} [UNKNOWN]", unknown, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,38 +3,98 @@ use crate::terminal::cells::*;
|
|||
use melib::error::{MeliError, Result};
|
||||
use nix::sys::wait::WaitStatus;
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag};
|
||||
use std::sync::{Arc, Mutex};
|
||||
/**
|
||||
* `EmbedGrid` manages the terminal grid state of the embed process.
|
||||
*
|
||||
* The embed process sends bytes to the master end (see super mod) and interprets them in a state
|
||||
* machine stored in `State`. Escape codes are translated as changes to the grid, eg changes in a
|
||||
* cell's colors.
|
||||
*
|
||||
* The main process copies the grid whenever the actual terminal is redrawn.
|
||||
**/
|
||||
|
||||
/// In a scroll region up and down cursor movements shift the region vertically. The new lines are
|
||||
/// empty.
|
||||
#[derive(Debug)]
|
||||
struct ScrollRegion {
|
||||
top: usize,
|
||||
bottom: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EmbedGrid {
|
||||
cursor: (usize, usize),
|
||||
/// [top;bottom]
|
||||
scroll_region: ScrollRegion,
|
||||
pub grid: CellBuffer,
|
||||
pub state: State,
|
||||
pub stdin: std::fs::File,
|
||||
/// Pid of the embed process
|
||||
pub child_pid: nix::unistd::Pid,
|
||||
/// (width, height)
|
||||
pub terminal_size: (usize, usize),
|
||||
resized: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
/// Store the fg/bg color when highlighting the cell where the cursor is so that it can be
|
||||
/// restored afterwards
|
||||
prev_fg_color: Option<Color>,
|
||||
prev_bg_color: Option<Color>,
|
||||
|
||||
show_cursor: bool,
|
||||
/// Store state in case a multi-byte character is encountered
|
||||
codepoints: CodepointBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum CodepointBuf {
|
||||
None,
|
||||
TwoCodepoints(Vec<u8>),
|
||||
ThreeCodepoints(Vec<u8>),
|
||||
FourCodepoints(Vec<u8>),
|
||||
}
|
||||
|
||||
impl EmbedGrid {
|
||||
pub fn new(stdin: std::fs::File, child_pid: nix::unistd::Pid) -> Self {
|
||||
EmbedGrid {
|
||||
cursor: (0, 0),
|
||||
scroll_region: ScrollRegion { top: 0, bottom: 0 },
|
||||
terminal_size: (0, 0),
|
||||
grid: CellBuffer::default(),
|
||||
state: State::Normal,
|
||||
stdin,
|
||||
child_pid,
|
||||
resized: false,
|
||||
fg_color: Color::Default,
|
||||
bg_color: Color::Default,
|
||||
prev_fg_color: None,
|
||||
prev_bg_color: None,
|
||||
show_cursor: true,
|
||||
codepoints: CodepointBuf::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_terminal_size(&mut self, new_val: (usize, usize)) {
|
||||
if new_val == self.terminal_size {
|
||||
return;
|
||||
}
|
||||
debug!("resizing to {:?}", new_val);
|
||||
if self.scroll_region.top == 0 && self.scroll_region.bottom == self.terminal_size.1 {
|
||||
self.scroll_region.bottom = new_val.1;
|
||||
}
|
||||
self.terminal_size = new_val;
|
||||
self.grid.resize(new_val.0, new_val.1, Cell::default());
|
||||
self.grid.clear(Cell::default());
|
||||
self.cursor = (0, 0);
|
||||
use std::convert::TryFrom;
|
||||
let winsize = Winsize {
|
||||
ws_row: <u16>::try_from(new_val.1).unwrap(),
|
||||
ws_col: <u16>::try_from(new_val.0).unwrap(),
|
||||
ws_xpixel: 0,
|
||||
ws_ypixel: 0,
|
||||
};
|
||||
|
||||
let master_fd = self.stdin.as_raw_fd();
|
||||
unsafe { set_window_size(master_fd, &winsize).unwrap() };
|
||||
nix::sys::signal::kill(self.child_pid, nix::sys::signal::SIGWINCH).unwrap();
|
||||
self.resized = true;
|
||||
}
|
||||
|
||||
pub fn wake_up(&self) {
|
||||
|
@ -54,27 +114,50 @@ impl EmbedGrid {
|
|||
pub fn process_byte(&mut self, byte: u8) {
|
||||
let EmbedGrid {
|
||||
ref mut cursor,
|
||||
ref mut scroll_region,
|
||||
ref terminal_size,
|
||||
ref mut grid,
|
||||
ref mut state,
|
||||
ref mut stdin,
|
||||
ref mut resized,
|
||||
ref mut fg_color,
|
||||
ref mut bg_color,
|
||||
ref mut prev_fg_color,
|
||||
ref mut prev_bg_color,
|
||||
ref mut codepoints,
|
||||
ref mut show_cursor,
|
||||
child_pid: _,
|
||||
} = self;
|
||||
|
||||
macro_rules! increase_cursor_x {
|
||||
() => {
|
||||
if *cursor == *terminal_size {
|
||||
/* do nothing */
|
||||
} else if cursor.0 + 1 >= terminal_size.0 {
|
||||
//cursor.0 = 0;
|
||||
//cursor.1 += 1;
|
||||
} else {
|
||||
if cursor.0 + 1 < terminal_size.0 {
|
||||
cursor.0 += 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cursor_x {
|
||||
() => {{
|
||||
if cursor.0 >= terminal_size.0 {
|
||||
cursor.0 = terminal_size.0.saturating_sub(1);
|
||||
}
|
||||
cursor.0
|
||||
}};
|
||||
}
|
||||
macro_rules! cursor_y {
|
||||
() => {
|
||||
std::cmp::min(
|
||||
cursor.1 + scroll_region.top,
|
||||
terminal_size.1.saturating_sub(1),
|
||||
)
|
||||
};
|
||||
}
|
||||
macro_rules! cursor_val {
|
||||
() => {
|
||||
(cursor_x!(), cursor_y!())
|
||||
};
|
||||
}
|
||||
|
||||
let mut state = state;
|
||||
match (byte, &mut state) {
|
||||
(b'\x1b', State::Normal) => {
|
||||
|
@ -91,7 +174,7 @@ impl EmbedGrid {
|
|||
*state = State::G0;
|
||||
}
|
||||
(b'J', State::ExpectingControlChar) => {
|
||||
// "ESCJ Erase from the cursor to the end of the screen"
|
||||
// ESCJ Erase from the cursor to the end of the screen
|
||||
debug!("sending {}", EscCode::from((&(*state), byte)));
|
||||
debug!("erasing from {:?} to {:?}", cursor, terminal_size);
|
||||
for y in cursor.1..terminal_size.1 {
|
||||
|
@ -102,14 +185,14 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
(b'K', State::ExpectingControlChar) => {
|
||||
// "ESCK Erase from the cursor to the end of the line"
|
||||
// ESCK Erase from the cursor to the end of the line
|
||||
debug!("sending {}", EscCode::from((&(*state), byte)));
|
||||
for x in cursor.0..terminal_size.0 {
|
||||
grid[(x, cursor.1)] = Cell::default();
|
||||
}
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::ExpectingControlChar) => {
|
||||
(_, State::ExpectingControlChar) => {
|
||||
debug!(
|
||||
"unrecognised: byte is {} and state is {:?}",
|
||||
byte as char, state
|
||||
|
@ -120,9 +203,6 @@ impl EmbedGrid {
|
|||
let buf1 = Vec::new();
|
||||
*state = State::CsiQ(buf1);
|
||||
}
|
||||
/* ********** */
|
||||
/* ********** */
|
||||
/* ********** */
|
||||
/* OSC stuff */
|
||||
(c, State::Osc1(ref mut buf)) if (c >= b'0' && c <= b'9') || c == b'?' => {
|
||||
buf.push(c);
|
||||
|
@ -135,21 +215,16 @@ impl EmbedGrid {
|
|||
(c, State::Osc2(_, ref mut buf)) if (c >= b'0' && c <= b'9') || c == b'?' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(c, State::Osc1(_)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(_, State::Osc1(_)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Osc2(_, _)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(_, State::Osc2(_, _)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
/* END OF OSC */
|
||||
/* ********** */
|
||||
/* ********** */
|
||||
/* ********** */
|
||||
/* ********** */
|
||||
/* Normal */
|
||||
(b'\r', State::Normal) => {
|
||||
//debug!("setting cell {:?} char '{}'", cursor, c as char);
|
||||
debug!("carriage return x-> 0, cursor was: {:?}", cursor);
|
||||
cursor.0 = 0;
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
|
@ -165,47 +240,112 @@ impl EmbedGrid {
|
|||
(b'', State::Normal) => {
|
||||
debug!("Visual bell ^G, ignoring {:?}", cursor);
|
||||
}
|
||||
/* Backspace */
|
||||
(0x08, State::Normal) => {
|
||||
//debug!("setting cell {:?} char '{}'", cursor, c as char);
|
||||
/* Backspace */
|
||||
debug!("backspace x-> x-1, cursor was: {:?}", cursor);
|
||||
if cursor.0 > 0 {
|
||||
cursor.0 -= 1;
|
||||
}
|
||||
//grid[*cursor].set_ch(' ');
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
}
|
||||
(c, State::Normal) => {
|
||||
grid[*cursor].set_ch(c as char);
|
||||
debug!("setting cell {:?} char '{}'", cursor, c as char);
|
||||
/* Character to be printed. */
|
||||
if *codepoints == CodepointBuf::None && c & 0x80 == 0 {
|
||||
/* This is a one byte char */
|
||||
grid[cursor_val!()].set_ch(c as char);
|
||||
} else {
|
||||
match codepoints {
|
||||
CodepointBuf::None if c & 0b1110_0000 == 0b1100_0000 => {
|
||||
*codepoints = CodepointBuf::TwoCodepoints(vec![c]);
|
||||
}
|
||||
CodepointBuf::None if c & 0b1111_0000 == 0b1110_0000 => {
|
||||
*codepoints = CodepointBuf::ThreeCodepoints(vec![c]);
|
||||
}
|
||||
CodepointBuf::None if c & 0b1111_1000 == 0b1111_0000 => {
|
||||
*codepoints = CodepointBuf::FourCodepoints(vec![c]);
|
||||
}
|
||||
CodepointBuf::TwoCodepoints(buf) => {
|
||||
grid[cursor_val!()].set_ch(
|
||||
unsafe { std::str::from_utf8_unchecked(&[buf[0], c]) }
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap(),
|
||||
);
|
||||
*codepoints = CodepointBuf::None;
|
||||
}
|
||||
CodepointBuf::ThreeCodepoints(buf) if buf.len() == 2 => {
|
||||
grid[cursor_val!()].set_ch(
|
||||
unsafe { std::str::from_utf8_unchecked(&[buf[0], buf[1], c]) }
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap(),
|
||||
);
|
||||
*codepoints = CodepointBuf::None;
|
||||
}
|
||||
CodepointBuf::ThreeCodepoints(buf) => {
|
||||
buf.push(c);
|
||||
return;
|
||||
}
|
||||
CodepointBuf::FourCodepoints(buf) if buf.len() == 3 => {
|
||||
grid[cursor_val!()].set_ch(
|
||||
unsafe {
|
||||
std::str::from_utf8_unchecked(&[buf[0], buf[1], buf[2], c])
|
||||
}
|
||||
.chars()
|
||||
.next()
|
||||
.unwrap(),
|
||||
);
|
||||
*codepoints = CodepointBuf::None;
|
||||
}
|
||||
CodepointBuf::FourCodepoints(buf) => {
|
||||
buf.push(c);
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
debug!(
|
||||
"invalid utf8 sequence: codepoints = {:?} and c={}",
|
||||
codepoints, c
|
||||
);
|
||||
*codepoints = CodepointBuf::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid[cursor_val!()].set_fg(*fg_color);
|
||||
grid[cursor_val!()].set_bg(*bg_color);
|
||||
increase_cursor_x!();
|
||||
}
|
||||
(b'u', State::Csi) => {
|
||||
/* restore cursor */
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
debug!("restore cursor {}", EscCode::from((&(*state), byte)));
|
||||
*show_cursor = true;
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'm', State::Csi) => {
|
||||
/* Character Attributes (SGR). Ps = 0 -> Normal (default), VT100 */
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
/* Reset character Attributes (SGR). Ps = 0 -> Normal (default), VT100 */
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*fg_color = Color::Default;
|
||||
*bg_color = Color::Default;
|
||||
grid[cursor_val!()].set_fg(Color::Default);
|
||||
grid[cursor_val!()].set_bg(Color::Default);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'H', State::Csi) => {
|
||||
/* move cursor to (1,1) */
|
||||
debug!("sending {}", EscCode::from((&(*state), byte)),);
|
||||
/* move cursor to (1,1) */
|
||||
debug!("{}", EscCode::from((&(*state), byte)),);
|
||||
debug!("move cursor to (1,1) cursor before: {:?}", *cursor);
|
||||
*cursor = (0, 0);
|
||||
debug!("cursor after: {:?}", *cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'P', State::Csi) => {
|
||||
/* delete one character */
|
||||
debug!("sending {}", EscCode::from((&(*state), byte)),);
|
||||
grid[*cursor].set_ch(' ');
|
||||
/* delete one character */
|
||||
debug!("{}", EscCode::from((&(*state), byte)),);
|
||||
grid[cursor_val!()].set_ch(' ');
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'C', State::Csi) => {
|
||||
// "ESC[C\t\tCSI Cursor Forward one Time",
|
||||
// ESC[C CSI Cursor Forward one Time
|
||||
debug!("cursor forward one time, cursor was: {:?}", cursor);
|
||||
cursor.0 = std::cmp::min(cursor.0 + 1, terminal_size.0.saturating_sub(1));
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
|
@ -215,17 +355,46 @@ impl EmbedGrid {
|
|||
(c, State::CsiQ(ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(c, State::CsiQ(ref mut buf)) => {
|
||||
// we are already in AlternativeScreen so do not forward this
|
||||
if &buf.as_slice() != &SWITCHALTERNATIVE_1049 {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(b'h', State::CsiQ(ref buf)) => {
|
||||
match buf.as_slice() {
|
||||
b"25" => {
|
||||
*show_cursor = true;
|
||||
*prev_fg_color = Some(grid[cursor_val!()].fg());
|
||||
*prev_bg_color = Some(grid[cursor_val!()].bg());
|
||||
grid[cursor_val!()].set_fg(Color::Black);
|
||||
grid[cursor_val!()].set_bg(Color::White);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'l', State::CsiQ(ref mut buf)) => {
|
||||
match buf.as_slice() {
|
||||
b"25" => {
|
||||
*show_cursor = false;
|
||||
if let Some(fg_color) = prev_fg_color.take() {
|
||||
grid[cursor_val!()].set_fg(fg_color);
|
||||
} else {
|
||||
grid[cursor_val!()].set_fg(*fg_color);
|
||||
}
|
||||
if let Some(bg_color) = prev_bg_color.take() {
|
||||
grid[cursor_val!()].set_bg(bg_color);
|
||||
} else {
|
||||
grid[cursor_val!()].set_bg(*bg_color);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(_, State::CsiQ(_)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
/* END OF CSI ? stuff */
|
||||
/* ******************* */
|
||||
/* ******************* */
|
||||
/* ******************* */
|
||||
(c, State::Csi) if c >= b'0' && c <= b'9' => {
|
||||
let mut buf1 = Vec::new();
|
||||
buf1.push(c);
|
||||
|
@ -239,7 +408,10 @@ impl EmbedGrid {
|
|||
(
|
||||
(
|
||||
0,
|
||||
std::cmp::min(cursor.1 + 1, terminal_size.1.saturating_sub(1)),
|
||||
std::cmp::min(
|
||||
cursor.1 + 1 + scroll_region.top,
|
||||
terminal_size.1.saturating_sub(1),
|
||||
),
|
||||
),
|
||||
(
|
||||
terminal_size.0.saturating_sub(1),
|
||||
|
@ -255,12 +427,38 @@ impl EmbedGrid {
|
|||
/* Erase to right (Default) */
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
for x in cursor.0..terminal_size.0 {
|
||||
grid[(x, cursor.1)] = Cell::default();
|
||||
grid[(x, cursor.1 + scroll_region.top)] = Cell::default();
|
||||
}
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Csi) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(b'M', State::Csi) => {
|
||||
/* Delete line */
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
for x in 0..terminal_size.0 {
|
||||
grid[(x, cursor.1 + scroll_region.top)] = Cell::default();
|
||||
}
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'A', State::Csi) => {
|
||||
// Move cursor up 1 line
|
||||
debug!("cursor up 1 times, cursor was: {:?}", cursor);
|
||||
if cursor.1 > 0 {
|
||||
cursor.1 -= 1;
|
||||
} else {
|
||||
debug!("cursor.1 == 0");
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'r', State::Csi) => {
|
||||
// Set scrolling region to default (size of window)
|
||||
scroll_region.top = 0;
|
||||
scroll_region.bottom = terminal_size.1.saturating_sub(1);
|
||||
*cursor = (0, 0);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(_, State::Csi) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'K', State::Csi1(buf)) if buf == b"0" => {
|
||||
|
@ -268,7 +466,7 @@ impl EmbedGrid {
|
|||
/* Erase to right (Default) */
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
for x in cursor.0..terminal_size.0 {
|
||||
grid[(x, cursor.1)] = Cell::default();
|
||||
grid[(x, cursor.1 + scroll_region.top)] = Cell::default();
|
||||
}
|
||||
*state = State::Normal;
|
||||
}
|
||||
|
@ -276,7 +474,7 @@ impl EmbedGrid {
|
|||
/* Erase in Line (ED), VT100.*/
|
||||
/* Erase to left (Default) */
|
||||
for x in cursor.0..=0 {
|
||||
grid[(x, cursor.1)] = Cell::default();
|
||||
grid[(x, cursor.1 + scroll_region.top)] = Cell::default();
|
||||
}
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
|
@ -301,7 +499,10 @@ impl EmbedGrid {
|
|||
(
|
||||
(
|
||||
0,
|
||||
std::cmp::min(cursor.1 + 1, terminal_size.1.saturating_sub(1)),
|
||||
std::cmp::min(
|
||||
cursor.1 + 1 + scroll_region.top,
|
||||
terminal_size.1.saturating_sub(1),
|
||||
),
|
||||
),
|
||||
(
|
||||
terminal_size.0.saturating_sub(1),
|
||||
|
@ -321,7 +522,7 @@ impl EmbedGrid {
|
|||
(0, 0),
|
||||
(
|
||||
terminal_size.0.saturating_sub(1),
|
||||
cursor.1.saturating_sub(1),
|
||||
cursor.1.saturating_sub(1) + scroll_region.top,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -338,15 +539,38 @@ impl EmbedGrid {
|
|||
(b'J', State::Csi1(ref buf)) if buf == b"3" => {
|
||||
/* Erase in Display (ED), VT100.*/
|
||||
/* Erase saved lines (What?) */
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'X', State::Csi1(ref buf)) => {
|
||||
/* Erase Ps Character(s) (default = 1) (ECH)..*/
|
||||
let ps = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
||||
let mut ctr = 0;
|
||||
let (mut cur_x, mut cur_y) = cursor_val!();
|
||||
while ctr < ps {
|
||||
if cur_x >= terminal_size.0 {
|
||||
cur_y += 1;
|
||||
cur_x = 0;
|
||||
if cur_y >= terminal_size.1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
grid[(cur_x, cur_y)] = Cell::default();
|
||||
cur_x += 1;
|
||||
ctr += 1;
|
||||
}
|
||||
debug!("Erased {} Character(s)", ps);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b't', State::Csi1(buf)) => {
|
||||
/* Window manipulation */
|
||||
if buf == b"18" {
|
||||
// Ps = 18 → Report the size of the text area in characters as CSI 8 ; height ; width t
|
||||
debug!("report size of the text area");
|
||||
debug!("got {}", EscCode::from((&(*state), byte)));
|
||||
// P s = 1 8 → Report the size of the text area in characters as CSI 8 ; height ; width t
|
||||
stdin.write_all(b"\x1b[8;").unwrap();
|
||||
stdin
|
||||
.write_all((terminal_size.1).to_string().as_bytes())
|
||||
|
@ -357,17 +581,16 @@ impl EmbedGrid {
|
|||
.unwrap();
|
||||
stdin.write_all(&[b't']).unwrap();
|
||||
} else {
|
||||
debug!("not sending {}", EscCode::from((&(*state), byte)));
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
}
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'n', State::Csi1(_)) => {
|
||||
/* report cursor position */
|
||||
// Ps = 6 ⇒ Report Cursor Position (CPR) [row;column].
|
||||
// Result is CSI r ; c R
|
||||
debug!("report cursor position");
|
||||
debug!("got {}", EscCode::from((&(*state), byte)));
|
||||
stdin.write_all(&[b'\x1b', b'[']).unwrap();
|
||||
// Ps = 6 ⇒ Report Cursor Position (CPR) [row;column].
|
||||
//Result is CSI r ; c R
|
||||
stdin
|
||||
.write_all((cursor.1 + 1).to_string().as_bytes())
|
||||
.unwrap();
|
||||
|
@ -378,8 +601,31 @@ impl EmbedGrid {
|
|||
stdin.write_all(&[b'R']).unwrap();
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'A', State::Csi1(buf)) => {
|
||||
// Move cursor up n lines
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
debug!("cursor up {} times, cursor was: {:?}", offset, cursor);
|
||||
if cursor.1 == scroll_region.top {
|
||||
for y in scroll_region.top..scroll_region.bottom {
|
||||
for x in 0..terminal_size.1 {
|
||||
grid[(x, y)] = grid[(x, y + 1)];
|
||||
}
|
||||
}
|
||||
for x in 0..terminal_size.1 {
|
||||
grid[(x, scroll_region.bottom)] = Cell::default();
|
||||
}
|
||||
} else if cursor.1 >= offset {
|
||||
cursor.1 -= offset;
|
||||
} else {
|
||||
debug!("offset > cursor.1");
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'B', State::Csi1(buf)) => {
|
||||
//"ESC[{buf}B\t\tCSI Cursor Down {buf} Times",
|
||||
// ESC[{buf}B CSI Cursor Down {buf} Times
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -387,23 +633,14 @@ impl EmbedGrid {
|
|||
if offset + cursor.1 < terminal_size.1 {
|
||||
cursor.1 += offset;
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'C', State::Csi1(buf)) => {
|
||||
// "ESC[{buf}C\t\tCSI Cursor Forward {buf} Times",
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
debug!("cursor forward {} times, cursor was: {:?}", offset, cursor);
|
||||
if offset + cursor.0 < terminal_size.0 {
|
||||
cursor.0 += offset;
|
||||
if scroll_region.top + cursor.1 >= terminal_size.1 {
|
||||
cursor.1 = terminal_size.1.saturating_sub(1);
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'D', State::Csi1(buf)) => {
|
||||
// "ESC[{buf}D\t\tCSI Cursor Backward {buf} Times",
|
||||
// ESC[{buf}D CSI Cursor Backward {buf} Times
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -415,7 +652,7 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
(b'E', State::Csi1(buf)) => {
|
||||
//"ESC[{buf}E\t\tCSI Cursor Next Line {buf} Times",
|
||||
// ESC[{buf}E CSI Cursor Next Line {buf} Times
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -425,18 +662,20 @@ impl EmbedGrid {
|
|||
);
|
||||
if offset + cursor.1 < terminal_size.1 {
|
||||
cursor.1 += offset;
|
||||
//cursor.0 = 0;
|
||||
}
|
||||
if scroll_region.top + cursor.1 >= terminal_size.1 {
|
||||
cursor.1 = terminal_size.1.saturating_sub(1);
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'G', State::Csi1(buf)) => {
|
||||
// "ESC[{buf}G\t\tCursor Character Absolute [column={buf}] (default = [row,1])",
|
||||
// ESC[{buf}G Cursor Character Absolute [column={buf}] (default = [row,1])
|
||||
let new_col = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
debug!("cursor absolute {}, cursor was: {:?}", new_col, cursor);
|
||||
if new_col < terminal_size.0 + 1 {
|
||||
if new_col < terminal_size.0 {
|
||||
cursor.0 = new_col.saturating_sub(1);
|
||||
} else {
|
||||
debug!(
|
||||
|
@ -448,7 +687,7 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
(b'C', State::Csi1(buf)) => {
|
||||
// "ESC[{buf}C\t\tCSI Cursor Preceding Line {buf} Times",
|
||||
// ESC[{buf}C CSI Cursor Preceding Line {buf} Times
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -458,13 +697,15 @@ impl EmbedGrid {
|
|||
);
|
||||
if cursor.1 >= offset {
|
||||
cursor.1 -= offset;
|
||||
//cursor.0 = 0;
|
||||
}
|
||||
if scroll_region.top + cursor.1 >= terminal_size.1 {
|
||||
cursor.1 = terminal_size.1.saturating_sub(1);
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'P', State::Csi1(buf)) => {
|
||||
// "ESC[{buf}P\t\tCSI Delete {buf} characters, default = 1",
|
||||
// ESC[{buf}P CSI Delete {buf} characters, default = 1
|
||||
let offset = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -473,13 +714,13 @@ impl EmbedGrid {
|
|||
offset, cursor
|
||||
);
|
||||
for x in (cursor.0 - std::cmp::min(offset, cursor.0))..cursor.0 {
|
||||
grid[(x, cursor.1)].set_ch(' ');
|
||||
grid[(x, cursor.1 + scroll_region.top)].set_ch(' ');
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
/* CSI Pm d Line Position Absolute [row] (default = [1,column]) (VPA). */
|
||||
(b'd', State::Csi1(buf)) => {
|
||||
/* CSI Pm d Line Position Absolute [row] (default = [1,column]) (VPA). */
|
||||
let row = unsafe { std::str::from_utf8_unchecked(buf) }
|
||||
.parse::<usize>()
|
||||
.unwrap();
|
||||
|
@ -487,7 +728,10 @@ impl EmbedGrid {
|
|||
"Line position absolute row {} with cursor at {:?}",
|
||||
row, cursor
|
||||
);
|
||||
cursor.1 = std::cmp::min(row.saturating_sub(1), terminal_size.1.saturating_sub(1));
|
||||
cursor.1 = row.saturating_sub(1);
|
||||
if scroll_region.top + cursor.1 >= terminal_size.1 {
|
||||
cursor.1 = terminal_size.1.saturating_sub(1);
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
|
@ -496,11 +740,40 @@ impl EmbedGrid {
|
|||
let buf2 = Vec::new();
|
||||
*state = State::Csi2(buf1, buf2);
|
||||
}
|
||||
(b'm', State::Csi1(ref buf1)) => {
|
||||
// Character Attributes.
|
||||
match buf1.as_slice() {
|
||||
b"30" => *fg_color = Color::Black,
|
||||
b"31" => *fg_color = Color::Red,
|
||||
b"32" => *fg_color = Color::Green,
|
||||
b"33" => *fg_color = Color::Yellow,
|
||||
b"34" => *fg_color = Color::Blue,
|
||||
b"35" => *fg_color = Color::Magenta,
|
||||
b"36" => *fg_color = Color::Cyan,
|
||||
b"37" => *fg_color = Color::White,
|
||||
|
||||
b"39" => *fg_color = Color::Default,
|
||||
b"40" => *fg_color = Color::Black,
|
||||
b"41" => *bg_color = Color::Red,
|
||||
b"42" => *bg_color = Color::Green,
|
||||
b"43" => *bg_color = Color::Yellow,
|
||||
b"44" => *bg_color = Color::Blue,
|
||||
b"45" => *bg_color = Color::Magenta,
|
||||
b"46" => *bg_color = Color::Cyan,
|
||||
b"47" => *bg_color = Color::White,
|
||||
|
||||
b"49" => *bg_color = Color::Default,
|
||||
_ => {}
|
||||
}
|
||||
grid[cursor_val!()].set_fg(*fg_color);
|
||||
grid[cursor_val!()].set_bg(*bg_color);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Csi1(ref mut buf)) if (c >= b'0' && c <= b'9') || c == b' ' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(c, State::Csi1(ref buf)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(_, State::Csi1(_)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b';', State::Csi2(ref mut buf1_p, ref mut buf2_p)) => {
|
||||
|
@ -509,11 +782,6 @@ impl EmbedGrid {
|
|||
let buf3 = Vec::new();
|
||||
*state = State::Csi3(buf1, buf2, buf3);
|
||||
}
|
||||
(b'n', State::Csi2(_, _)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
// Report Cursor Position, skip it
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b't', State::Csi2(_, _)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
// Window manipulation, skip it
|
||||
|
@ -532,7 +800,7 @@ impl EmbedGrid {
|
|||
"cursor set to ({},{}), cursor was: {:?}",
|
||||
orig_x, orig_y, cursor
|
||||
);
|
||||
if orig_x - 1 < terminal_size.0 && orig_y - 1 < terminal_size.1 {
|
||||
if orig_x - 1 <= terminal_size.0 && orig_y - 1 <= terminal_size.1 {
|
||||
cursor.0 = orig_x - 1;
|
||||
cursor.1 = orig_y - 1;
|
||||
} else {
|
||||
|
@ -541,14 +809,34 @@ impl EmbedGrid {
|
|||
terminal_size, cursor, orig_x, orig_y
|
||||
);
|
||||
}
|
||||
if scroll_region.top + cursor.1 >= terminal_size.1 {
|
||||
cursor.1 = terminal_size.1.saturating_sub(1);
|
||||
}
|
||||
debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Csi2(_, ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(c, State::Csi2(ref buf1, ref buf2)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(b'r', State::Csi2(ref top, ref bottom)) => {
|
||||
/* CSI Ps ; Ps r Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM). */
|
||||
let top = unsafe { std::str::from_utf8_unchecked(top) }
|
||||
.parse::<usize>()
|
||||
.unwrap_or(1);
|
||||
let bottom = unsafe { std::str::from_utf8_unchecked(bottom) }
|
||||
.parse::<usize>()
|
||||
.unwrap_or(1);
|
||||
|
||||
if bottom > top {
|
||||
scroll_region.top = top - 1;
|
||||
scroll_region.bottom = bottom - 1;
|
||||
*cursor = (0, 0);
|
||||
}
|
||||
debug!("set scrolling region to {:?}", scroll_region);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(_, State::Csi2(_, _)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b't', State::Csi3(_, _, _)) => {
|
||||
|
@ -560,21 +848,43 @@ impl EmbedGrid {
|
|||
(c, State::Csi3(_, _, ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(c, State::Csi3(_, _, _)) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
(b'm', State::Csi3(ref buf1, ref buf2, ref buf3)) if buf1 == b"38" && buf2 == b"5" => {
|
||||
/* Set character attributes | foreground color */
|
||||
*fg_color = if let Ok(byte) =
|
||||
u8::from_str_radix(unsafe { std::str::from_utf8_unchecked(buf3) }, 10)
|
||||
{
|
||||
debug!("parsed buf as {}", byte);
|
||||
Color::Byte(byte)
|
||||
} else {
|
||||
Color::Default
|
||||
};
|
||||
grid[cursor_val!()].set_fg(*fg_color);
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b'm', State::Csi3(ref buf1, ref buf2, ref buf3)) if buf1 == b"48" && buf2 == b"5" => {
|
||||
/* Set character attributes | background color */
|
||||
*bg_color = if let Ok(byte) =
|
||||
u8::from_str_radix(unsafe { std::str::from_utf8_unchecked(buf3) }, 10)
|
||||
{
|
||||
debug!("parsed buf as {}", byte);
|
||||
Color::Byte(byte)
|
||||
} else {
|
||||
Color::Default
|
||||
};
|
||||
grid[cursor_val!()].set_bg(*bg_color);
|
||||
debug!("{}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(_, State::Csi3(_, _, _)) => {
|
||||
debug!("ignoring unknown code {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
/* other stuff */
|
||||
/* ******************* */
|
||||
/* ******************* */
|
||||
/* ******************* */
|
||||
(c, State::G0) => {
|
||||
(_, State::G0) => {
|
||||
debug!("ignoring {}", EscCode::from((&(*state), byte)));
|
||||
*state = State::Normal;
|
||||
}
|
||||
(b, s) => {
|
||||
debug!("unrecognised: byte is {} and state is {:?}", b as char, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
use super::*;
|
||||
use crossbeam::{channel::Receiver, select};
|
||||
use serde::{Serialize, Serializer};
|
||||
use std::io;
|
||||
use termion::event::Event as TermionEvent;
|
||||
use termion::event::Key as TermionKey;
|
||||
use termion::input::TermRead;
|
||||
|
|
Loading…
Reference in New Issue