shell: first ProcessLauncher with PTY
This commit is contained in:
parent
bd1572c632
commit
cee6e02a04
5 changed files with 261 additions and 214 deletions
|
@ -77,5 +77,10 @@ where Key: Clone + Hash + Eq + Send + Sync + 'static,
|
||||||
self.insert(key, item);
|
self.insert(key, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: Key) {
|
||||||
|
self.data.write().unwrap().remove(&key);
|
||||||
|
self.cast.notify(&key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,6 @@ impl TerminalEditor for CharEditor {
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
})
|
})
|
||||||
.map_item(
|
|
||||||
|_idx, atom|
|
|
||||||
atom.add_style_back(TerminalStyle::fg_color((120, 200, 10)))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
@ -114,6 +110,10 @@ impl TerminalEditor for StringEditor {
|
||||||
.decorate("\"", "\"", "", 1)
|
.decorate("\"", "\"", "", 1)
|
||||||
.to_grid_horizontal()
|
.to_grid_horizontal()
|
||||||
.flatten()
|
.flatten()
|
||||||
|
.map_item(
|
||||||
|
|_idx, atom|
|
||||||
|
atom.add_style_back(TerminalStyle::fg_color((120, 200, 10)))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
|
|
@ -7,6 +7,9 @@ edition = "2018"
|
||||||
nested = { path = "../nested" }
|
nested = { path = "../nested" }
|
||||||
cgmath = "*"
|
cgmath = "*"
|
||||||
termion = "*"
|
termion = "*"
|
||||||
|
bincode = "*"
|
||||||
|
libc = "0.2.*"
|
||||||
|
tty = { git = "https://github.com/stemjail/tty-rs.git" }
|
||||||
|
|
||||||
[dependencies.async-std]
|
[dependencies.async-std]
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
|
||||||
|
extern crate tty;
|
||||||
|
|
||||||
mod monstera;
|
mod monstera;
|
||||||
|
mod process;
|
||||||
|
|
||||||
use{
|
use{
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
|
@ -15,9 +18,9 @@ use{
|
||||||
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
|
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
|
||||||
port::{UpdateTask}},
|
port::{UpdateTask}},
|
||||||
index::{IndexView},
|
index::{IndexView},
|
||||||
sequence::{SequenceView},
|
sequence::{SequenceView, SequenceViewExt},
|
||||||
vec::{VecBuffer},
|
vec::{VecBuffer},
|
||||||
integer::{RadixProjection, DigitEditor},
|
integer::{RadixProjection, DigitEditor, PosIntEditor},
|
||||||
terminal::{
|
terminal::{
|
||||||
Terminal,
|
Terminal,
|
||||||
TerminalStyle,
|
TerminalStyle,
|
||||||
|
@ -27,60 +30,17 @@ use{
|
||||||
make_label,
|
make_label,
|
||||||
TerminalView,
|
TerminalView,
|
||||||
TerminalEditor},
|
TerminalEditor},
|
||||||
string_editor::{CharEditor},
|
string_editor::{StringEditor},
|
||||||
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
|
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
|
||||||
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle}
|
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle}
|
||||||
|
},
|
||||||
|
crate::{
|
||||||
|
process::ProcessLauncher
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridFill<T: Send + Sync + Clone>(T);
|
|
||||||
impl<T: Send + Sync + Clone> View for GridFill<T> {
|
|
||||||
type Msg = Point2<i16>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Send + Sync + Clone> IndexView<Point2<i16>> for GridFill<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, _: &Point2<i16>) -> Option<T> {
|
|
||||||
Some(self.0.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
/* todo:
|
|
||||||
|
|
||||||
open::
|
|
||||||
>0:
|
|
||||||
( Path )
|
|
||||||
( Sequence ( Sequence UnicodeChar ) )
|
|
||||||
( Sequence UnicodeChar )
|
|
||||||
<1:
|
|
||||||
( FileDescriptor )
|
|
||||||
( MachineInt )
|
|
||||||
|
|
||||||
read::
|
|
||||||
>0:
|
|
||||||
( FileDescriptor )
|
|
||||||
( MachineInt )
|
|
||||||
<1:
|
|
||||||
( Sequence MachineSyllab )
|
|
||||||
( Vec MachineSyllab )
|
|
||||||
|
|
||||||
write::
|
|
||||||
>0
|
|
||||||
( FileDescriptor )
|
|
||||||
( MachineInt )
|
|
||||||
>1:
|
|
||||||
( Sequence MachineSyllab )
|
|
||||||
( Vec MachineSyllab )
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
let term_port = ViewPort::new();
|
let term_port = ViewPort::new();
|
||||||
let compositor = TerminalCompositor::new(term_port.inner());
|
let compositor = TerminalCompositor::new(term_port.inner());
|
||||||
|
|
||||||
|
@ -107,83 +67,27 @@ write::
|
||||||
let cur_size_port = ViewPort::new();
|
let cur_size_port = ViewPort::new();
|
||||||
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
|
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
|
||||||
|
|
||||||
// TypeEditor
|
|
||||||
let make_char_editor = || {
|
|
||||||
std::sync::Arc::new(std::sync::RwLock::new(CharEditor::new()))
|
|
||||||
};
|
|
||||||
let make_subsub_editor = move || {
|
|
||||||
std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_char_editor.clone(), ListEditorStyle::String)))
|
|
||||||
};
|
|
||||||
let make_sub_editor = move || {
|
|
||||||
std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_subsub_editor.clone(), ListEditorStyle::HorizontalSexpr)))
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut te = ListEditor::new(make_sub_editor.clone(), ListEditorStyle::VerticalSexpr);
|
|
||||||
|
|
||||||
te.goto(
|
|
||||||
TreeCursor {
|
|
||||||
leaf_mode: ListCursorMode::Insert,
|
|
||||||
tree_addr: vec![ 0 ]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut p = te.get_data_port().map(|sub_editor| sub_editor.read().unwrap().get_data_port());
|
|
||||||
|
|
||||||
let status_chars_port = ViewPort::new();
|
let status_chars_port = ViewPort::new();
|
||||||
let mut status_chars = VecBuffer::new(status_chars_port.inner());
|
let mut status_chars = VecBuffer::new(status_chars_port.inner());
|
||||||
|
|
||||||
let help_port = ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
|
|
||||||
let mut help_buf = nested::index::buffer::IndexBuffer::<Point2<i16>, OuterViewPort<dyn TerminalView>>::new(help_port.inner());
|
|
||||||
|
|
||||||
let table_style = TerminalStyle::fg_color((120, 100, 80));
|
|
||||||
let desc_style = TerminalStyle::italic(true);
|
|
||||||
help_buf.insert_iter(vec![
|
|
||||||
(Point2::new(0, 0), make_label("CTRL+{c,d,g}").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 0), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 0), make_label("quit").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
|
|
||||||
(Point2::new(0, 1), make_label("↞ ← ↑ ↓ → ↠").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 1), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 1), make_label("move cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
|
|
||||||
(Point2::new(0, 3), make_label("<DEL> (Select)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 3), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 3), make_label("delete item at cursor position").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
|
|
||||||
(Point2::new(0, 4), make_label("<DEL> (Insert)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 4), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 4), make_label("delete item right to cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
|
|
||||||
(Point2::new(0, 5), make_label("<BACKSPACE> (Insert)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 5), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 5), make_label("delete item left to cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
|
|
||||||
(Point2::new(0, 6), make_label("<TAB>").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
|
|
||||||
(Point2::new(1, 6), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
|
|
||||||
(Point2::new(2, 6), make_label("toggle cursor mode (insert / select)").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let help_head = make_label("─────────────────────┬─────────────────────").map_item(move |_idx, atom| atom.add_style_back(table_style));
|
|
||||||
|
|
||||||
table_buf.insert_iter(vec![
|
table_buf.insert_iter(vec![
|
||||||
(Point2::new(0, 0), magic.clone()),
|
(Point2::new(0, 0), magic.clone()),
|
||||||
(Point2::new(0, 2), status_chars_port.outer().to_sequence().to_grid_horizontal()),
|
(Point2::new(0, 1), status_chars_port.outer().to_sequence().to_grid_horizontal()),
|
||||||
(Point2::new(0, 3), te.get_term_view()),
|
|
||||||
(Point2::new(0, 4), make_label(" ")),
|
|
||||||
(Point2::new(0, 5), help_head),
|
|
||||||
(Point2::new(0, 6), help_port.outer().flatten()),
|
|
||||||
(Point2::new(0, 7), magic.clone()),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
compositor.write().unwrap().push(monstera::make_monstera());
|
compositor.write().unwrap().push(monstera::make_monstera());
|
||||||
compositor.write().unwrap().push(table_port.outer().flatten().offset(Vector2::new(40, 2)));
|
compositor.write().unwrap().push(table_port.outer().flatten().offset(Vector2::new(40, 2)));
|
||||||
|
|
||||||
/*
|
let mut y = 2;
|
||||||
te.get_data_port()
|
|
||||||
.map(
|
let mut process_launcher = ProcessLauncher::new();
|
||||||
|item_editor| item_editor.read().unwrap().get_data_port()
|
table_buf.insert(Point2::new(0, y), process_launcher.get_term_view());
|
||||||
)
|
|
||||||
*/
|
process_launcher.goto(TreeCursor {
|
||||||
|
leaf_mode: ListCursorMode::Insert,
|
||||||
|
tree_addr: vec![ 0 ]
|
||||||
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
term_port.update();
|
term_port.update();
|
||||||
match term.next_event().await {
|
match term.next_event().await {
|
||||||
|
@ -200,122 +104,60 @@ write::
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
|
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
|
||||||
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
||||||
if te.pxev() == TreeNavResult::Exit {
|
process_launcher.pxev();
|
||||||
te.goto_home();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
||||||
if te.nexd() == TreeNavResult::Exit {
|
process_launcher.nexd();
|
||||||
te.goto_end();
|
|
||||||
}
|
}
|
||||||
}
|
TerminalEvent::Input(Event::Key(Key::Up)) => { process_launcher.up(); }
|
||||||
TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); }
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
||||||
if te.dn() == TreeNavResult::Continue {
|
if process_launcher.dn() == TreeNavResult::Continue {
|
||||||
te.goto_home();
|
process_launcher.goto_home();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
||||||
if te.goto_home() == TreeNavResult::Exit {
|
process_launcher.goto_home();
|
||||||
te.goto_home();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminalEvent::Input(Event::Key(Key::End)) => {
|
TerminalEvent::Input(Event::Key(Key::End)) => {
|
||||||
if te.goto_end() == TreeNavResult::Exit {
|
process_launcher.goto_end();
|
||||||
te.goto_end();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
/*
|
let output_view = process_launcher.launch();
|
||||||
let mut strings = Vec::new();
|
|
||||||
|
|
||||||
let v = p.get_view().unwrap();
|
|
||||||
for i in 0 .. v.len().unwrap_or(0) {
|
|
||||||
strings.push(
|
|
||||||
v
|
|
||||||
.get(&i).unwrap()
|
|
||||||
.get_view().unwrap()
|
|
||||||
.read().unwrap()
|
|
||||||
.iter().collect::<String>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.len() == 0 { continue; }
|
|
||||||
|
|
||||||
if let Ok(output) =
|
|
||||||
std::process::Command::new(strings[0].as_str())
|
|
||||||
.args(&strings[1..])
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
// take output and update terminal view
|
|
||||||
let mut line_port = ViewPort::new();
|
|
||||||
let mut line = VecBuffer::new(line_port.inner());
|
|
||||||
for byte in output.stdout {
|
|
||||||
match byte {
|
|
||||||
b'\n' => {
|
|
||||||
compositor.write().unwrap().push(
|
|
||||||
line_port.outer()
|
|
||||||
.to_sequence()
|
|
||||||
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((130,90,90))))
|
|
||||||
.to_grid_horizontal()
|
|
||||||
.offset(Vector2::new(45, y))
|
|
||||||
);
|
|
||||||
y += 1;
|
y += 1;
|
||||||
line_port = ViewPort::new();
|
table_buf.insert(Point2::new(0, y), output_view);
|
||||||
line = VecBuffer::new(line_port.inner());
|
|
||||||
}
|
|
||||||
byte => {
|
|
||||||
line.push(byte as char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
compositor.write().unwrap().push(
|
|
||||||
make_label("Command not found")
|
|
||||||
.map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0))))
|
|
||||||
.offset(Vector2::new(45, y))
|
|
||||||
);
|
|
||||||
y+=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
te.up();
|
process_launcher = ProcessLauncher::new();
|
||||||
te.goto_home();
|
process_launcher.goto(TreeCursor {
|
||||||
te = ListEditor::new(make_sub_editor.clone());
|
leaf_mode: ListCursorMode::Insert,
|
||||||
|
tree_addr: vec![ 0 ]
|
||||||
|
});
|
||||||
|
|
||||||
compositor.write().unwrap().push(magic.offset(Vector2::new(40, y)));
|
|
||||||
y += 1;
|
|
||||||
compositor.write().unwrap().push(
|
|
||||||
te
|
|
||||||
.horizontal_sexpr_view()
|
|
||||||
.offset(Vector2::new(40, y))
|
|
||||||
);
|
|
||||||
y += 1;
|
y += 1;
|
||||||
|
table_buf.insert(Point2::new(0, y), process_launcher.get_term_view());
|
||||||
|
}
|
||||||
|
|
||||||
p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
ev => {
|
ev => {
|
||||||
if te.get_cursor().leaf_mode == ListCursorMode::Select {
|
if process_launcher.get_cursor().leaf_mode == ListCursorMode::Select {
|
||||||
match ev {
|
match ev {
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('l'))) => { te.up(); },
|
TerminalEvent::Input(Event::Key(Key::Char('l'))) => { process_launcher.up(); },
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('a'))) => { te.dn(); },
|
TerminalEvent::Input(Event::Key(Key::Char('a'))) => { process_launcher.dn(); },
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('i'))) => { te.pxev(); },
|
TerminalEvent::Input(Event::Key(Key::Char('i'))) => { process_launcher.pxev(); },
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('e'))) => { te.nexd(); },
|
TerminalEvent::Input(Event::Key(Key::Char('e'))) => { process_launcher.nexd(); },
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('u'))) => { te.goto_home(); },
|
TerminalEvent::Input(Event::Key(Key::Char('u'))) => { process_launcher.goto_home(); },
|
||||||
TerminalEvent::Input(Event::Key(Key::Char('o'))) => { te.goto_end(); },
|
TerminalEvent::Input(Event::Key(Key::Char('o'))) => { process_launcher.goto_end(); },
|
||||||
_ => {
|
_ => {
|
||||||
te.handle_terminal_event(&ev);
|
process_launcher.handle_terminal_event(&ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
te.handle_terminal_event(&ev);
|
process_launcher.handle_terminal_event(&ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status_chars.clear();
|
status_chars.clear();
|
||||||
let cur = te.get_cursor();
|
let cur = process_launcher.get_cursor();
|
||||||
|
|
||||||
if cur.tree_addr.len() > 0 {
|
if cur.tree_addr.len() > 0 {
|
||||||
status_chars.push(TerminalAtom::new('@', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
|
status_chars.push(TerminalAtom::new('@', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
|
||||||
|
|
197
shell/src/process.rs
Normal file
197
shell/src/process.rs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
use {
|
||||||
|
std::{
|
||||||
|
sync::Arc,
|
||||||
|
process::Command,
|
||||||
|
os::unix::io::{FromRawFd, AsRawFd},
|
||||||
|
},
|
||||||
|
std::sync::RwLock,
|
||||||
|
tty::{FileDesc, TtyServer},
|
||||||
|
termion::event::{Key, Event},
|
||||||
|
cgmath::Point2,
|
||||||
|
nested::{
|
||||||
|
core::{ViewPort, OuterViewPort, Observer},
|
||||||
|
singleton::{SingletonView, SingletonBuffer},
|
||||||
|
sequence::{SequenceView, SequenceViewExt},
|
||||||
|
index::buffer::IndexBuffer,
|
||||||
|
vec::VecBuffer,
|
||||||
|
terminal::{TerminalAtom, TerminalStyle, TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult, make_label},
|
||||||
|
tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor},
|
||||||
|
list::{ListEditor, ListEditorStyle, sexpr::ListDecoration},
|
||||||
|
string_editor::CharEditor,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
pub struct ProcessArg {
|
||||||
|
editor: ListEditor< CharEditor,
|
||||||
|
Box<dyn Fn() -> Arc<RwLock<CharEditor>> + Send + Sync + 'static> >
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessArg {
|
||||||
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = char>> {
|
||||||
|
self.editor.get_data_port()
|
||||||
|
.map(
|
||||||
|
|char_editor| char_editor.read().unwrap().get_data_port().get_view().unwrap().get().unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminalEditor for ProcessArg {
|
||||||
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
self.editor
|
||||||
|
.get_seg_seq_view()
|
||||||
|
.to_grid_horizontal()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
match event {
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char(' '))) |
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
|
self.editor.up();
|
||||||
|
TerminalEditorResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
event => self.editor.handle_terminal_event(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeNav for ProcessArg {
|
||||||
|
fn get_cursor(&self) -> TreeCursor { self.editor.get_cursor() }
|
||||||
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { self.editor.goto(cur) }
|
||||||
|
fn goto_home(&mut self) -> TreeNavResult { self.editor.goto_home() }
|
||||||
|
fn goto_end(&mut self) -> TreeNavResult { self.editor.goto_end() }
|
||||||
|
fn pxev(&mut self) -> TreeNavResult { self.editor.pxev() }
|
||||||
|
fn nexd(&mut self) -> TreeNavResult { self.editor.nexd() }
|
||||||
|
fn up(&mut self) -> TreeNavResult { self.editor.up() }
|
||||||
|
fn dn(&mut self) -> TreeNavResult { self.editor.dn() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProcessLauncher {
|
||||||
|
editor: ListEditor< ProcessArg,
|
||||||
|
Box<dyn Fn() -> Arc<RwLock<ProcessArg>> + Send + Sync + 'static> >
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessLauncher {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ProcessLauncher {
|
||||||
|
editor: ListEditor::new(
|
||||||
|
Box::new(
|
||||||
|
|| {
|
||||||
|
Arc::new(RwLock::new(ProcessArg {
|
||||||
|
editor: ListEditor::new(
|
||||||
|
Box::new(
|
||||||
|
|| {
|
||||||
|
Arc::new(RwLock::new(CharEditor::new()))
|
||||||
|
}
|
||||||
|
),
|
||||||
|
ListEditorStyle::Plain)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
),
|
||||||
|
ListEditorStyle::Plain
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn launch(&mut self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
self.up();
|
||||||
|
self.up();
|
||||||
|
|
||||||
|
let mut strings = Vec::new();
|
||||||
|
|
||||||
|
let v = self.editor.get_data_port().get_view().unwrap();
|
||||||
|
for i in 0 .. v.len().unwrap_or(0) {
|
||||||
|
let arg_view = v.get(&i).unwrap().read().unwrap().get_data_port().get_view().unwrap();
|
||||||
|
strings.push(arg_view.iter().collect::<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.len() > 0 {
|
||||||
|
let stdin = FileDesc::new(libc::STDIN_FILENO, false);
|
||||||
|
let mut server = match TtyServer::new(Some(&stdin)) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => { return make_label(&format!("Error TTY server: {}", e)); },
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cmd = std::process::Command::new(strings[0].as_str());
|
||||||
|
cmd.args(&strings[1..]).stdin(std::process::Stdio::null());
|
||||||
|
|
||||||
|
let process = match server.spawn(cmd) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => { return make_label(&format!("Failed to execute process: {}", e));},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(mut term_view_proc) = std::process::Command::new("./target/release/ansi_parser")
|
||||||
|
.stdin(unsafe{ std::process::Stdio::from_raw_fd(server.get_master().as_raw_fd()) })
|
||||||
|
.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(
|
||||||
|
async move {
|
||||||
|
*/
|
||||||
|
|
||||||
|
let output_view_port = ViewPort::new();
|
||||||
|
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 {
|
||||||
|
output_buf.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// });
|
||||||
|
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))))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
make_label("no command")
|
||||||
|
.map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminalEditor for ProcessLauncher {
|
||||||
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||||
|
self.editor
|
||||||
|
.get_seg_seq_view()
|
||||||
|
.decorate("$(", ")", " ", 0)
|
||||||
|
.to_grid_horizontal()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
||||||
|
match event {
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
||||||
|
// launch command
|
||||||
|
self.editor.up();
|
||||||
|
self.editor.up();
|
||||||
|
TerminalEditorResult::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
event => self.editor.handle_terminal_event(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeNav for ProcessLauncher {
|
||||||
|
fn get_cursor(&self) -> TreeCursor { self.editor.get_cursor() }
|
||||||
|
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { self.editor.goto(cur) }
|
||||||
|
fn goto_home(&mut self) -> TreeNavResult { self.editor.goto_home() }
|
||||||
|
fn goto_end(&mut self) -> TreeNavResult { self.editor.goto_end() }
|
||||||
|
fn pxev(&mut self) -> TreeNavResult { self.editor.pxev() }
|
||||||
|
fn nexd(&mut self) -> TreeNavResult { self.editor.nexd() }
|
||||||
|
fn up(&mut self) -> TreeNavResult { self.editor.up() }
|
||||||
|
fn dn(&mut self) -> TreeNavResult { self.editor.dn() }
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue