lib-nested/shell/src/main.rs
Michael Sippel cec7b4a0a0
more improvements for ListEditor
fix some glitches by refactoring ListCursor: mode is now always present, only idx is optional
2021-08-26 08:20:51 +02:00

315 lines
12 KiB
Rust

mod monstera;
use{
std::sync::{Arc, RwLock},
cgmath::{Point2, Vector2},
termion::event::{Event, Key},
nested::{
core::{
View,
ViewPort,
OuterViewPort,
Observer,
ObserverExt,
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}},
index::{IndexView},
sequence::{SequenceView},
vec::{VecBuffer},
integer::{RadixProjection, DigitEditor},
terminal::{
Terminal,
TerminalStyle,
TerminalAtom,
TerminalCompositor,
TerminalEvent,
make_label,
TerminalView,
TerminalEditor},
string_editor::{CharEditor},
tree_nav::{TreeNav, TreeNavResult, TreeCursor, TerminalTreeEditor},
list::{SExprView, ListCursorMode, ListEditor, ListEditorStyle}
}
};
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 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 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 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)
)
)
);
{
compositor.write().unwrap().push(magic.offset(Vector2::new(40, 4)));
//compositor.write().unwrap().push(magic.offset(Vector2::new(40, 20)));
//let monstera_port = monstera::make_monstera();
//compositor.write().unwrap().push(monstera_port.clone());
//compositor.write().unwrap().push(monstera_port.offset(Vector2::new(83,0)));
}
let cur_size_port = ViewPort::new();
let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
let mut y = 5;
// TypeEditor
let make_char_editor = || {
std::sync::Arc::new(std::sync::RwLock::new(DigitEditor::new(16)))
};
let make_sub_editor = move || {
std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_char_editor.clone(), ListEditorStyle::Hex)))
};
let mut te = ListEditor::new(make_sub_editor.clone(), ListEditorStyle::Clist);
te.goto(
TreeCursor {
leaf_mode: ListCursorMode::Insert,
tree_addr: vec![ 0 ]
}
);
compositor.write().unwrap().push(
te.get_term_view()
.offset(cgmath::Vector2::new(40,y))
);
y += 1;
let mut p = te.get_data_port().map(|sub_editor| sub_editor.read().unwrap().get_data_port());
let status_chars_port = ViewPort::new();
let mut status_chars = VecBuffer::new(status_chars_port.inner());
compositor.write().unwrap().push(
status_chars_port.outer()
.to_sequence()
.to_grid_horizontal()
.offset(cgmath::Vector2::new(40, 2))
);
loop {
term_port.update();
match term.next_event().await {
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)) => {
if te.pxev() == TreeNavResult::Exit {
te.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
if te.nexd() == TreeNavResult::Exit {
te.goto_end();
}
}
TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); }
TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); }
TerminalEvent::Input(Event::Key(Key::Home)) => {
if te.goto_home() == TreeNavResult::Exit {
te.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::End)) => {
if te.goto_end() == TreeNavResult::Exit {
te.goto_end();
}
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
/*
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;
line_port = ViewPort::new();
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();
te.goto_home();
te = ListEditor::new(make_sub_editor.clone());
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;
p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
*/
},
ev => {
if te.get_cursor().leaf_mode == ListCursorMode::Select {
match ev {
TerminalEvent::Input(Event::Key(Key::Char('l'))) => { te.up(); },
TerminalEvent::Input(Event::Key(Key::Char('a'))) => { te.dn(); },
TerminalEvent::Input(Event::Key(Key::Char('i'))) => { te.pxev(); },
TerminalEvent::Input(Event::Key(Key::Char('e'))) => { te.nexd(); },
TerminalEvent::Input(Event::Key(Key::Char('u'))) => { te.goto_home(); },
TerminalEvent::Input(Event::Key(Key::Char('o'))) => { te.goto_end(); },
_ => {
te.handle_terminal_event(&ev);
}
}
} else {
te.handle_terminal_event(&ev);
}
}
}
status_chars.clear();
let cur = te.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))));
}
}
//drop(term);
}
);
term_writer.show().await.expect("output error!");
}