diff --git a/Cargo.toml b/Cargo.toml index ce6bd01..73f07fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "lib-nested-core", "lib-nested-tty", "examples/tty-01-hello", - "examples/tty-02-node" + "examples/tty-02-digit", + "examples/tty-03-string", ] diff --git a/examples/tty-02-node/Cargo.toml b/examples/tty-02-digit/Cargo.toml similarity index 95% rename from examples/tty-02-node/Cargo.toml rename to examples/tty-02-digit/Cargo.toml index ccfc655..b875ea5 100644 --- a/examples/tty-02-node/Cargo.toml +++ b/examples/tty-02-digit/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tty-02-node" +name = "tty-02-digit" version = "0.1.0" edition = "2021" diff --git a/examples/tty-02-digit/src/main.rs b/examples/tty-02-digit/src/main.rs new file mode 100644 index 0000000..12b4f71 --- /dev/null +++ b/examples/tty-02-digit/src/main.rs @@ -0,0 +1,144 @@ +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}, + edit_tree::{EditTree} + }, + nested_tty::{ + DisplaySegment, TTYApplication, + TerminalCompositor, TerminalStyle, TerminalView, + TerminalAtom, TerminalEvent + }, + r3vi::{ + buffer::{singleton::*, vec::*}, + view::{port::UpdateTask, list::*} + }, + std::sync::{Arc, RwLock}, +}; + +#[async_std::main] +async fn main() { + /* setup context & create Editor-Tree + */ + 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); + + /* structure of Repr-Tree + * + * === Repr-Tree === + * + * + * / | \ + * / | \ + * / | \ + * u32 EditTree Char + * - Editor \ + * - Display EditTree + * / | \ - Editor + * / | \ - Display + * TTY PixelBuf SDF / | \ + * / | \ + * TTY PixelBuf SDF + */ + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "") ); + + /* add initial representation + * ~ Char + */ + rt_digit.insert_leaf( + Context::parse(&ctx, "Char"), + nested::repr_tree::ReprLeaf::from_singleton_buffer( SingletonBuffer::new('5') ) + ); + + /* furthermore, setup projections to and from u8 value, + * this synchronizes the buffers + */ + ctx.read().unwrap().morphisms.apply_morphism( + rt_digit.clone(), + &Context::parse(&ctx, "~Char"), + &Context::parse(&ctx, "~ℤ_256~machine::UInt8") + ); + + /* setup TTY-Display for DigitEditor + * + * `setup_edittree` will setup the projection + * Char -> Char~EditTree + * and call the hook defined above with `set_edittree_hook()` + * + */ + let edittree_digit = ctx.read().unwrap() + .setup_edittree( + rt_digit.clone(), + SingletonBuffer::new(0).get_port() + ); + + let mut digit_u8_buffer = rt_digit + .descend(Context::parse(&ctx, "ℤ_256~machine::UInt8")).unwrap() + .singleton_buffer::(); + + /* setup terminal + */ + let app = TTYApplication::new({ + /* event handler + */ + let ctx = ctx.clone(); + + let mut edittree_digit = edittree_digit.clone(); + move |ev| { + edittree_digit.get().send_cmd_obj(ev.to_repr_tree(&ctx)); + } + }); + + /* setup display view routed to `app.port` + */ + let compositor = TerminalCompositor::new(app.port.inner()); + + // add some views to the display compositor + { + let mut comp = compositor.write().unwrap(); + + comp.push( + nested_tty::make_label("Hello World") + .map_item(|p, a| { + a.add_style_back(TerminalStyle::fg_color(((25 * p.x % 255) as u8, 200, 0))) + }) + .offset(Vector2::new(5, 0)), + ); + + let label_str = ctx.read().unwrap().type_term_to_str(&rt_digit.read().unwrap().get_type()); + comp.push( + nested_tty::make_label(&label_str) + .map_item(|_pt,atom| atom.add_style_front(TerminalStyle::fg_color((90,90,90)))) + .offset(Vector2::new(1, 1)) + ); + comp.push( + edittree_digit.get().display_view() + .offset(Vector2::new(3,2)) + ); + comp.push( + digit_u8_buffer.get_port().map( + |d| nested_tty::make_label(&format!("Digit value={}", d)) + ) + .to_grid() + .flatten() + .offset(Vector2::new(5,3)) + ); + } + + /* write the changes in the view of `term_port` to the terminal + */ + app.show().await.expect("output error!"); +} diff --git a/examples/tty-02-node/src/main.rs b/examples/tty-02-node/src/main.rs deleted file mode 100644 index 7e40c63..0000000 --- a/examples/tty-02-node/src/main.rs +++ /dev/null @@ -1,223 +0,0 @@ -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}, - edit_tree::{EditTree} - }, - nested_tty::{ - DisplaySegment, TTYApplication, - TerminalCompositor, TerminalStyle, TerminalView, - TerminalAtom, TerminalEvent - }, - r3vi::{ - buffer::{singleton::*, vec::*}, - view::{port::UpdateTask} - }, -// termion::{}, - std::sync::{Arc, RwLock}, -}; - -#[async_std::main] -async fn main() { - /* setup context & create Editor-Tree - */ - 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() ); - - let char_type = Context::parse(&ctx, "Char"); - let digit_type = Context::parse(&ctx, ""); - let list_type = Context::parse(&ctx, ""); - let posint_type = Context::parse(&ctx, ""); - let item_tyid = ctx.read().unwrap().get_var_typeid("Item").unwrap(); - - ctx.write().unwrap().meta_chars.push(','); - ctx.write().unwrap().meta_chars.push('\"'); - ctx.write().unwrap().meta_chars.push('}'); - - // Define a hook which is executed when a new editTree of type `t` is created. - // this will setup the display and navigation elements of the editor. - // It provides the necessary bridge to the rendering- & input-backend. - ctx.write().unwrap().set_edittree_hook( - Arc::new( - move |et: &mut EditTree, t: laddertypes::TypeTerm| { -// let mut et = et.write().unwrap(); - - if let Ok(σ) = laddertypes::unify(&t, &char_type.clone()) { - *et = nested_tty::editors::edittree_make_char_view(et.clone()); - } - else if let Ok(σ) = laddertypes::unify(&t, &digit_type) { - *et = nested_tty::editors::edittree_make_digit_view(et.clone()); - } - else if let Ok(σ) = laddertypes::unify(&t, &posint_type) { - nested_tty::editors::list::PTYListStyle::for_node( &mut *et, ("0d", "", "")); - nested_tty::editors::list::PTYListController::for_node( &mut *et, None, None ); - } - else if let Ok(σ) = laddertypes::unify(&t, &list_type) { - let item_type = σ.get( &laddertypes::TypeID::Var(item_tyid) ).unwrap(); - - // choose style based on element type - if *item_type == char_type { - nested_tty::editors::list::PTYListStyle::for_node( &mut *et, ("\"", "", "\"")); - nested_tty::editors::list::PTYListController::for_node( &mut *et, None, Some('\"') ); - } else { - nested_tty::editors::list::PTYListStyle::for_node( &mut *et, ("{", ", ", "}")); - nested_tty::editors::list::PTYListController::for_node( &mut *et, Some(','), Some('}') ); - } - //*et = nested_tty::editors::edittree_make_list_edit(et.clone()); - } - } - ) - ); - - /* structure of Repr-Tree - * - * === Repr-Tree === - * - * - * / | \ - * / | \ - * / | \ - * u32 EditTree Char - * - Editor \ - * - Display EditTree - * / | \ - Editor - * / | \ - Display - * TTY PixelBuf SDF / | \ - * / | \ - * TTY PixelBuf SDF - */ - let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "") ); - - /* add initial representation - * ~ Char - */ - rt_digit.insert_leaf( - Context::parse(&ctx, "Char"), - nested::repr_tree::ReprLeaf::from_singleton_buffer( SingletonBuffer::new('5') ) - ); - - /* furthermore, setup projections to and from u8 value, - * this synchronizes the buffers - */ - ctx.read().unwrap().morphisms.apply_morphism( - rt_digit.clone(), - &Context::parse(&ctx, "~Char"), - &Context::parse(&ctx, "~ℤ_256~machine::UInt8") - ); - - /* setup TTY-Display for DigitEditor - * - * `setup_edittree` will setup the projection - * Char -> Char~EditTree - * and call the hook defined above with `set_edittree_hook()` - * - */ - let edittree_digit = ctx.read().unwrap() - .setup_edittree( - rt_digit.clone(), - r3vi::buffer::singleton::SingletonBuffer::new(0).get_port() - ); - - let mut digit_u8_buffer = rt_digit - .descend(Context::parse(&ctx, "ℤ_256~machine::UInt8")).unwrap() - .singleton_buffer::(); - - //--- - let rt_string = ReprTree::new_arc( Context::parse(&ctx, "") ); - - let edittree_list = ctx.read().unwrap() - .setup_edittree( - rt_string.clone(), - r3vi::buffer::singleton::SingletonBuffer::new(0).get_port()); - - /* setup terminal - */ - let app = TTYApplication::new({ - /* event handler - */ - let ctx = ctx.clone(); - let mut editors = Vec::new(); - editors.push(edittree_digit.clone()); - editors.push(edittree_list.clone()); - - let edit_select = Arc::new(RwLock::new(0)); - move |ev| { - match ev { - TerminalEvent::Input(termion::event::Event::Key(termion::event::Key::Char('\t'))) => { - let mut i = edit_select.write().unwrap(); - *i = (*i + 1) % editors.len(); - } - _ => { - let i = edit_select.read().unwrap(); - editors[*i].get().send_cmd_obj(ev.to_repr_tree(&ctx)); - } - } - } - }); - - /* setup display view routed to `app.port` - */ - let compositor = TerminalCompositor::new(app.port.inner()); - - // add some views to the display compositor - { - let mut comp = compositor.write().unwrap(); - - comp.push( - nested_tty::make_label("Hello World") - .map_item(|p, a| { - a.add_style_back(TerminalStyle::fg_color(((25 * p.x % 255) as u8, 200, 0))) - }) - .offset(Vector2::new(5, 0)), - ); - - comp.push( - edittree_digit.get().display_view() - .offset(Vector2::new(2,2)) - ); - - let label_str = ctx.read().unwrap().type_term_to_str(&rt_digit.read().unwrap().get_type()); - comp.push( - nested_tty::make_label(&label_str) - .map_item(|_pt,atom| atom.add_style_front(TerminalStyle::fg_color((90,90,90)))) - .offset(Vector2::new(0, 1)) - ); - - comp.push( - digit_u8_buffer.get_port().map( - |d| nested_tty::make_label(&format!("Digit={}", d)) - ) - .to_grid() - .flatten() - .offset(Vector2::new(2,3)) - ); - - - comp.push( - edittree_list.get().display_view() - .offset(Vector2::new(2,6)) - ); - - let label_str = ctx.read().unwrap().type_term_to_str(&rt_string.read().unwrap().get_type()); - comp.push( - nested_tty::make_label(&label_str) - .map_item(|_pt, atom| atom.add_style_front(TerminalStyle::fg_color((90,90,90)))) - .offset(Vector2::new(0, 5)) - ); - } - - /* write the changes in the view of `term_port` to the terminal - */ - app.show().await.expect("output error!"); -} diff --git a/examples/tty-03-string/Cargo.toml b/examples/tty-03-string/Cargo.toml new file mode 100644 index 0000000..10763ef --- /dev/null +++ b/examples/tty-03-string/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tty-03-string" +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-03-string/src/main.rs b/examples/tty-03-string/src/main.rs new file mode 100644 index 0000000..de84271 --- /dev/null +++ b/examples/tty-03-string/src/main.rs @@ -0,0 +1,118 @@ +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}, + edit_tree::{EditTree} + }, + nested_tty::{ + DisplaySegment, TTYApplication, + TerminalCompositor, TerminalStyle, TerminalView, + TerminalAtom, TerminalEvent + }, + r3vi::{ + buffer::{singleton::*, vec::*}, + view::{port::UpdateTask, list::*} + }, + 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); + + + /* Create a Representation-Tree of type + */ + let rt_string = ReprTree::new_arc( Context::parse(&ctx, "") ); + + /* Setup an Editor for this ReprTree + * (by adding the representation ~EditTree to the ReprTree) + */ + let edittree_list = ctx.read().unwrap() + .setup_edittree( + rt_string.clone(), + SingletonBuffer::new(0).get_port()); + + /* In order to get acces to the values that are modified by the Editor, + * we apply a morphism that, given the List of Edit-Trees, extracts + * the value from each EditTree and shows them in a ListView. + */ + ctx.read().unwrap().morphisms.apply_morphism( + rt_string.clone(), + &Context::parse(&ctx, "~EditTree"), + &Context::parse(&ctx, "") + ); + + /* Now, get the ListView that serves our char-values. + * This view is a projection created by the morphism that was called above. + */ + let mut chars_view = rt_string + .read().unwrap() + .get_port::>() + .unwrap(); + + /* transform ListView into a TerminalView + */ + let string_view_tty = chars_view + .to_sequence() + .to_grid_vertical() + .map_item(|_pt,c| TerminalAtom::new(*c, TerminalStyle::fg_color((200,10,60)))); + + /* setup terminal + */ + let app = TTYApplication::new({ + let edittree_list = edittree_list.clone(); + + /* event handler + */ + let ctx = ctx.clone(); + move |ev| { + edittree_list.get().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(); + + let label_str = ctx.read().unwrap().type_term_to_str(&rt_string.read().unwrap().get_type()); + comp.push( + nested_tty::make_label(&label_str) + .map_item(|_pt, atom| atom.add_style_front(TerminalStyle::fg_color((90,90,90)))) + .offset(Vector2::new(1, 1))); + + comp.push( + edittree_list.get() + .display_view() + .offset(Vector2::new(3,2))); + + comp.push( + string_view_tty + .offset(Vector2::new(5,3))); + } + + /* write the changes in the view of `term_port` to the terminal + */ + app.show().await.expect("output error!"); +} diff --git a/lib-nested-tty/Cargo.toml b/lib-nested-tty/Cargo.toml index e85b2d9..0e5b412 100644 --- a/lib-nested-tty/Cargo.toml +++ b/lib-nested-tty/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] r3vi = { path = "../../lib-r3vi" } +laddertypes = { path = "../../lib-laddertypes" } nested = { path = "../lib-nested-core" } cgmath = { version = "0.18.0", features = ["serde"] } serde = { version = "1.0", features = ["serde_derive"] } diff --git a/lib-nested-tty/src/lib.rs b/lib-nested-tty/src/lib.rs index 0da7946..2bc1138 100644 --- a/lib-nested-tty/src/lib.rs +++ b/lib-nested-tty/src/lib.rs @@ -114,3 +114,54 @@ impl TerminalProjections for OuterViewPort { } +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub fn setup_edittree_hook(ctx: &Arc>) { + + let char_type = Context::parse(&ctx, "Char"); + let digit_type = Context::parse(&ctx, ""); + let list_type = Context::parse(&ctx, ""); + let posint_type = Context::parse(&ctx, ""); + let item_tyid = ctx.read().unwrap().get_var_typeid("Item").unwrap(); + + ctx.write().unwrap().meta_chars.push(','); + ctx.write().unwrap().meta_chars.push('\"'); + ctx.write().unwrap().meta_chars.push('}'); + + // Define a hook which is executed when a new editTree of type `t` is created. + // this will setup the display and navigation elements of the editor. + // It provides the necessary bridge to the rendering- & input-backend. + ctx.write().unwrap().set_edittree_hook( + Arc::new( + move |et: &mut nested::edit_tree::EditTree, t: laddertypes::TypeTerm| { +// let mut et = et.write().unwrap(); + + if let Ok(σ) = laddertypes::unify(&t, &char_type.clone()) { + *et = crate::editors::edittree_make_char_view(et.clone()); + } + else if let Ok(σ) = laddertypes::unify(&t, &digit_type) { + *et = crate::editors::edittree_make_digit_view(et.clone()); + } + else if let Ok(σ) = laddertypes::unify(&t, &posint_type) { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("0d", "", "")); + crate::editors::list::PTYListController::for_node( &mut *et, None, None ); + } + else if let Ok(σ) = laddertypes::unify(&t, &list_type) { + let item_type = σ.get( &laddertypes::TypeID::Var(item_tyid) ).unwrap(); + + // choose style based on element type + if *item_type == char_type { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("\"", "", "\"")); + crate::editors::list::PTYListController::for_node( &mut *et, None, Some('\"') ); + } else { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("{", ", ", "}")); + crate::editors::list::PTYListController::for_node( &mut *et, Some(','), Some('}') ); + } + //*et = nested_tty::editors::edittree_make_list_edit(et.clone()); + } + } + ) + ); + +} +