lib-nested/shell/src/main.rs

323 lines
12 KiB
Rust
Raw Normal View History

extern crate portable_pty;
2021-09-03 06:49:18 +02:00
2021-08-11 17:56:42 +02:00
mod monstera;
2021-09-03 06:49:18 +02:00
mod process;
2021-09-15 17:47:40 +02:00
mod pty;
use{
std::sync::{Arc, RwLock},
cgmath::{Point2, Vector2},
2021-06-05 23:30:40 +02:00
termion::event::{Event, Key},
nested::{
core::{
View,
2021-06-05 23:30:40 +02:00
ViewPort,
2021-09-15 17:47:40 +02:00
InnerViewPort,
2021-06-05 23:30:40 +02:00
OuterViewPort,
Observer,
ObserverExt,
2021-09-15 17:47:40 +02:00
ObserverBroadcast,
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}},
index::{IndexView},
2021-09-13 01:52:37 +02:00
grid::{GridWindowIterator},
2021-09-03 06:49:18 +02:00
sequence::{SequenceView, SequenceViewExt},
vec::{VecBuffer},
2021-09-03 06:49:18 +02:00
integer::{RadixProjection, DigitEditor, PosIntEditor},
terminal::{
Terminal,
TerminalStyle,
TerminalAtom,
TerminalCompositor,
TerminalEvent,
make_label,
TerminalView,
TerminalEditor},
2021-09-03 06:49:18 +02:00
string_editor::{StringEditor},
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
2021-08-23 05:00:57 +02:00
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle}
2021-09-03 06:49:18 +02:00
},
crate::{
process::ProcessLauncher
2021-06-05 23:30:40 +02:00
}
};
2021-09-13 01:52:37 +02:00
struct AsciiBox {
content: Option<Arc<dyn TerminalView>>,
2021-09-15 17:47:40 +02:00
extent: Vector2<i16>,
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
}
impl AsciiBox {
pub fn new(
extent: Vector2<i16>,
content_port: OuterViewPort<dyn TerminalView>,
output_port: InnerViewPort<dyn TerminalView>
) -> Arc<RwLock<Self>> {
let ascii_box = Arc::new(RwLock::new(AsciiBox {
content: None,
extent,
cast: output_port.get_broadcast()
}));
output_port.0.update_hooks.write().unwrap().push(Arc::new(content_port.0.clone()));
output_port.set_view(Some(ascii_box.clone()));
content_port.add_observer(ascii_box.clone());
ascii_box
}
}
impl Observer<dyn TerminalView> for AsciiBox {
fn reset(&mut self, new_content: Option<Arc<dyn TerminalView>>) {
self.content = new_content;
self.notify_each(GridWindowIterator::from(Point2::new(0, 0) ..= Point2::new(self.extent.x, self.extent.y)));
}
fn notify(&mut self, pt: &Point2<i16>) {
self.cast.notify(&(pt + Vector2::new(1, 1)));
}
2021-09-13 01:52:37 +02:00
}
impl View for AsciiBox {
type Msg = Point2<i16>;
}
impl IndexView<Point2<i16>> for AsciiBox {
type Item = TerminalAtom;
fn get(&self, pt: &Point2<i16>) -> Option<TerminalAtom> {
if pt.x == 0 || pt.x == self.extent.x {
// vertical line
if pt.y == 0 && pt.x == 0 {
Some(TerminalAtom::from('╭'))
} else if pt.y == 0 && pt.x == self.extent.x {
Some(TerminalAtom::from('╮'))
} else if pt.y > 0 && pt.y < self.extent.y {
Some(TerminalAtom::from('│'))
} else if pt.y == self.extent.y && pt.x == 0 {
Some(TerminalAtom::from('╰'))
} else if pt.y == self.extent.y && pt.x == self.extent.x {
Some(TerminalAtom::from('╯'))
} else {
None
}
} else if pt.y == 0 || pt.y == self.extent.y {
// horizontal line
if pt.x > 0 && pt.x < self.extent.x {
Some(TerminalAtom::from('─'))
} else {
None
}
} else if
pt.x < self.extent.x &&
pt.y < self.extent.y
{
self.content.get(&(pt - Vector2::new(1, 1)))
} else {
None
}
}
fn area(&self) -> Option<Vec<Point2<i16>>> {
Some(GridWindowIterator::from(
Point2::new(0, 0) ..= Point2::new(self.extent.x, self.extent.y)
).collect())
}
}
2021-06-05 23:30:40 +02:00
#[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 {
2021-08-28 17:01:31 +02:00
let table_port = ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::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)
2021-06-05 23:30:40 +02:00
)
2021-08-28 17:01:31 +02:00
)
);
2021-06-05 23:30:40 +02:00
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());
2021-08-28 17:01:31 +02:00
table_buf.insert_iter(vec![
(Point2::new(0, 0), magic.clone()),
2021-09-03 06:49:18 +02:00
(Point2::new(0, 1), status_chars_port.outer().to_sequence().to_grid_horizontal()),
2021-09-13 01:52:37 +02:00
(Point2::new(0, 2), magic.clone()),
2021-08-28 17:01:31 +02:00
]);
2021-09-15 17:47:40 +02:00
compositor.write().unwrap().push(monstera::make_monstera());
compositor.write().unwrap().push(table_port.outer().flatten().offset(Vector2::new(40, 2)));
2021-08-28 17:01:31 +02:00
2021-09-13 01:52:37 +02:00
let mut y = 4;
2021-09-03 06:49:18 +02:00
let mut process_launcher = ProcessLauncher::new();
table_buf.insert(Point2::new(0, y), process_launcher.get_term_view());
process_launcher.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![ 0 ]
});
2021-09-15 17:47:40 +02:00
let mut pty : Option<pty::PTY> = None;
2021-06-05 23:30:40 +02:00
loop {
term_port.update();
2021-09-15 17:47:40 +02:00
if let Some(p) = pty.as_mut() {
if p.get_status() {
pty = None;
process_launcher = ProcessLauncher::new();
process_launcher.goto(TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![ 0 ]
});
y += 1;
table_buf.insert(Point2::new(0, y), process_launcher.get_term_view());
}
}
term_port.update();
let ev = term.next_event().await;
if let Some(pty) = pty.as_mut() {
pty.handle_terminal_event(&ev);
} else {
match ev {
TerminalEvent::Resize(new_size) => {
cur_size.set(new_size);
term_port.inner().get_broadcast().notify_each(
nested::grid::GridWindowIterator::from(
Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
)
);
}
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
TerminalEvent::Input(Event::Key(Key::Left)) => {
2021-09-03 06:49:18 +02:00
process_launcher.pxev();
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
2021-09-03 06:49:18 +02:00
process_launcher.nexd();
}
2021-09-15 17:47:40 +02:00
TerminalEvent::Input(Event::Key(Key::Up)) => {
if process_launcher.up() == TreeNavResult::Exit {
//process_launcher.dn();
//process_launcher.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::Down)) => {
2021-09-03 06:49:18 +02:00
if process_launcher.dn() == TreeNavResult::Continue {
process_launcher.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::Home)) => {
2021-09-03 06:49:18 +02:00
process_launcher.goto_home();
}
TerminalEvent::Input(Event::Key(Key::End)) => {
2021-09-03 06:49:18 +02:00
process_launcher.goto_end();
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
2021-09-15 17:47:40 +02:00
let mut output_port = ViewPort::new();
pty = process_launcher.launch_pty(output_port.inner());
2021-09-13 01:52:37 +02:00
2021-09-15 17:47:40 +02:00
let box_port = ViewPort::new();
let test_box = AsciiBox::new(
Vector2::new(81, 26),
output_port.outer()
.map_item(|_,a| a.add_style_back(TerminalStyle::fg_color((230, 230, 230)))),
box_port.inner()
);
2021-09-13 01:52:37 +02:00
2021-09-15 17:47:40 +02:00
table_buf.remove(Point2::new(0, y-1));
2021-09-15 17:47:40 +02:00
let mut p = box_port.outer().map_item(|_idx, x| x.add_style_back(TerminalStyle::fg_color((90, 120, 100))))
.offset(Vector2::new(0, -1));
table_port.update_hooks.write().unwrap().push(Arc::new(p.clone().0));
y += 1;
2021-09-15 17:47:40 +02:00
table_buf.insert(Point2::new(0, y), p.clone());
2021-09-03 06:49:18 +02:00
}
ev => {
2021-09-03 06:49:18 +02:00
if process_launcher.get_cursor().leaf_mode == ListCursorMode::Select {
match ev {
2021-09-03 06:49:18 +02:00
TerminalEvent::Input(Event::Key(Key::Char('l'))) => { process_launcher.up(); },
TerminalEvent::Input(Event::Key(Key::Char('a'))) => { process_launcher.dn(); },
TerminalEvent::Input(Event::Key(Key::Char('i'))) => { process_launcher.pxev(); },
TerminalEvent::Input(Event::Key(Key::Char('e'))) => { process_launcher.nexd(); },
TerminalEvent::Input(Event::Key(Key::Char('u'))) => { process_launcher.goto_home(); },
TerminalEvent::Input(Event::Key(Key::Char('o'))) => { process_launcher.goto_end(); },
_ => {
2021-09-03 06:49:18 +02:00
process_launcher.handle_terminal_event(&ev);
}
}
} else {
2021-09-03 06:49:18 +02:00
process_launcher.handle_terminal_event(&ev);
}
}
2021-06-05 23:30:40 +02:00
}
2021-09-15 17:47:40 +02:00
}
status_chars.clear();
2021-09-03 06:49:18 +02:00
let cur = process_launcher.get_cursor();
if cur.tree_addr.len() > 0 {
2021-08-23 05:00:57 +02:00
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))));
}
2021-08-23 05:00:57 +02:00
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))));
}
2021-08-23 05:00:57 +02:00
status_chars.push(TerminalAtom::new(':', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
} else {
for c in "Press <DN> to enter".chars() {
status_chars.push(TerminalAtom::new(c, TerminalStyle::fg_color((200, 200, 20))));
}
}
2021-06-05 23:30:40 +02:00
}
//drop(term);
2021-06-05 23:30:40 +02:00
}
);
term_writer.show().await.expect("output error!");
}