diff --git a/Cargo.toml b/Cargo.toml index 44403c7..38b4295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ members = [ "examples/tty-02-digit", "examples/tty-03-string", "examples/tty-04-posint", + "examples/tty-05-dictionary", ] diff --git a/examples/tty-05-dictionary/Cargo.toml b/examples/tty-05-dictionary/Cargo.toml new file mode 100644 index 0000000..fef954f --- /dev/null +++ b/examples/tty-05-dictionary/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tty-05-dictionary" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +laddertypes = { path = "../../../lib-laddertypes" } +r3vi = { path = "../../../lib-r3vi" } +nested = { path = "../../lib-nested-core" } +nested-tty = { path = "../../lib-nested-tty" } +termion = "*" +cgmath = "*" + +[dependencies.async-std] +version = "1.9.0" +features = ["unstable", "attributes"] + diff --git a/examples/tty-05-dictionary/src/main.rs b/examples/tty-05-dictionary/src/main.rs new file mode 100644 index 0000000..d6daefc --- /dev/null +++ b/examples/tty-05-dictionary/src/main.rs @@ -0,0 +1,299 @@ +extern crate cgmath; +extern crate nested; +extern crate nested_tty; +extern crate r3vi; +extern crate termion; + +use { + cgmath::Vector2, + nested::{ + editors::{ + ObjCommander + }, + repr_tree::{Context, ReprTree, ReprTreeExt, ReprLeaf}, + edit_tree::{EditTree, TreeNav, TreeCursor} + }, + laddertypes::{ + bimap::Bimap, + sugar::SugaredTypeTerm + }, + nested_tty::{ + DisplaySegment, TTYApplication, + TerminalCompositor, TerminalStyle, TerminalView, + TerminalAtom, TerminalEvent + }, + r3vi::{ + buffer::{singleton::*, vec::*}, + view::{port::UpdateTask, singleton::*, list::*, sequence::*}, + projection::* + }, + std::sync::{Arc, RwLock}, +}; + +#[async_std::main] +async fn main() { + /* setup context + */ + let ctx = Arc::new(RwLock::new(Context::new())); + nested::editors::char::init_ctx( ctx.clone() ); + nested::editors::digit::init_ctx( ctx.clone() ); + nested::editors::integer::init_ctx( ctx.clone() ); + nested::editors::list::init_ctx( ctx.clone() ); + nested_tty::setup_edittree_hook(&ctx); + + let dict = Arc::new(RwLock::new(Bimap::::new())); + dict.write().unwrap().insert( "Nop".into(), 0 ); + dict.write().unwrap().insert( "Jmp".into(), 1 ); + dict.write().unwrap().insert( "Call".into(), 2 ); + dict.write().unwrap().insert( "Branch".into(), 3 ); + dict.write().unwrap().insert( "Ret".into(), 4 ); + dict.write().unwrap().insert( "Lit".into(), 5 ); + dict.write().unwrap().insert( "Pick".into(), 6 ); + dict.write().unwrap().insert( "Roll".into(), 7 ); + dict.write().unwrap().insert( "Dup".into(), 8 ); + dict.write().unwrap().insert( "Drop".into(), 9 ); + dict.write().unwrap().insert( "Swap".into(), 10 ); + dict.write().unwrap().insert( "Rot".into(), 11 ); + dict.write().unwrap().insert( "Fetch".into(), 13 ); + dict.write().unwrap().insert( "Store".into(), 14 ); + dict.write().unwrap().insert( "Accept".into(), 15 ); + dict.write().unwrap().insert( "Emit".into(), 16 ); + dict.write().unwrap().insert( "IntAdd".into(), 17 ); + dict.write().unwrap().insert( "IntSub".into(), 18 ); + dict.write().unwrap().insert( "IntMul".into(), 19 ); + dict.write().unwrap().insert( "IntDiv".into(), 20 ); + dict.write().unwrap().insert( "IntRem".into(), 21 ); + dict.write().unwrap().insert( "FltAdd".into(), 22 ); + dict.write().unwrap().insert( "FltSub".into(), 23 ); + dict.write().unwrap().insert( "FltMul".into(), 24 ); + dict.write().unwrap().insert( "FltDiv".into(), 25 ); + dict.write().unwrap().insert( "FltRem".into(), 26 ); + dict.write().unwrap().insert( "BitNeg".into(), 28 ); + dict.write().unwrap().insert( "BitAnd".into(), 29 ); + dict.write().unwrap().insert( "BitOr".into(), 30 ); + dict.write().unwrap().insert( "BitXor".into(), 31 ); + dict.write().unwrap().insert( "BitShl".into(), 32 ); + dict.write().unwrap().insert( "BitShr".into(), 33 ); + + let symbol_morph_str_to_u64 = nested::repr_tree::GenericReprTreeMorphism::new( + Context::parse(&ctx, "Instruction ~ Mnemonic ~ "), + Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ machine.UInt64"), + + { + let ctx = ctx.clone(); + let dict = dict.clone(); + + move |rt, σ| { + let str_view = rt + .descend(Context::parse(&ctx, "Instruction ~ Mnemonic ~ ")).unwrap() + .vec_buffer::() + .get_port(); + + let u64_view = str_view + .to_singleton() + .map({ + let old_value = Arc::new(RwLock::new(0)); + let dict = dict.clone(); + move |chars| { + let str_val = chars.iter().collect::(); + let dict = &dict.read().unwrap().mλ; + + let mut old_value = old_value.write().unwrap(); + if let Some( new_value ) = dict.get( &str_val ) { + *old_value = new_value.clone(); + new_value.clone() + } else { + old_value.clone() + } + } + }); + + rt.attach_leaf_to( + Context::parse(&ctx, "Opcode ~ ℕ ~ machine.UInt64"), + u64_view + ); + } + } + ); + + let symbol_morph_u64_to_str = nested::repr_tree::GenericReprTreeMorphism::new( + Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ machine.UInt64"), + Context::parse(&ctx, "Instruction ~ Mnemonic ~ "), + + { + let ctx = ctx.clone(); + let dict = dict.clone(); + + move |rt, σ| { + let u64_view = rt + .descend(Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ machine.UInt64")).unwrap() + .view_u64(); + + let str_view = + u64_view + .map({ + let dict = dict.clone(); + let old_value = Arc::new(RwLock::new( VecBuffer::::new() )); + move |idx| { + let dict = &dict.read().unwrap().my; + let mut old_value = old_value.write().unwrap(); + if let Some( new_value ) = dict.get( &idx ) { + *old_value = VecBuffer::::with_data( + new_value.chars().collect::>() + ); + } + + old_value.get_port().to_sequence() + } + }) + .to_sequence() + .flatten(); + + rt.attach_leaf_to( + Context::parse(&ctx, "Instruction ~ Mnemonic ~ "), + str_view + ); + } + } + ); + + ctx.write().unwrap().morphisms.add_morphism( symbol_morph_u64_to_str ); + ctx.write().unwrap().morphisms.add_morphism( symbol_morph_str_to_u64 ); + + let mut symbol_rt = nested::repr_tree::ReprTree::from_str(Context::parse(&ctx, " + Instruction ~ Mnemonic ~ + "), + "Call" + ); + + // this is required to initialize the representation, + // and to take the value from + ctx.read().unwrap().build_repr_tree( + &symbol_rt, + Context::parse(&ctx, "Instruction ~ Mnemonic ~ "), + vec![ + Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ ~ EditTree"), + Context::parse(&ctx, "Instruction ~ Mnemonic ~ ~ EditTree"), + ]); + + symbol_rt.write().unwrap().detach( &ctx ); + + fn set_master( + ctx: &Arc>, + rt: &Arc>, + mut leaves: Vec< laddertypes::TypeTerm >, + master_idx: usize + ) { + eprintln!("set master to {}", master_idx); + if master_idx < leaves.len() { + let master = leaves.remove( master_idx ); + rt.write().unwrap().detach( &ctx ); + ctx.read().unwrap().build_repr_tree( + rt, + master, + leaves + ); + } + } + + let editor_types = vec![ + Context::parse(&ctx, + "Instruction ~ Mnemonic ~ ~ EditTree"), + Context::parse(&ctx, + "Instruction ~ Opcode ~ ℕ ~ ~ EditTree"), + Context::parse(&ctx, + "Instruction ~ Opcode ~ ℕ ~ ~ EditTree"), + ]; + + set_master(&ctx, &symbol_rt, editor_types.clone(), 0); + let mut list_editor = nested::editors::list::ListEditor::new(ctx.clone(), Context::parse(&ctx, "")); + + // add all desired editors to the list + for leaf in editor_types.iter() { + let et = + symbol_rt + .descend(leaf.clone()).unwrap() + .edittree(&ctx).get(); + et.write().unwrap().goto(TreeCursor::none()); + list_editor.data.push(et); + } + + let mut edittree = list_editor.into_node(SingletonBuffer::new(0).get_port()); + edittree.goto(TreeCursor{ + leaf_mode: nested::editors::list::ListCursorMode::Insert, + tree_addr: vec![0, 0] + }); + let edittree = Arc::new(RwLock::new(edittree)); + + /* setup terminal + */ + let app = TTYApplication::new({ + /* event handler + */ + let ctx = ctx.clone(); + let symbol_rt = symbol_rt.clone(); + let last_idx = RwLock::new(0); + let editor_types = editor_types.clone(); + move |ev| { + let cur = edittree.read().unwrap().get_cursor(); + if cur.tree_addr.len() > 0 { + let mut li = last_idx.write().unwrap(); + let ci = cur.tree_addr[0]; + + if *li != ci { + eprintln!("----------------------------------"); + set_master( + &ctx, + &symbol_rt, + editor_types.clone(), + ci as usize + ); + *li = ci; + } + } + + edittree.write().unwrap().send_cmd_obj(ev.to_repr_tree(&ctx)); + } + }); + + /* Setup the compositor to serve as root-view + * by routing it to the `app.port` Viewport, + * so it will be displayed on TTY-output. + */ + let compositor = TerminalCompositor::new(app.port.inner()); + + /* Now add some views to our compositor + */ + { + let mut comp = compositor.write().unwrap(); + + fn show_edit_tree( + ctx: &Arc>, + comp: &mut TerminalCompositor, + rt: &Arc>, + y: i16 + ) { + let rt_edittree = rt.descend(Context::parse(&ctx, "EditTree")).expect("descend"); + let halo_type = rt_edittree.read().unwrap().get_halo_type().clone(); + let edittree = rt_edittree.read().unwrap().get_view::>>>().unwrap().get().read().unwrap().clone(); + + comp.push( nested_tty::make_label( &ctx.read().unwrap().type_term_to_str(&halo_type) ) + .map_item(|_pt, atom| atom.add_style_front(TerminalStyle::fg_color((90,90,90)))) + .offset(Vector2::new(1,y))); + + comp.push( edittree.display_view() + .map_item(|_pt, atom| + atom.add_style_front(TerminalStyle::bg_color((80,80,80))) + ) + .offset(Vector2::new(1,y+1))); + } + + show_edit_tree( &ctx, &mut comp, &symbol_rt.descend(Context::parse(&ctx, "Instruction ~ Mnemonic ~ ")).unwrap(), 1 ); + show_edit_tree( &ctx, &mut comp, &symbol_rt.descend(Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ ")).unwrap(), 3 ); + show_edit_tree( &ctx, &mut comp, &symbol_rt.descend(Context::parse(&ctx, "Instruction ~ Opcode ~ ℕ ~ ")).unwrap(), 5 ); + } + + /* write the changes in the view of `term_port` to the terminal + */ + app.show().await.expect("output error!"); +}