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 Arc> + Send + Sync + 'static> > } impl ProcessArg { pub fn get_data_port(&self) -> OuterViewPort> { 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 { 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 Arc> + 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 { 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::()); } 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, Option)>::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 { 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() } }