extern crate portable_pty; mod ascii_box; mod monstera; mod process; mod pty; mod plot; use { crate::process::ProcessLauncher, cgmath::{Point2, Vector2}, nested::{ core::{port::UpdateTask, Observer, OuterViewPort, ViewPort}, index::IndexArea, list::{ListCursorMode, ListEditor, ListEditorStyle}, terminal::{ make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView, }, tree_nav::{TerminalTreeEditor, TreeCursor, TreeNavResult}, vec::VecBuffer, }, std::sync::{Arc, RwLock}, termion::event::{Event, Key}, }; #[async_std::main] async fn main() { let term_port = ViewPort::new(); let compositor = TerminalCompositor::new(term_port.inner()); let mut term = Terminal::new(term_port.outer()); let term_writer = term.get_writer(); async_std::task::spawn(async move { let table_port = ViewPort::>>::new(); let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner()); let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>").map_item(|pos, atom| { atom.add_style_back(TerminalStyle::fg_color(( 5, ((80 + (pos.x * 30) % 100) as u8), (55 + (pos.x * 15) % 180) as u8, ))) }); let cur_size_port = ViewPort::new(); let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner()); let status_chars_port = ViewPort::new(); let mut status_chars = VecBuffer::new(status_chars_port.inner()); let mut process_list_editor = ListEditor::new( Box::new(|| Arc::new(RwLock::new(ProcessLauncher::new()))), ListEditorStyle::VerticalSexpr, ); let plist_vec_port = ViewPort::new(); let mut plist = VecBuffer::new(plist_vec_port.inner()); async_std::task::spawn(async move { let (w, _h) = termion::terminal_size().unwrap(); let mut x: usize = 0; loop { let val = (5.0 + (x as f32 / 3.0).sin() * 5.0 + 2.0 + ((7 + x) as f32 / 5.0).sin() * 2.0 + 2.0 + ((9 + x) as f32 / 10.0).cos() * 3.0) as usize; if x < w as usize { plist.push(val); } else { *plist.get_mut(x % (w as usize)) = val; } x += 1; async_std::task::sleep(std::time::Duration::from_millis(10)).await; if x % (w as usize) == 0 { async_std::task::sleep(std::time::Duration::from_secs(3)).await; } } }); let plot_port = ViewPort::new(); let _plot = crate::plot::Plot::new(plist_vec_port.outer().to_sequence(), plot_port.inner()); table_buf.insert_iter(vec![ (Point2::new(0, 0), magic.clone()), ( Point2::new(0, 1), status_chars_port.outer().to_sequence().to_grid_horizontal(), ), (Point2::new(0, 2), magic.clone()), (Point2::new(0, 3), process_list_editor.get_term_view()), ]); let (w, h) = termion::terminal_size().unwrap(); compositor.write().unwrap().push( plot_port .outer() .map_item(|pt, a| { a.add_style_back(TerminalStyle::fg_color(( 255 - pt.y as u8 * 8, 100, pt.y as u8 * 15, ))) }) .offset(Vector2::new(0, h as i16 - 20)), ); compositor .write() .unwrap() .push(monstera::make_monstera().offset(Vector2::new(w as i16 - 38, 0))); compositor .write() .unwrap() .push(table_port.outer().flatten().offset(Vector2::new(3, 0))); process_list_editor.goto(TreeCursor { leaf_mode: ListCursorMode::Insert, tree_addr: vec![0], }); let tp = term_port.clone(); async_std::task::spawn(async move { loop { tp.update(); async_std::task::sleep(std::time::Duration::from_millis(10)).await; } }); loop { status_chars.clear(); let cur = process_list_editor.get_cursor(); if cur.tree_addr.len() > 0 { status_chars.push(TerminalAtom::new( '@', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)), )); for x in cur.tree_addr { for c in format!("{}", x).chars() { status_chars .push(TerminalAtom::new(c, TerminalStyle::fg_color((0, 100, 20)))); } status_chars.push(TerminalAtom::new( '.', TerminalStyle::fg_color((120, 80, 80)), )); } status_chars.push(TerminalAtom::new( ':', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)), )); for c in match cur.leaf_mode { ListCursorMode::Insert => "INSERT", ListCursorMode::Select => "SELECT", ListCursorMode::Modify => "MODIFY", } .chars() { status_chars.push(TerminalAtom::new( c, TerminalStyle::fg_color((200, 200, 20)), )); } status_chars.push(TerminalAtom::new( ':', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true)), )); } else { for c in "Press to enter".chars() { status_chars.push(TerminalAtom::new( c, TerminalStyle::fg_color((200, 200, 20)), )); } } let ev = term.next_event().await; if let TerminalEvent::Resize(new_size) = ev { cur_size.set(new_size); term_port.inner().get_broadcast().notify(&IndexArea::Full); continue; } if let Some(process_editor) = process_list_editor.get_item() { let mut pe = process_editor.write().unwrap(); if pe.is_captured() { if let TerminalEditorResult::Exit = pe.handle_terminal_event(&ev) { drop(pe); process_list_editor.up(); process_list_editor.nexd(); } continue; } } match ev { TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break, TerminalEvent::Input(Event::Key(Key::Ctrl('l'))) => { process_list_editor.goto(TreeCursor { leaf_mode: ListCursorMode::Insert, tree_addr: vec![0], }); process_list_editor.clear(); } TerminalEvent::Input(Event::Key(Key::Left)) => { process_list_editor.pxev(); } TerminalEvent::Input(Event::Key(Key::Right)) => { process_list_editor.nexd(); } TerminalEvent::Input(Event::Key(Key::Up)) => { if process_list_editor.up() == TreeNavResult::Exit { process_list_editor.dn(); process_list_editor.goto_home(); } } TerminalEvent::Input(Event::Key(Key::Down)) => { if process_list_editor.dn() == TreeNavResult::Continue { process_list_editor.goto_home(); } } TerminalEvent::Input(Event::Key(Key::Home)) => { process_list_editor.goto_home(); } TerminalEvent::Input(Event::Key(Key::End)) => { process_list_editor.goto_end(); } ev => { if process_list_editor.get_cursor().leaf_mode == ListCursorMode::Select { match ev { TerminalEvent::Input(Event::Key(Key::Char('l'))) => { process_list_editor.up(); } TerminalEvent::Input(Event::Key(Key::Char('a'))) => { process_list_editor.dn(); } TerminalEvent::Input(Event::Key(Key::Char('i'))) => { process_list_editor.pxev(); } TerminalEvent::Input(Event::Key(Key::Char('e'))) => { process_list_editor.nexd(); } TerminalEvent::Input(Event::Key(Key::Char('u'))) => { process_list_editor.goto_home(); } TerminalEvent::Input(Event::Key(Key::Char('o'))) => { process_list_editor.goto_end(); } _ => { process_list_editor.handle_terminal_event(&ev); } } } else { if let TerminalEditorResult::Exit = process_list_editor.handle_terminal_event(&ev) { process_list_editor.nexd(); } } } } } drop(term); drop(term_port); }); term_writer.show().await.expect("output error!"); }