shell: use portable-pty crate instead of pty-rs
This commit is contained in:
parent
1076d2a1e9
commit
372ef9cb77
8 changed files with 358 additions and 47 deletions
|
@ -8,6 +8,8 @@ version = "0.1.0"
|
||||||
no_deadlocks = "*"
|
no_deadlocks = "*"
|
||||||
cgmath = { version = "0.18.0", features = ["serde"] }
|
cgmath = { version = "0.18.0", features = ["serde"] }
|
||||||
termion = "1.5.5"
|
termion = "1.5.5"
|
||||||
|
vte = "0.10.1"
|
||||||
|
ansi_colours = "1.0"
|
||||||
signal-hook = "0.3.1"
|
signal-hook = "0.3.1"
|
||||||
signal-hook-async-std = "0.2.0"
|
signal-hook-async-std = "0.2.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
|
@ -327,8 +327,6 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.goto_home();
|
|
||||||
}
|
}
|
||||||
TreeNavResult::Continue
|
TreeNavResult::Continue
|
||||||
}
|
}
|
||||||
|
|
292
nested/src/terminal/ansi_parser.rs
Normal file
292
nested/src/terminal/ansi_parser.rs
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
use {
|
||||||
|
std::{
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
pin::Pin,
|
||||||
|
fs::File,
|
||||||
|
os::unix::io::FromRawFd
|
||||||
|
},
|
||||||
|
std::io::Read,
|
||||||
|
//async_std::{io::{Read, ReadExt}},
|
||||||
|
crate::{
|
||||||
|
core::{InnerViewPort, OuterViewPort},
|
||||||
|
terminal::{
|
||||||
|
TerminalAtom,
|
||||||
|
TerminalStyle,
|
||||||
|
TerminalView
|
||||||
|
},
|
||||||
|
index::buffer::IndexBuffer
|
||||||
|
},
|
||||||
|
cgmath::Point2,
|
||||||
|
vte::{Params, Parser, Perform}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn read_ansi_from<R: Read + Unpin>(ansi_reader: &mut R, port: InnerViewPort<dyn TerminalView>) {
|
||||||
|
let mut statemachine = Parser::new();
|
||||||
|
|
||||||
|
let mut performer = PerfAtom {
|
||||||
|
cursor: Point2::new(0, 0),
|
||||||
|
style: TerminalStyle::default(),
|
||||||
|
term_width: 200,
|
||||||
|
|
||||||
|
buf: IndexBuffer::new(port),
|
||||||
|
|
||||||
|
colors: ColorPalett {
|
||||||
|
black: (1, 1, 1),
|
||||||
|
red: (222, 56, 43),
|
||||||
|
green: (0, 64, 0),
|
||||||
|
yellow: (255, 199, 6),
|
||||||
|
blue: (0, 111, 184),
|
||||||
|
magenta: (118, 38, 113),
|
||||||
|
cyan: (44, 181, 233),
|
||||||
|
white: (204, 204, 204)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buf = [0; 2048];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match ansi_reader.read(&mut buf) {
|
||||||
|
Ok(0) => break,
|
||||||
|
Ok(n) => {
|
||||||
|
for byte in &buf[..n] {
|
||||||
|
statemachine.advance(&mut performer, *byte);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
println!("err: {}", err);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ColorPalett {
|
||||||
|
black: (u8, u8, u8),
|
||||||
|
red: (u8, u8, u8),
|
||||||
|
green: (u8, u8, u8),
|
||||||
|
yellow: (u8, u8, u8),
|
||||||
|
blue: (u8, u8, u8),
|
||||||
|
magenta: (u8, u8, u8),
|
||||||
|
cyan: (u8, u8, u8),
|
||||||
|
white: (u8, u8, u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PerfAtom {
|
||||||
|
colors: ColorPalett,
|
||||||
|
term_width: i16,
|
||||||
|
|
||||||
|
cursor: Point2<i16>,
|
||||||
|
style: TerminalStyle,
|
||||||
|
|
||||||
|
buf: IndexBuffer<Point2<i16>, TerminalAtom>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerfAtom {
|
||||||
|
fn write_atom(&mut self, pos: Point2<i16>, atom: Option<TerminalAtom>) {
|
||||||
|
if let Some(a) = atom {
|
||||||
|
self.buf.insert(pos, a);
|
||||||
|
} else {
|
||||||
|
self.buf.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Perform for PerfAtom {
|
||||||
|
fn print(&mut self, c: char) {
|
||||||
|
//eprintln!("[print] {:?}", c);
|
||||||
|
self.write_atom(
|
||||||
|
self.cursor,
|
||||||
|
Some(TerminalAtom::new(c, self.style))
|
||||||
|
);
|
||||||
|
|
||||||
|
self.cursor.x += 1;
|
||||||
|
if self.cursor.x > self.term_width {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
self.cursor.y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&mut self, byte: u8) {
|
||||||
|
//eprintln!("[execute] {:02x}", byte);
|
||||||
|
match byte {
|
||||||
|
b'\n' => {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
self.cursor.y += 1;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
||||||
|
eprintln!(
|
||||||
|
"[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}",
|
||||||
|
params, intermediates, ignore, c
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put(&mut self, byte: u8) {
|
||||||
|
eprintln!("[put] {:02x}", byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unhook(&mut self) {
|
||||||
|
eprintln!("[unhook]");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
|
||||||
|
eprintln!("[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
|
||||||
|
eprintln!(
|
||||||
|
"[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
|
||||||
|
params, intermediates, ignore, c
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut piter = params.into_iter();
|
||||||
|
|
||||||
|
match c {
|
||||||
|
// Set SGR
|
||||||
|
'm' => while let Some(n) = piter.next() {
|
||||||
|
match n[0] {
|
||||||
|
0 => self.style = TerminalStyle::default(),
|
||||||
|
1 => self.style = self.style.add(TerminalStyle::bold(true)),
|
||||||
|
3 => self.style = self.style.add(TerminalStyle::italic(true)),
|
||||||
|
4 => self.style = self.style.add(TerminalStyle::underline(true)),
|
||||||
|
|
||||||
|
30 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.black)),
|
||||||
|
40 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.black)),
|
||||||
|
31 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.red)),
|
||||||
|
41 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.red)),
|
||||||
|
32 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.green)),
|
||||||
|
42 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.green)),
|
||||||
|
33 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.yellow)),
|
||||||
|
43 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.yellow)),
|
||||||
|
34 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.blue)),
|
||||||
|
44 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.blue)),
|
||||||
|
35 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.magenta)),
|
||||||
|
45 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.magenta)),
|
||||||
|
36 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.cyan)),
|
||||||
|
46 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.cyan)),
|
||||||
|
37 => self.style = self.style.add(TerminalStyle::fg_color(self.colors.white)),
|
||||||
|
47 => self.style = self.style.add(TerminalStyle::bg_color(self.colors.white)),
|
||||||
|
|
||||||
|
38 => {
|
||||||
|
let x = piter.next().unwrap();
|
||||||
|
match x[0] {
|
||||||
|
2 => {
|
||||||
|
let r = piter.next().unwrap();
|
||||||
|
let g = piter.next().unwrap();
|
||||||
|
let b = piter.next().unwrap();
|
||||||
|
self.style = self.style.add(TerminalStyle::fg_color((r[0] as u8, g[0] as u8, b[30] as u8)))
|
||||||
|
},
|
||||||
|
5 => {
|
||||||
|
let v = piter.next().unwrap();
|
||||||
|
self.style = self.style.add(TerminalStyle::fg_color(ansi_colours::rgb_from_ansi256(v[0] as u8)))
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
48 => {
|
||||||
|
let x = piter.next().unwrap();
|
||||||
|
match x[0] {
|
||||||
|
2 => {
|
||||||
|
let r = piter.next().unwrap();
|
||||||
|
let g = piter.next().unwrap();
|
||||||
|
let b = piter.next().unwrap();
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color((r[0] as u8, g[0] as u8, b[30] as u8)))
|
||||||
|
},
|
||||||
|
5 => {
|
||||||
|
let v = piter.next().unwrap();
|
||||||
|
self.style = self.style.add(TerminalStyle::bg_color(ansi_colours::rgb_from_ansi256(v[0] as u8)))
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'H' => {
|
||||||
|
if let Some(y) = piter.next() { self.cursor.y = y[0] as i16 - 1 };
|
||||||
|
if let Some(x) = piter.next() { self.cursor.x = x[0] as i16 - 1 };
|
||||||
|
|
||||||
|
eprintln!("cursor at {:?}", self.cursor);
|
||||||
|
},
|
||||||
|
|
||||||
|
'A' => { self.cursor.y -= piter.next().unwrap()[0] as i16; }
|
||||||
|
'B' => { self.cursor.y += piter.next().unwrap()[0] as i16; }
|
||||||
|
'C' => { self.cursor.x += piter.next().unwrap()[0] as i16; }
|
||||||
|
'D' => { self.cursor.x -= piter.next().unwrap()[0] as i16; }
|
||||||
|
'E' => {
|
||||||
|
self.cursor.x = 0;
|
||||||
|
self.cursor.y += piter.next().unwrap()[0] as i16;
|
||||||
|
}
|
||||||
|
|
||||||
|
'J' => {
|
||||||
|
let x = piter.next().unwrap_or(&[0 as u16; 1]);
|
||||||
|
match x[0] {
|
||||||
|
0 => {
|
||||||
|
|
||||||
|
},
|
||||||
|
1 => {
|
||||||
|
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
for y in 0 .. 100 {
|
||||||
|
for x in 0 .. self.term_width {
|
||||||
|
self.write_atom(Point2::new(x, y), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'K' => {
|
||||||
|
let x = piter.next().unwrap();
|
||||||
|
match x[0] {
|
||||||
|
|
||||||
|
// clear cursor until end
|
||||||
|
0 => {
|
||||||
|
for x in self.cursor.x .. self.term_width {
|
||||||
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// clear start until cursor
|
||||||
|
1 => {
|
||||||
|
for x in 0 .. self.cursor.x {
|
||||||
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// clear entire line
|
||||||
|
2 => {
|
||||||
|
for x in 0 .. self.term_width {
|
||||||
|
self.write_atom(Point2::new(x, self.cursor.y), None);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// invalid
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
|
||||||
|
eprintln!(
|
||||||
|
"[esc_dispatch] intermediates={:?}, ignore={:?}, byte={:02x}",
|
||||||
|
intermediates, ignore, byte
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub mod style;
|
||||||
pub mod atom;
|
pub mod atom;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
pub mod compositor;
|
pub mod compositor;
|
||||||
|
pub mod ansi_parser;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
style::{TerminalStyle},
|
style::{TerminalStyle},
|
||||||
|
|
|
@ -9,7 +9,7 @@ cgmath = "*"
|
||||||
termion = "*"
|
termion = "*"
|
||||||
bincode = "*"
|
bincode = "*"
|
||||||
libc = "0.2.*"
|
libc = "0.2.*"
|
||||||
tty = { git = "https://github.com/stemjail/tty-rs.git" }
|
portable-pty = "0.4.0"
|
||||||
|
|
||||||
[dependencies.async-std]
|
[dependencies.async-std]
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|
28
shell/src/expr.rs
Normal file
28
shell/src/expr.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use {
|
||||||
|
std::{
|
||||||
|
sync::{Arc, RwLock}
|
||||||
|
}
|
||||||
|
nested::{
|
||||||
|
core::TypeTerm,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExprEditor {
|
||||||
|
editor: Arc<RwLock<dyn TerminalTreeEditor>>,
|
||||||
|
type_tag: TypeTerm
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeNav for ExprEditor {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminalEditor for ExprEditor {
|
||||||
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
extern crate tty;
|
extern crate portable_pty;
|
||||||
|
|
||||||
mod monstera;
|
mod monstera;
|
||||||
mod process;
|
mod process;
|
||||||
|
@ -170,6 +170,7 @@ async fn main() {
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Up)) => { process_launcher.up(); }
|
TerminalEvent::Input(Event::Key(Key::Up)) => { process_launcher.up(); }
|
||||||
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
||||||
|
//process_launcher.dn();
|
||||||
if process_launcher.dn() == TreeNavResult::Continue {
|
if process_launcher.dn() == TreeNavResult::Continue {
|
||||||
process_launcher.goto_home();
|
process_launcher.goto_home();
|
||||||
}
|
}
|
||||||
|
@ -183,12 +184,10 @@ async fn main() {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
let output_view = process_launcher.launch();
|
let output_view = process_launcher.launch();
|
||||||
|
|
||||||
let range = output_view.get_view().unwrap().range();
|
|
||||||
|
|
||||||
let box_port = ViewPort::new();
|
let box_port = ViewPort::new();
|
||||||
let test_box = Arc::new(RwLock::new(AsciiBox {
|
let test_box = Arc::new(RwLock::new(AsciiBox {
|
||||||
content: Some(output_view.map_item(|_,a| a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))).get_view().unwrap()),
|
content: Some(output_view.map_item(|_,a| a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))).get_view().unwrap()),
|
||||||
extent: range.end - range.start + Vector2::new(1,1)
|
extent: Vector2::new(120,30)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
box_port.inner().set_view(Some(test_box.clone() as Arc<dyn TerminalView>));
|
box_port.inner().set_view(Some(test_box.clone() as Arc<dyn TerminalView>));
|
||||||
|
|
|
@ -5,7 +5,6 @@ use {
|
||||||
os::unix::io::{FromRawFd, AsRawFd},
|
os::unix::io::{FromRawFd, AsRawFd},
|
||||||
},
|
},
|
||||||
std::sync::RwLock,
|
std::sync::RwLock,
|
||||||
tty::{FileDesc, TtyServer},
|
|
||||||
termion::event::{Key, Event},
|
termion::event::{Key, Event},
|
||||||
cgmath::Point2,
|
cgmath::Point2,
|
||||||
nested::{
|
nested::{
|
||||||
|
@ -20,6 +19,7 @@ use {
|
||||||
string_editor::CharEditor,
|
string_editor::CharEditor,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
use portable_pty::{CommandBuilder, PtySize, native_pty_system, PtySystem};
|
||||||
|
|
||||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ impl ProcessLauncher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn launch(&mut self) -> OuterViewPort<dyn TerminalView> {
|
pub fn launch(&mut self) -> (OuterViewPort<dyn TerminalView>) {
|
||||||
self.up();
|
self.up();
|
||||||
self.up();
|
self.up();
|
||||||
|
|
||||||
|
@ -109,49 +109,40 @@ impl ProcessLauncher {
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.len() > 0 {
|
if strings.len() > 0 {
|
||||||
let stdin = FileDesc::new(libc::STDIN_FILENO, false);
|
// Create a new pty
|
||||||
let mut server = match TtyServer::new(Some(&stdin)) {
|
let mut pair = native_pty_system().openpty(PtySize {
|
||||||
Ok(s) => s,
|
rows: 30,
|
||||||
Err(e) => { return make_label(&format!("Error TTY server: {}", e)); },
|
cols: 120,
|
||||||
};
|
// Not all systems support pixel_width, pixel_height,
|
||||||
|
// but it is good practice to set it to something
|
||||||
|
// that matches the size of the selected font. That
|
||||||
|
// is more complex than can be shown here in this
|
||||||
|
// brief example though!
|
||||||
|
pixel_width: 0,
|
||||||
|
pixel_height: 0,
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
let mut cmd = std::process::Command::new(strings[0].as_str());
|
// Spawn a shell into the pty
|
||||||
cmd.args(&strings[1..]).stdin(std::process::Stdio::null());
|
let mut cmd = CommandBuilder::new(strings[0].as_str());
|
||||||
|
cmd.args(&strings[1..]);
|
||||||
|
|
||||||
let process = match server.spawn(cmd) {
|
if let Ok(child) = pair.slave.spawn_command(cmd) {
|
||||||
Ok(p) => p,
|
// Read and parse output from the pty with reader
|
||||||
Err(e) => { return make_label(&format!("Failed to execute process: {}", e));},
|
let mut reader = pair.master.try_clone_reader().unwrap();
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(mut term_view_proc) = std::process::Command::new("./target/release/ansi_parser")
|
// Send data to the pty by writing to the master
|
||||||
.stdin(unsafe{ std::process::Stdio::from_raw_fd(server.get_master().as_raw_fd()) })
|
//writeln!(pair.master, "ls -l\r\n");
|
||||||
.stdout(std::process::Stdio::piped())
|
|
||||||
.stderr(std::process::Stdio::null())
|
|
||||||
.spawn()
|
|
||||||
{
|
|
||||||
let mut term_view_bin = term_view_proc.stdout.unwrap();
|
|
||||||
/*
|
|
||||||
//let mut term_view_bin = async_std::io::BufReader::new(unsafe { async_std::fs::File::from_raw_fd( term_view_proc.stdout.unwrap().as_raw_fd() ) } );
|
|
||||||
//let mut tv_stream = async_bincode::AsyncBincodeReader::<_, (Point2<i16>, Option<TerminalAtom>)>::from(term_view_bin);
|
|
||||||
|
|
||||||
async_std::task::spawn(
|
let port = ViewPort::new();
|
||||||
async move {
|
let p = port.inner();
|
||||||
*/
|
async_std::task::spawn_blocking(
|
||||||
|
move || {
|
||||||
|
nested::terminal::ansi_parser::read_ansi_from(&mut reader, p);
|
||||||
|
});
|
||||||
|
|
||||||
let output_view_port = ViewPort::new();
|
port.into_outer()
|
||||||
let mut output_buf = IndexBuffer::new(output_view_port.inner());
|
|
||||||
|
|
||||||
while let Ok((pos, atom)) = bincode::deserialize_from(&mut term_view_bin) {
|
|
||||||
if let Some(a) = atom {
|
|
||||||
output_buf.insert(pos, a);
|
|
||||||
} else {
|
} else {
|
||||||
output_buf.remove(pos);
|
make_label("invalid command")
|
||||||
}
|
|
||||||
}
|
|
||||||
// });
|
|
||||||
output_view_port.outer()
|
|
||||||
} else {
|
|
||||||
make_label("Failed to spawn ansi parser process")
|
|
||||||
.map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0))))
|
.map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0))))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue