diff --git a/Cargo.toml b/Cargo.toml index 641b295..44403c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,14 @@ [workspace] members = [ - "nested", -# "terminal/display_server", -# "terminal/ansi_parser", -# "math/str2int", -# "math/int2str", -# "math/radix_transform", -# "math/fib" + "lib-nested-core", + "lib-nested-tty", + + "srv-tty-output", + "srv-pty-capture", + + "examples/tty-01-hello", + "examples/tty-02-digit", + "examples/tty-03-string", + "examples/tty-04-posint", ] + diff --git a/math/radix_transform/Cargo.toml b/examples/tty-01-hello/Cargo.toml similarity index 53% rename from math/radix_transform/Cargo.toml rename to examples/tty-01-hello/Cargo.toml index 678a012..4582fd7 100644 --- a/math/radix_transform/Cargo.toml +++ b/examples/tty-01-hello/Cargo.toml @@ -1,13 +1,18 @@ [package] -name = "radix_transform" +name = "tty-01-hello" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nested = { path = "../../nested" } +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-01-hello/README.md b/examples/tty-01-hello/README.md new file mode 100644 index 0000000..b1be4e7 --- /dev/null +++ b/examples/tty-01-hello/README.md @@ -0,0 +1,8 @@ +# tty-01-hello + +This example shows how to: + - initialize the TTY backend (`lib-nestetd-tty`), + - create a simple 'Hello World' output, + - create color gradients on the outputted text + utilizing basic projection functionality from `lib-r3vi`, + - perform basic layouting & compositing. diff --git a/examples/tty-01-hello/src/main.rs b/examples/tty-01-hello/src/main.rs new file mode 100644 index 0000000..468d8f5 --- /dev/null +++ b/examples/tty-01-hello/src/main.rs @@ -0,0 +1,60 @@ +//! This example shows how to: +//! - initialize the TTY backend (`lib-nestetd-tty`), +//! - create a simple 'Hello World' output, +//! - create color gradients on the outputted text +//! utilizing basic projection functionality from `lib-r3vi`, +//! - perform basic layouting & compositing. + +extern crate cgmath; +extern crate nested; +extern crate nested_tty; +extern crate r3vi; +extern crate termion; + +use { + cgmath::Vector2, + nested::repr_tree::Context, + nested_tty::{Terminal, TerminalCompositor, TTYApplication, TerminalEvent, TerminalStyle, TerminalView}, + r3vi::view::{port::UpdateTask, ViewPort}, + std::sync::{Arc, RwLock}, + termion::event::{Event, Key}, +}; + +#[async_std::main] +async fn main() { + /* Initialize our terminal. + */ + let tty_app = TTYApplication::new(|event| { /* handle event */ }); + + /* Setup our "root" view of the application. + * This will be the compositor, which is able to + * mix multiple `TerminalView`-Views together. + * Its output is routed to the `app.port` Viewport, + * so it will be displayed on TTY-output. + */ + let compositor = TerminalCompositor::new(tty_app.port.inner()); + + /* Add the label 'test' at position (7, 2) + */ + compositor + .write() + .unwrap() + .push(nested_tty::make_label("test").offset(Vector2::new(7, 2))); + + /* Add a 'Hello World' label at position (5, 3) + * and set a coloring determined by formula from + * the position of each character. + */ + compositor.write().unwrap().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, 3)), + ); + + /* write the changes in the root-view to the terminal + */ + tty_app.show().await.expect("output error!"); +} + diff --git a/examples/tty-02-digit/Cargo.toml b/examples/tty-02-digit/Cargo.toml new file mode 100644 index 0000000..b875ea5 --- /dev/null +++ b/examples/tty-02-digit/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tty-02-digit" +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-02-digit/README.md b/examples/tty-02-digit/README.md new file mode 100644 index 0000000..23b502b --- /dev/null +++ b/examples/tty-02-digit/README.md @@ -0,0 +1,4 @@ +# tty-02-digit + +This example demonstrates how a very simple editor for hexadecimal digits +can be created with `lib-nested` and the `lib-nested-tty` backend. diff --git a/examples/tty-02-digit/src/main.rs b/examples/tty-02-digit/src/main.rs new file mode 100644 index 0000000..9279cc5 --- /dev/null +++ b/examples/tty-02-digit/src/main.rs @@ -0,0 +1,137 @@ +//! This example demonstrates how a very simple editor for hexadecimal digits +//! can be created with `lib-nested` and the `lib-nested-tty` backend. + +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 === + * + * <Digit 10> + * / | \ + * / | \ + * / | \ + * u64 EditTree Char + * - Editor \ + * - Display EditTree + * / | \ - Editor + * / | \ - Display + * TTY PixelBuf SDF / | \ + * / | \ + * TTY PixelBuf SDF + */ + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "<Digit 16>") ); + + /* add initial representation + * <Digit 16> ~ 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().apply_morphism( + &rt_digit, + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<Digit 16>~Char"), + dst_type: Context::parse(&ctx, "<Digit 16>~ℤ_2^64~machine.UInt64") + } + ); + ctx.read().unwrap().apply_morphism( + &rt_digit, + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<Digit 16>~Char"), + dst_type: Context::parse(&ctx, "<Digit 16>~EditTree") + } + ); + + /* setup terminal + */ + let app = TTYApplication::new({ + /* event handler + */ + let ctx = ctx.clone(); + let digit_edittree = rt_digit.edittree( &ctx ); + move |ev| { + digit_edittree.get().write().unwrap().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(rt_digit + .edittree( &ctx ).get().read().unwrap() + .display_view() + .offset(Vector2::new(3,2))); + + comp.push(rt_digit + .descend(Context::parse(&ctx, "ℤ_2^64~machine.UInt64")).unwrap() + .view_u64() + .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-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/README.md b/examples/tty-03-string/README.md new file mode 100644 index 0000000..85305aa --- /dev/null +++ b/examples/tty-03-string/README.md @@ -0,0 +1,8 @@ +# tty-03-string + +Similarly to `tty-02-digit`, a editor is created +but of type <List Char>. +The contents of the editor can be retrieved by +a morphism from the `EditTree` node. +To demonstrate that, the values are are mapped +to the TTY-display in different form. diff --git a/examples/tty-03-string/src/main.rs b/examples/tty-03-string/src/main.rs new file mode 100644 index 0000000..d5f8ff9 --- /dev/null +++ b/examples/tty-03-string/src/main.rs @@ -0,0 +1,168 @@ +//! Similarly to `tty-02-digit`, a editor is created +//! but of type <List Char>. +//! The contents of the editor can be retrieved by +//! a morphism from the `EditTree` node. +//! To demonstrate that, the values are are mapped +//! to the TTY-display in different form. + +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::*, sequence::SequenceViewExt} + }, + 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 <List Char> + */ + let mut rt_string = ReprTree::from_str( + Context::parse(&ctx, "<List Char>~<Vec Char>"), + "hello world" + ); + + /* create EditTree + */ + ctx.read().unwrap().apply_morphism( + &rt_string, + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<List~Vec Char>"), + dst_type: Context::parse(&ctx, "<List Char> ~ EditTree") + } + ); + + // .. avoid cycle of projections.. + rt_string.write().unwrap().detach(&ctx); + + /* In order to get access 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().apply_morphism( + &rt_string, + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<List Char>~EditTree"), + dst_type: Context::parse(&ctx, "<List Char>") + } + ); + + /* 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::<dyn ListView<char>>() + .unwrap(); + + /* Lets add another morphism which will store the values + * of the character-list in a `Vec<char>` + */ + ctx.read().unwrap().apply_morphism( + &rt_string, + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<List Char>"), + dst_type: Context::parse(&ctx, "<List Char>~<Vec Char>") + } + ); + + /* Access the Vec<char> object (wrapped behind a VecBuffer<char>) + * from the ReprTree. + */ + let chars_vec = rt_string + .descend(Context::parse(&ctx, "<Vec Char>")).unwrap() + .vec_buffer::<char>(); + + /* transform `ListView<char>` 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 = rt_string.edittree(&ctx).clone(); + + /* event handler + */ + let ctx = ctx.clone(); + move |ev| { + edittree_list.get().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(); + + 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( + rt_string.edittree(&ctx).get() + .read().unwrap() + .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!"); + + /* need to call update because changes are applied lazily + */ + chars_vec.get_port().0.update(); + + /* Vec<char> to String + */ + let string = chars_vec + .get_port() + .to_sequence() + .get_view().unwrap() + //.data.read().unwrap() + .iter().collect::<String>(); + + eprintln!("value of the editor was: {}\n\n", string); +} diff --git a/examples/tty-04-posint/Cargo.toml b/examples/tty-04-posint/Cargo.toml new file mode 100644 index 0000000..0e4e285 --- /dev/null +++ b/examples/tty-04-posint/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tty-04-posint" +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-04-posint/README.md b/examples/tty-04-posint/README.md new file mode 100644 index 0000000..1f85cdd --- /dev/null +++ b/examples/tty-04-posint/README.md @@ -0,0 +1,7 @@ +# tty-04-posint + +In the following example, a <List Char> editor +as before is used, but its data is morphed into +representing a positional integer which is then +projected into different radices and displayed +in different views on screen diff --git a/examples/tty-04-posint/src/main.rs b/examples/tty-04-posint/src/main.rs new file mode 100644 index 0000000..4c91ee5 --- /dev/null +++ b/examples/tty-04-posint/src/main.rs @@ -0,0 +1,199 @@ +//! In the following example, a <List Char> editor +//! as before is used, but its data is morphed into +//! representing a positional integer which is then +//! projected into different radices and displayed +//! in different views on screen + +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} + }, + 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); + + /* Create a Representation-Tree of type `ℕ` + * with a specific representation-path (big-endian hexadecimal string) + */ + let mut rt_int = nested::repr_tree::ReprTree::from_str( + /* TYPE */ + Context::parse(&ctx, " + ℕ + ~ <PosInt 16 BigEndian> + ~ <Seq <Digit 16>> + ~ <List <Digit 16>> + ~ <List Char> + ~ <Vec Char> + "), + + /* VALUE */ + "cff" + ); + + /* initially copy values from Vec to EditTree... + */ + ctx.read().unwrap().build_repr_tree( + &rt_int, + Context::parse(&ctx, "ℕ ~ <PosInt 16 BigEndian> ~ <Seq~List <Digit 16>~Char> ~ <Vec Char>"), + vec![ + Context::parse(&ctx, "ℕ ~ <PosInt 16 BigEndian> ~ <Seq~List <Digit 16>> ~ EditTree"), + Context::parse(&ctx, "ℕ ~ <PosInt 16 LittleEndian> ~ <Seq~List <Digit 16>> ~ EditTree"), + ]); + + fn set_master( + ctx: &Arc<RwLock<Context>>, + rt: &Arc<RwLock<ReprTree>>, + 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, + "ℕ ~ <PosInt 16 BigEndian> ~ <Seq~List <Digit 16>> ~ EditTree"), + Context::parse(&ctx, + "ℕ ~ <PosInt 16 LittleEndian> ~ <Seq~List <Digit 16>> ~ EditTree"), + Context::parse(&ctx, + "ℕ ~ <PosInt 16 BigEndian> ~ EditTree"), + Context::parse(&ctx, + "ℕ ~ <PosInt 8 BigEndian> ~ EditTree"), + Context::parse(&ctx, + "ℕ ~ <PosInt 2 BigEndian> ~ EditTree"), + ]; + + set_master(&ctx, &rt_int, editor_types.clone(), 0); + + /* list of editors + */ + let mut list_editor = nested::editors::list::ListEditor::new(ctx.clone(), Context::parse(&ctx, "<Seq Char>")); + + // add all desired editors to the list + for leaf in editor_types.iter() { + let et = + rt_int + .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()); + + /* cursors are a bit screwed initially so fix them up + * TODO: how to fix this generally? + */ + 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 rt_int = rt_int.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, + &rt_int, + 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<RwLock<Context>>, comp: &mut TerminalCompositor, rt: &Arc<RwLock<ReprTree>>, 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.edittree( &ctx ); + + 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.get().read().unwrap().display_view() + .offset(Vector2::new(1,y+1))); + } + + let mut y = 1; + for t in editor_types.iter() { + show_edit_tree(&ctx, &mut comp, &rt_int.descend(t.clone()).expect(""), y); + y += 3; + } + } + + /* write the changes in the view of `term_port` to the terminal + */ + app.show().await.expect("output error!"); +} + diff --git a/lib-nested-core/Cargo.toml b/lib-nested-core/Cargo.toml new file mode 100644 index 0000000..0805fce --- /dev/null +++ b/lib-nested-core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +authors = ["Michael Sippel <micha@fragmental.art>"] +edition = "2018" +name = "nested" +version = "0.1.0" + +[dependencies] +r3vi = { path = "../../lib-r3vi" } +laddertypes = { path = "../../lib-laddertypes" } +cgmath = { version = "0.18.0", features = ["serde"] } + diff --git a/nested/src/tree/addr.rs b/lib-nested-core/src/edit_tree/addr.rs similarity index 100% rename from nested/src/tree/addr.rs rename to lib-nested-core/src/edit_tree/addr.rs diff --git a/nested/src/tree/cursor.rs b/lib-nested-core/src/edit_tree/cursor.rs similarity index 100% rename from nested/src/tree/cursor.rs rename to lib-nested-core/src/edit_tree/cursor.rs diff --git a/lib-nested-core/src/edit_tree/diagnostics.rs b/lib-nested-core/src/edit_tree/diagnostics.rs new file mode 100644 index 0000000..4b39a1f --- /dev/null +++ b/lib-nested-core/src/edit_tree/diagnostics.rs @@ -0,0 +1,24 @@ +use { + r3vi::{ + view::{OuterViewPort, sequence::*}, + buffer::{vec::*, index_hashmap::*} + }, + crate::{ + repr_tree::ReprTree + }, + std::sync::{Arc, RwLock}, + cgmath::Point2 +}; + +#[derive(Clone)] +pub struct Message { + pub addr: Vec<usize>, + pub disp: Arc<RwLock<ReprTree>> +} + +pub trait Diagnostics { + fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { + VecBuffer::new().get_port().to_sequence() + } +} + diff --git a/nested/src/tree/mod.rs b/lib-nested-core/src/edit_tree/mod.rs similarity index 83% rename from nested/src/tree/mod.rs rename to lib-nested-core/src/edit_tree/mod.rs index 71e40c8..92e0411 100644 --- a/nested/src/tree/mod.rs +++ b/lib-nested-core/src/edit_tree/mod.rs @@ -3,12 +3,13 @@ pub mod cursor; pub mod nav; pub mod node; pub mod treetype; +pub mod diagnostics; pub use { addr::TreeAddr, cursor::TreeCursor, nav::{TreeNav, TreeNavResult, TreeHeightOp}, treetype::{TreeType}, - node::NestedNode + node::EditTree }; diff --git a/nested/src/tree/nav.rs b/lib-nested-core/src/edit_tree/nav.rs similarity index 74% rename from nested/src/tree/nav.rs rename to lib-nested-core/src/edit_tree/nav.rs index 9d85cdd..a8dc371 100644 --- a/nested/src/tree/nav.rs +++ b/lib-nested-core/src/edit_tree/nav.rs @@ -15,8 +15,7 @@ use { }, crate::{ editors::list::ListCursorMode, - tree::TreeCursor, - terminal::{TerminalView, TerminalProjections, make_label} + edit_tree::TreeCursor }, cgmath::Vector2, }; @@ -27,9 +26,19 @@ pub enum TreeNavResult { Continue, Exit } #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub enum TreeHeightOp { P, Q, Max } +#[derive(Clone, Copy, Debug)] +pub enum TreeNavCmd { + pxev, nexd, up, dn, + qpxev, qnexd, dup, qdn, + + dn_pxev, + up_nexd, + pxev_dn_qnexd +} + pub trait TreeNav { /* CORE - */ + */ fn get_cursor(&self) -> TreeCursor { TreeCursor::default() } @@ -150,35 +159,6 @@ pub trait TreeNav { } } - fn get_cursor_widget(&self) -> OuterViewPort<dyn TerminalView> { - VecBuffer::with_data( - vec![ - make_label("@").with_fg_color((150, 80,230)), - self.get_addr_view() - .map(|i| - make_label(&format!("{}", i)).with_fg_color((0, 100, 20))) - .separate(make_label(".").with_fg_color((150, 80,230))) - .to_grid_horizontal() - .flatten(), - make_label(":").with_fg_color((150, 80,230)), - self.get_mode_view() - .map(|mode| { - make_label( - match mode { - ListCursorMode::Insert => "INSERT", - ListCursorMode::Select => "SELECT" - }) - .with_fg_color((200, 200, 20)) - }) - .to_grid() - .flatten(), - make_label(":").with_fg_color((150, 80,230)) - ] - ).get_port() - .to_sequence() - .to_grid_horizontal() - .flatten() - } } diff --git a/lib-nested-core/src/edit_tree/node.rs b/lib-nested-core/src/edit_tree/node.rs new file mode 100644 index 0000000..8b5a8a6 --- /dev/null +++ b/lib-nested-core/src/edit_tree/node.rs @@ -0,0 +1,228 @@ +use { + std::{sync::{Arc, RwLock}, any::Any}, + cgmath::{Vector2, Point2}, + r3vi::{ + view::{View, ViewPort, OuterViewPort, AnyOuterViewPort, singleton::*, sequence::*}, + buffer::{singleton::*, vec::*} + }, + laddertypes::{TypeTerm}, + crate::{ + repr_tree::{ReprTree, Context}, + edit_tree::{TreeNav, TreeCursor, TreeNavResult, TreeHeightOp, diagnostics::{Diagnostics, Message}}, + editors::{list::{ListCursorMode}, ObjCommander} + } +}; + +#[derive(Clone)] +pub struct EdittreeDisplay { + /// display view + pub view: Arc<RwLock<ReprTree>>, + + /// diagnostics + pub diag: Option< OuterViewPort<dyn SequenceView<Item = Message>> >, + + /// depth + pub depth: OuterViewPort<dyn SingletonView<Item = usize>>, +} + +#[derive(Clone)] +pub struct EdittreeControl { + /// abstract editor + pub editor: SingletonBuffer< + Option< Arc<dyn Any + Send + Sync> > + >, + + pub spillbuf: Arc<RwLock< + Vec< Arc<RwLock< EditTree >> > + >>, + + /// commander & navigation + pub cmd: SingletonBuffer< + Option< Arc<RwLock<dyn ObjCommander + Send + Sync>> > + >, /// abstract data view + + pub close_char: SingletonBuffer< Option< char > >, + + // could be replaced by cmd when TreeNav -CmdObjects are used + pub tree_nav: SingletonBuffer< + Option< Arc<RwLock<dyn TreeNav + Send + Sync>> > + >, +} + +#[derive(Clone)] +pub struct EditTree { + /// context + pub ctx: Arc<RwLock<Context>>, + + /// viewports for terminal display + pub disp: EdittreeDisplay, + + /// editor & commander objects + pub ctrl: EdittreeControl +} + +impl EditTree { + pub fn new(ctx: Arc<RwLock<Context>>, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> Self { + EditTree { + disp: EdittreeDisplay { + view: ReprTree::new_arc(Context::parse(&ctx, "Display")), + diag: None, + depth, + }, + ctrl: EdittreeControl { + editor: SingletonBuffer::new(None), + spillbuf: Arc::new(RwLock::new(Vec::new())), + cmd: SingletonBuffer::new(None), + close_char: SingletonBuffer::new(None), + tree_nav: SingletonBuffer::new(None), + }, + ctx + } + } + + pub fn set_editor(mut self, editor: Arc<dyn Any + Send + Sync>) -> Self { + self.ctrl.editor.set(Some(editor)); + self + } + + pub fn set_cmd(mut self, cmd: Arc<RwLock<dyn ObjCommander + Send + Sync>>) -> Self { + self.ctrl.cmd.set(Some(cmd)); + self + } + + pub fn set_nav(mut self, nav: Arc<RwLock<dyn TreeNav + Send + Sync>>) -> Self { + self.ctrl.tree_nav.set(Some(nav)); + self + } + + pub fn set_diag(mut self, diag: OuterViewPort<dyn SequenceView<Item = Message>>) -> Self { + self.disp.diag = Some(diag); + self + } + + //\\//\\ + + pub fn get_diag(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { + self.disp.diag.clone().unwrap_or(ViewPort::new().into_outer()) + } + + pub fn get_edit<T: Send + Sync + 'static>(&self) -> Option<Arc<RwLock<T>>> { + if let Some(edit) = self.ctrl.editor.get() { + if let Ok(edit) = edit.downcast::<RwLock<T>>() { + Some(edit) + } else { + None + } + } else { + None + } + } +} + +/* +impl TreeType for NestedNode { + fn get_type(&self, addr: &TreeAddr) -> TypeLadder { + if let Some(editor) = self.editor { + editor.read().unwrap().get_type(addr) + } else { + vec![] + } + } +} +*/ + +impl TreeNav for EditTree { + fn get_cursor(&self) -> TreeCursor { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.read().unwrap().get_cursor() + } else { + TreeCursor::default() + } + } + + fn get_addr_view(&self) -> OuterViewPort<dyn SequenceView<Item = isize>> { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.read().unwrap().get_addr_view() + } else { + OuterViewPort::default() + } + } + + fn get_mode_view(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursorMode>> { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.read().unwrap().get_mode_view() + } else { + OuterViewPort::default() + } + } + + fn get_cursor_warp(&self) -> TreeCursor { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.read().unwrap().get_cursor_warp() + } else { + TreeCursor::default() + } + } + + fn get_height(&self, op: &TreeHeightOp) -> usize { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.read().unwrap().get_height( op ) + } else { + 0 + } + } + + fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.write().unwrap().goby(direction) + } else { + TreeNavResult::Exit + } + } + + fn goto(&mut self, new_cursor: TreeCursor) -> TreeNavResult { + if let Some(tn) = self.ctrl.tree_nav.get() { + tn.write().unwrap().goto(new_cursor) + } else { + TreeNavResult::Exit + } + } +} + +use crate::edit_tree::nav::TreeNavCmd; + +impl ObjCommander for EditTree { + fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { + + if cmd_obj.read().unwrap().get_type() == &Context::parse(&self.ctx, "TreeNavCmd") { + if let Some(cmd) = cmd_obj.read().unwrap().get_view::<dyn SingletonView<Item = TreeNavCmd>>() { + match cmd.get() { + TreeNavCmd::pxev => self.pxev(), + TreeNavCmd::nexd => self.nexd(), + TreeNavCmd::qpxev => self.qpxev(), + TreeNavCmd::qnexd => self.qnexd(), + + TreeNavCmd::up => self.up(), + TreeNavCmd::dn => self.dn(), + + _ => TreeNavResult::Continue + } + } else { + TreeNavResult::Exit + } + } else if let Some(cmd) = self.ctrl.cmd.get() { + // todo: filter out tree-nav cmds and send them to tree_nav + cmd.write().unwrap().send_cmd_obj(cmd_obj) + } else { + TreeNavResult::Exit + } + } +} + + +impl Diagnostics for EditTree { + fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { + self.get_diag() + } +} + diff --git a/nested/src/tree/treetype.rs b/lib-nested-core/src/edit_tree/treetype.rs similarity index 85% rename from nested/src/tree/treetype.rs rename to lib-nested-core/src/edit_tree/treetype.rs index 9f66849..c3ad118 100644 --- a/nested/src/tree/treetype.rs +++ b/lib-nested-core/src/edit_tree/treetype.rs @@ -2,7 +2,7 @@ use { laddertypes::{TypeTerm, TypeID}, crate::{ - tree::{TreeAddr} + edit_tree::{TreeAddr} } }; diff --git a/lib-nested-core/src/editors/char/mod.rs b/lib-nested-core/src/editors/char/mod.rs new file mode 100644 index 0000000..f9f97c0 --- /dev/null +++ b/lib-nested-core/src/editors/char/mod.rs @@ -0,0 +1,149 @@ +use { + r3vi::{ + view::{ + OuterViewPort, + singleton::*, + port::UpdateTask + }, + buffer::singleton::* + }, + laddertypes::{TypeTerm}, + crate::{ + repr_tree::{Context, ReprTree, ReprLeaf, ReprTreeExt, GenericReprTreeMorphism}, + edit_tree::{EditTree, TreeNavResult}, + editors::ObjCommander, + }, + std::sync::Arc, + std::sync::RwLock +}; + +pub fn init_ctx( ctx: Arc<RwLock<Context>> ) { + + let char_morph_to_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "Char"), + Context::parse(&ctx, "Char~EditTree"), + { + let ctx = ctx.clone(); + move |rt, σ| { + { + let mut b = rt.write().unwrap().singleton_buffer::<char>(); + if let Some(buf) = b { + // buffer already exists + } else { + // create char buffer + rt.write().unwrap().insert_leaf( + vec![].into_iter(), + ReprLeaf::from_singleton_buffer(SingletonBuffer::new('\0')) + ); + } + } + + let char_buf = rt.singleton_buffer::<char>(); + let mut edittree = CharEditor::new_edit_tree( + ctx.clone(), + char_buf, + SingletonBuffer::<usize>::new(0).get_port() + ); + + rt.insert_leaf( + Context::parse(&ctx, "EditTree"), + ReprLeaf::from_singleton_buffer( + SingletonBuffer::new( + Arc::new(RwLock::new(edittree)) + ) + ) + ); + + ctx.read().unwrap().setup_edittree(rt); + } + } + ); + + let char_morph_from_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "Char~EditTree"), + Context::parse(&ctx, "Char"), + { + let ctx = ctx.clone(); + move |rt, σ| + { + let mut b = rt + .descend(Context::parse(&ctx, "EditTree")).unwrap() + .view_singleton::<Arc<RwLock<EditTree>>>(); + + rt.attach_leaf_to( + Context::parse(&ctx, "Char"), + b.map(|x| + x.read().unwrap() + .get_edit::<CharEditor>().unwrap() + .read().unwrap() + .get()) + ); + } + }); + ctx.write().unwrap().morphisms.add_morphism( char_morph_to_edittree ); + ctx.write().unwrap().morphisms.add_morphism( char_morph_from_edittree ); +} + +pub struct CharEditor { + ctx: Arc<RwLock<Context>>, + data: SingletonBuffer<char> +} + +impl ObjCommander for CharEditor { + fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { + let cmd_obj = cmd_obj.read().unwrap(); + let cmd_type = cmd_obj.get_type().clone(); + + if cmd_type == Context::parse(&self.ctx, "Char") { + if let Some(cmd_view) = cmd_obj.get_view::<dyn SingletonView<Item = char>>() { + let value = cmd_view.get(); + + if self.ctx.read().unwrap().meta_chars.contains(&value) { + TreeNavResult::Exit + } else { + self.data.set(value); + TreeNavResult::Continue + } + } else { + TreeNavResult::Exit + } + } else { + TreeNavResult::Exit + } + } +} + +impl CharEditor { + pub fn new(ctx: Arc<RwLock<Context>>) -> Self { + CharEditor { + ctx, + data: SingletonBuffer::new('\0') + } + } + + pub fn get_port(&self) -> OuterViewPort<dyn SingletonView<Item = char>> { + self.data.get_port() + } + + pub fn get(&self) -> char { + self.get_port().get_view().unwrap().get() + } + + pub fn new_edit_tree( + ctx0: Arc<RwLock<Context>>, + data: SingletonBuffer<char>, + depth: OuterViewPort<dyn SingletonView<Item = usize>> + ) -> EditTree { + //let data = SingletonBuffer::new('\0'); + let ctx = ctx0.clone(); + let editor = Arc::new(RwLock::new(CharEditor{ ctx, data: data.clone() })); + + EditTree::new( + ctx0.clone(), + depth + ) + .set_cmd( editor.clone() ) + .set_editor( editor.clone() ) + } +} + diff --git a/lib-nested-core/src/editors/digit/cmd.rs b/lib-nested-core/src/editors/digit/cmd.rs new file mode 100644 index 0000000..ae56f9f --- /dev/null +++ b/lib-nested-core/src/editors/digit/cmd.rs @@ -0,0 +1,52 @@ + +use { + r3vi::view::singleton::SingletonView, + crate::{ + repr_tree::{ReprTree, Context}, + edit_tree::{TreeNav, TreeNavResult}, + editors::{ObjCommander, digit::DigitEditor} + }, + + std::sync::{Arc, RwLock} +}; + +impl ObjCommander for DigitEditor { + fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { + let cmd_obj = cmd_obj.read().unwrap(); + let cmd_type = cmd_obj.get_type().clone(); + + if cmd_type == Context::parse(&self.ctx, "Char") { + if let Some(cmd_view) = cmd_obj.get_view::<dyn SingletonView<Item = char>>() { + let c = cmd_view.get(); + + self.msg.clear(); + + if self.ctx.read().unwrap().meta_chars.contains(&c) { + return TreeNavResult::Exit; + + } else if c.to_digit(self.radix).is_none() { + /* in case the character c is not in the range of digit-chars, + add a message to the diagnostics view + */ +/* + let message = IndexBuffer::from_iter(vec![ + (Point2::new(1, 0), make_label("invalid digit '")), + (Point2::new(2, 0), make_label(&format!("{}", c)) + .map_item(|_p,a| a.add_style_back(TerminalStyle::fg_color((140,140,250))))), + (Point2::new(3, 0), make_label("'")) + ]); + + self.msg.push(crate::diagnostics::make_error(message.get_port().flatten())); +*/ + + self.data.set(c); + } else { + self.data.set(c); + } + } + } + + TreeNavResult::Continue + } +} + diff --git a/lib-nested-core/src/editors/digit/ctx.rs b/lib-nested-core/src/editors/digit/ctx.rs new file mode 100644 index 0000000..f78b962 --- /dev/null +++ b/lib-nested-core/src/editors/digit/ctx.rs @@ -0,0 +1,205 @@ + +use { + laddertypes::TypeTerm, + r3vi::{ + buffer::singleton::SingletonBuffer, + view::{ + AnyOuterViewPort, + singleton::* + } + }, + crate::{ + repr_tree::{Context, ReprTree, ReprTreeExt, ReprLeaf, GenericReprTreeMorphism}, + editors::digit::DigitEditor, + }, + std::sync::{Arc, RwLock} +}; + +pub fn init_ctx( ctx: Arc<RwLock<Context>> ) { + // todo: proper scoping of Radix variable + ctx.write().unwrap().add_varname("Radix"); + + let digit_make_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<Digit Radix>"), + Context::parse(&ctx, "<Digit Radix>~EditTree"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let radix = + match σ.get( &laddertypes::TypeID::Var(ctx.read().unwrap().get_var_typeid("Radix").unwrap()) ) { + Some(TypeTerm::Num(n)) => *n as u32, + _ => 0 + }; + + let char_buf = SingletonBuffer::<char>::new('?'); + + /* Create EditTree object + */ + let mut edittree = DigitEditor::new( + ctx.clone(), + radix, + char_buf + ).into_node( + r3vi::buffer::singleton::SingletonBuffer::<usize>::new(0).get_port() + ); + + src_rt.write().unwrap() + .insert_branch( + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "EditTree"), + SingletonBuffer::new(Arc::new(RwLock::new(edittree))) + ) + ); + + ctx.read().unwrap().setup_edittree( src_rt ); + } + } + ); + + let digit_morph_char_to_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<Digit Radix>~Char"), + Context::parse(&ctx, "<Digit Radix>~EditTree"), + + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let radix = + match σ.get( &laddertypes::TypeID::Var(ctx.read().unwrap().get_var_typeid("Radix").unwrap()) ) { + Some(TypeTerm::Num(n)) => *n as u32, + _ => 0 + }; + + /* Create EditTree object + */ + let mut edittree = DigitEditor::new( + ctx.clone(), + radix, + src_rt + .descend( Context::parse(&ctx, "Char") ).unwrap() + .singleton_buffer::<char>() + ).into_node( + r3vi::buffer::singleton::SingletonBuffer::<usize>::new(0).get_port() + ); + + src_rt.write().unwrap() + .insert_branch( + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "EditTree"), + SingletonBuffer::new(Arc::new(RwLock::new(edittree))) + ) + ); + + ctx.read().unwrap().setup_edittree( src_rt ); + } + } + ); + + let digit_morph_char_from_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<Digit Radix>~EditTree"), + Context::parse(&ctx, "<Digit Radix>~Char"), + + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let edittree = src_rt.edittree( &ctx ); + let port = + edittree + .get() + .read().unwrap() + .get_edit::<DigitEditor>().unwrap() + .read().unwrap() + .get_char_port(); + + src_rt.insert_leaf( + Context::parse(&ctx, "Char"), + ReprLeaf::from_view( port ) + ) + } + } + ); + + let digit_morph_char_to_u64 = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<Digit Radix>~Char"), + Context::parse(&ctx, "<Digit Radix>~ℤ_2^64~machine.UInt64"), + + { + let ctx = ctx.clone(); + move |rt: &mut Arc<RwLock<ReprTree>>, σ: &std::collections::HashMap<laddertypes::TypeID, TypeTerm>| { + /* infer radix from type + */ + let radix_typeid = ctx.read().unwrap().get_var_typeid("Radix").unwrap(); + let radix = + match σ.get( &laddertypes::TypeID::Var(radix_typeid) ) { + Some(TypeTerm::Num(n)) => (*n) as u32, + x => { + eprintln!("invalid radix {:?}", x); + 0 + } + }; + + if radix <= 16 { + if let Some(src_rt) = rt.descend(Context::parse(&ctx, "Char")) { + /* insert projected view into ReprTree + */ + let u64_view = + src_rt.view_char() + .map(move |c| c.to_digit(radix).unwrap_or(0) as u64); + + rt.write().unwrap().attach_leaf_to::<dyn SingletonView<Item = u64>>( + Context::parse(&ctx, "ℤ_2^64~machine.UInt64").get_lnf_vec().into_iter(), + u64_view + ); + } else { + eprintln!("could not find required source representation: <Digit {}>~Char", radix); + } + } else { + eprintln!("radix too large ({})", radix); + } + } + } + ); + + + let digit_morph_u64_to_char = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<Digit Radix>~ℤ_2^64~machine.UInt64"), + Context::parse(&ctx, "<Digit Radix>~Char"), + { + let ctx = ctx.clone(); + move |rt: &mut Arc<RwLock<ReprTree>>, σ: &std::collections::HashMap<laddertypes::TypeID, TypeTerm>| { + /* infer radix from type + */ + let radix = + match σ.get( &laddertypes::TypeID::Var(ctx.read().unwrap().get_var_typeid("Radix").unwrap()) ) { + Some(TypeTerm::Num(n)) => (*n) as u32, + _ => 0 + }; + + if radix <= 16 { + /* insert projected view into ReprTree + */ + let char_view = + rt.descend(Context::parse(&ctx, "ℤ_2^64~machine.UInt64")) + .unwrap() + .view_u64() + .map(move |digit| char::from_digit((digit%radix as u64) as u32, radix).unwrap_or('?')); + + rt.write().unwrap().attach_leaf_to::<dyn SingletonView<Item = char>>( + Context::parse(&ctx, "Char").get_lnf_vec().into_iter(), + char_view + ); + } else { + eprintln!("radix too large ({})", radix); + } + } + } + ); + + + ctx.write().unwrap().morphisms.add_morphism( digit_make_edittree ); + ctx.write().unwrap().morphisms.add_morphism( digit_morph_char_to_edittree ); + ctx.write().unwrap().morphisms.add_morphism( digit_morph_char_from_edittree ); + ctx.write().unwrap().morphisms.add_morphism( digit_morph_char_to_u64 ); + ctx.write().unwrap().morphisms.add_morphism( digit_morph_u64_to_char ); +} + + diff --git a/lib-nested-core/src/editors/digit/editor.rs b/lib-nested-core/src/editors/digit/editor.rs new file mode 100644 index 0000000..2f80d5d --- /dev/null +++ b/lib-nested-core/src/editors/digit/editor.rs @@ -0,0 +1,98 @@ + +use { + laddertypes::TypeTerm, + r3vi::{ + view::{OuterViewPort,singleton::*}, + buffer::{singleton::*, vec::*} + }, + crate::{ + repr_tree::{ReprTree, Context}, + edit_tree::{ + EditTree, + diagnostics::Message + } + }, + + std::sync::{Arc, RwLock} +}; + + +pub struct DigitEditor { + pub(super) ctx: Arc<RwLock<Context>>, + pub(super) radix: u32, + pub(super) data: SingletonBuffer<char>, + pub(super) msg: VecBuffer<Message>, +} + + +impl DigitEditor { + pub fn new(ctx: Arc<RwLock<Context>>, radix: u32, data: SingletonBuffer<char>) -> Self { + DigitEditor { + ctx, + radix, + data, + msg: VecBuffer::new(), + } + } + + pub fn into_node(self, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> EditTree { + // let data = self.get_data(); + let editor = Arc::new(RwLock::new(self)); + let ed = editor.write().unwrap(); + let r = ed.radix; + + EditTree::new(ed.ctx.clone(), depth) + .set_editor(editor.clone()) + .set_cmd(editor.clone()) + .set_diag( + ed.msg.get_port().to_sequence() + ) + } + + pub fn attach_to(&mut self, source: OuterViewPort<dyn SingletonView<Item = u32>>) { + /* + source.add_observer( + Arc::new(NotifyFnObserver::new(|_msg| { + self.data.set( source.get() ) + })) + ); + */ + } + + pub fn get_char_port(&self) -> OuterViewPort<dyn SingletonView<Item = char>> { + self.data.get_port() + } + + pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Result<u32, char>>> { + let radix = self.radix; + self.data.get_port().map(move |c| + if let Some(d) = c.to_digit(radix) { + Ok(d) + } else { + Err(c) + } + ) + } + + pub fn get_type(&self) -> TypeTerm { + TypeTerm::TypeID(self.ctx.read().unwrap().get_typeid("Digit").unwrap()) + } + + pub fn get_char(&self) -> char { + self.data.get() + } + +/* + pub fn get_data(&self) -> Arc<RwLock<ReprTree>> { + ReprTree::ascend( + &ReprTree::from_view( + self.ctx.read().unwrap().type_term_from_str("<Seq u32>").unwrap(), + self.get_data_port() + ), + self.get_type() + ) + } + */ +} + + diff --git a/lib-nested-core/src/editors/digit/mod.rs b/lib-nested-core/src/editors/digit/mod.rs new file mode 100644 index 0000000..980db26 --- /dev/null +++ b/lib-nested-core/src/editors/digit/mod.rs @@ -0,0 +1,8 @@ + +pub mod ctx; +pub mod cmd; +pub mod editor; + +pub use editor::DigitEditor; +pub use ctx::init_ctx; + diff --git a/nested/src/editors/integer/add.rs b/lib-nested-core/src/editors/integer/add.rs similarity index 100% rename from nested/src/editors/integer/add.rs rename to lib-nested-core/src/editors/integer/add.rs diff --git a/lib-nested-core/src/editors/integer/ctx.rs b/lib-nested-core/src/editors/integer/ctx.rs new file mode 100644 index 0000000..1165543 --- /dev/null +++ b/lib-nested-core/src/editors/integer/ctx.rs @@ -0,0 +1,302 @@ + +use { + r3vi::{ + view::{OuterViewPort, singleton::*, list::*}, + buffer::singleton::SingletonBuffer + }, + laddertypes::{TypeTerm, MorphismType}, + crate::{ + repr_tree::{ReprTree, ReprTreeExt, ReprLeaf, Context, GenericReprTreeMorphism}, + editors::{ + list::*, + integer::* + }, + }, + std::sync::{Arc, RwLock} +}; + +pub fn init_ctx(ctx: Arc<RwLock<Context>>) { + // TODO: proper scoping + ctx.write().unwrap().add_varname("SrcRadix"); + ctx.write().unwrap().add_varname("DstRadix"); + + + let posint_seq_morph_big_to_little = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> + ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + Context::parse(&ctx, "ℕ ~ <PosInt Radix LittleEndian> + ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let src_digits = src_rt + .descend(Context::parse(&ctx, " + <PosInt Radix BigEndian> + ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ") + .apply_substitution(&|k|σ.get(k).cloned()) + .clone() + ).expect("cant descend") + .view_seq::< u64 >(); + + src_rt.attach_leaf_to(Context::parse(&ctx, " + <PosInt Radix LittleEndian> + ~ <Seq <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ").apply_substitution(&|k|σ.get(k).cloned()).clone(), + src_digits.reverse() + ); + } + } + ); + + let posint_list_morph_big_to_little = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + Context::parse(&ctx, "ℕ ~ <PosInt Radix LittleEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let src_digits = src_rt + .descend(Context::parse(&ctx, " + <PosInt Radix BigEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ") + .apply_substitution(&|k|σ.get(k).cloned()) + .clone() + ).expect("cant descend") + .view_list::< u64 >(); + + src_rt.attach_leaf_to(Context::parse(&ctx, " + <PosInt Radix LittleEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ").apply_substitution(&|k|σ.get(k).cloned()).clone(), + src_digits.reverse() + ); + } + } + ); + + let posint_list_morph_little_to_big = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt Radix LittleEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 >"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let src_digits = src_rt + .descend(Context::parse(&ctx, " + <PosInt Radix LittleEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ") + .apply_substitution(&|k|σ.get(k).cloned()) + .clone() + ).expect("cant descend") + .view_list::< u64 >(); + + src_rt.attach_leaf_to(Context::parse(&ctx, " + <PosInt Radix BigEndian> + ~ <Seq~List <Digit Radix> ~ ℤ_2^64 ~ machine.UInt64 > + ").apply_substitution(&|k|σ.get(k).cloned()).clone(), + src_digits.reverse() + ); + } + } + ); + + + let posint_list_morph_radix = GenericReprTreeMorphism::new( + Context::parse(&ctx, " + ℕ + ~ <PosInt SrcRadix LittleEndian> + ~ <Seq <Digit SrcRadix>> + ~ <List <Digit SrcRadix> + ~ ℤ_2^64 + ~ machine.UInt64> + "), + Context::parse(&ctx, " + ℕ + ~ <PosInt DstRadix LittleEndian> + ~ <Seq <Digit DstRadix>> + ~ <List <Digit DstRadix> + ~ ℤ_2^64 + ~ machine.UInt64> + "), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let src_radix = match σ.get(&laddertypes::TypeID::Var( + ctx.read().unwrap().get_var_typeid("SrcRadix").unwrap() + )) { + Some(laddertypes::TypeTerm::Num(n)) => *n as u64, + _ => 0 + }; + + let dst_radix = match σ.get(&laddertypes::TypeID::Var( + ctx.read().unwrap().get_var_typeid("DstRadix").unwrap() + )) { + Some(laddertypes::TypeTerm::Num(n)) => *n as u64, + _ => 0 + }; + + let src_digits_rt = src_rt.descend(Context::parse(&ctx, " + <PosInt SrcRadix LittleEndian> + ~ <Seq <Digit SrcRadix>> + ~ <List <Digit SrcRadix> + ~ ℤ_2^64 + ~ machine.UInt64 > + ").apply_substitution(&|k|σ.get(k).cloned()).clone() + ).expect("cant descend repr tree"); + + let dst_digits_port = + src_digits_rt.view_list::<u64>() + .to_sequence() + .to_positional_uint( src_radix ) + .transform_radix( dst_radix ) + .to_list(); + + src_rt.attach_leaf_to( + Context::parse(&ctx, " + <PosInt DstRadix LittleEndian> + ~ <Seq <Digit DstRadix> > + ~ <List <Digit DstRadix> + ~ ℤ_2^64 + ~ machine.UInt64 > + ").apply_substitution(&|k|σ.get(k).cloned()).clone(), + dst_digits_port + ); + } + + } + ); + + let posint_list_morph_from_u64 = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ machine.UInt64"), + Context::parse(&ctx, "ℕ ~ <PosInt 0 LittleEndian> ~ <Seq~List <Digit 0>~ℤ_2^64~machine.UInt64>"), + { + let ctx = ctx.clone(); + move |rt, σ| { + let digits = rt + .descend(Context::parse(&ctx, "ℕ ~ machine.UInt64")).unwrap() + .view_u64() + .to_sequence() + .to_list(); + + rt.attach_leaf_to( + Context::parse(&ctx, "ℕ ~ <PosInt 0 LittleEndian> ~ <Seq~List <Digit 0>~ℤ_2^64~machine.UInt64>"), + digits + ); + } + } + ); + let posint_list_morph_to_u64 = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt 0 LittleEndian> ~ <Seq~List <Digit 0>~ℤ_2^64~machine.UInt64> ~ <Vec machine.UInt64>"), + Context::parse(&ctx, "ℕ ~ machine.UInt64"), + { + let ctx = ctx.clone(); + move |rt, σ| { + let u64_view = rt + .descend(Context::parse(&ctx, "ℕ ~ <PosInt 0 LittleEndian> ~ <Seq~List <Digit 0>~ℤ_2^64~machine.UInt64> ~ <Vec machine.UInt64>")).unwrap() + .get_port::< RwLock<Vec< u64 >> >().unwrap() + .to_singleton() + .map(|digits| { + digits.get(0).cloned().unwrap_or(0) + }); + + rt.attach_leaf_to( + Context::parse(&ctx, "ℕ ~ machine.UInt64"), + u64_view + ); + } + } + ); + + let posint_make_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> ~ <Seq~List <Digit Radix>> ~ EditTree"), + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> ~ EditTree"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let mut list_edittree = src_rt.descend( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> ~ <Seq~List <Digit Radix>>") + .apply_substitution(&|x| σ.get(x).cloned()).clone() + ) + .unwrap() + .edittree( &ctx ) + .get().clone() + .read().unwrap() + .clone(); + + // clear display + list_edittree.disp.view = ReprTree::new_arc(Context::parse(&ctx, "Display")); + + src_rt.insert_leaf( + Context::parse(&ctx, "<PosInt Radix BigEndian> ~ EditTree") + .apply_substitution(&|x| σ.get(x).cloned()).clone(), + ReprLeaf::from_singleton_buffer( + SingletonBuffer::new( + Arc::new(RwLock::new(list_edittree)) + ) + ) + ); + + ctx.read().unwrap().setup_edittree( + &src_rt.descend( + Context::parse(&ctx, "<PosInt Radix BigEndian>") + .apply_substitution(&|x| σ.get(x).cloned()).clone() + ).unwrap() + ); + } + } + ); + + let posint_edittree_to_list = GenericReprTreeMorphism::new( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> ~ EditTree"), + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian> ~ <Seq~List <Digit Radix>> ~ EditTree"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let mut list_edittree = src_rt.descend( + Context::parse(&ctx, "ℕ ~ <PosInt Radix BigEndian>") + .apply_substitution(&|x| σ.get(x).cloned()).clone()) + .unwrap() + .edittree( &ctx ) + .get().clone() + .read().unwrap() + .clone(); + + // clear display + list_edittree.disp.view = ReprTree::new_arc(Context::parse(&ctx, "Display")); + + src_rt.insert_leaf( + Context::parse(&ctx, "<PosInt Radix BigEndian> ~ <Seq~List <Digit Radix>>~EditTree") + .apply_substitution(&|x| σ.get(x).cloned()).clone(), + ReprLeaf::from_singleton_buffer( + SingletonBuffer::new( + Arc::new(RwLock::new(list_edittree)) + ) + ) + ); + + ctx.read().unwrap().setup_edittree( + &src_rt.descend( + Context::parse(&ctx, "<PosInt Radix BigEndian> ~ <Seq~List <Digit Radix>>") + .apply_substitution(&|x| σ.get(x).cloned()).clone() + ).unwrap() + ); + } + } + ); + + ctx.write().unwrap().morphisms.add_morphism( posint_make_edittree ); + ctx.write().unwrap().morphisms.add_morphism( posint_edittree_to_list ); + + ctx.write().unwrap().morphisms.add_morphism( posint_seq_morph_big_to_little ); + ctx.write().unwrap().morphisms.add_morphism( posint_list_morph_big_to_little ); + ctx.write().unwrap().morphisms.add_morphism( posint_list_morph_little_to_big ); + ctx.write().unwrap().morphisms.add_morphism( posint_list_morph_radix ); + ctx.write().unwrap().morphisms.add_morphism( posint_list_morph_from_u64 ); + ctx.write().unwrap().morphisms.add_morphism( posint_list_morph_to_u64 ); +} + diff --git a/lib-nested-core/src/editors/integer/editor.rs b/lib-nested-core/src/editors/integer/editor.rs new file mode 100644 index 0000000..4fdfe23 --- /dev/null +++ b/lib-nested-core/src/editors/integer/editor.rs @@ -0,0 +1,102 @@ +use { + r3vi::{ + view::{ + OuterViewPort, + singleton::*, + }, + buffer::{ + singleton::*, + vec::*, + index_hashmap::* + } + }, + laddertypes::{TypeTerm}, + crate::{ + editors::{ + digit::DigitEditor, + list::{ListCmd}, + ObjCommander + }, + repr_tree::{Context, ReprTree}, + edit_tree::{EditTree, TreeNav, TreeNavResult, TreeCursor, diagnostics::{Message}}, + }, + std::sync::Arc, + std::sync::RwLock, + std::iter::FromIterator, + cgmath::{Point2} +}; + +pub struct PosIntEditor { + radix: u32, + digits: EditTree, + + // todo: endianness +} + +impl PosIntEditor { + pub fn new(ctx: Arc<RwLock<Context>>, radix: u32) -> Self { + PosIntEditor { + radix, + digits: EditTree::new( + ctx, + r3vi::buffer::singleton::SingletonBuffer::new(0).get_port() + ) + } + } + + pub fn from_u64(ctx: Arc<RwLock<Context>>, radix: u32, value: u64) -> Self { + let mut edit = PosIntEditor::new(ctx, radix); + edit.set_value_u64( value ); + edit + } + + pub fn set_value_u64(&mut self, mut value: u64) { + self.digits.send_cmd_obj(ListCmd::Clear.into_repr_tree(&self.digits.ctx)); + + while value > 0 { + let digit_val = (value % self.radix as u64) as u32; + value /= self.radix as u64; + + // if BigEndian + self.digits.goto(TreeCursor::home()); + + self.digits.send_cmd_obj(ReprTree::from_char(&self.digits.ctx, char::from_digit(digit_val, self.radix).expect("invalid digit"))); + } + self.digits.goto(TreeCursor::none()); + } + + pub fn into_node(self) -> EditTree { + self.digits + } + +/* + pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = u32>> { + let radix = self.radix; + self.digits + .get_data_port() + .filter_map(move |digit_editor| { + digit_editor.read().unwrap().data.get()?.to_digit(radix) + }) + } + + pub fn get_value(&self) -> u32 { + let mut value = 0; + let mut weight = 1; + for digit_value in self + .get_data_port() + .get_view() + .unwrap() + .iter() + .collect::<Vec<_>>() + .into_iter() + .rev() + { + value += digit_value * weight; + weight *= self.radix; + } + + value +} +*/ +} + diff --git a/lib-nested-core/src/editors/integer/mod.rs b/lib-nested-core/src/editors/integer/mod.rs new file mode 100644 index 0000000..c0d59d4 --- /dev/null +++ b/lib-nested-core/src/editors/integer/mod.rs @@ -0,0 +1,150 @@ +pub mod add; +pub mod editor; +pub mod radix; +pub mod ctx; + +pub use { + add::Add, + editor::PosIntEditor, + radix::RadixProjection, + ctx::init_ctx +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +use { + r3vi::{ + view::{ + View, ViewPort, OuterViewPort, + Observer, + ObserverBroadcast, + sequence::* + } + }, + crate::{ + editors::integer::radix::{ + PosIntProjections + } + }, + std::sync::{Arc, RwLock} +}; + +pub trait PositionalUInt : SequenceView<Item = u64> { + fn get_radix(&self) -> u64; + fn get_value(&self) -> u64 { + let mut val = 0; + let mut r = 1; + for i in 0..self.len().unwrap_or(0) { + if let Some(digit_val) = self.get(&i) { + val += r * digit_val; + r *= self.get_radix(); + } + } + + val + } +} + +impl<V: PositionalUInt> PositionalUInt for RwLock<V> { + fn get_radix(&self) -> u64 { + self.read().unwrap().get_radix() + } +} + +struct PosUIntFromDigits { + radix: u64, + src_digits: Option<Arc<dyn SequenceView<Item = u64>>>, + cast: Arc<RwLock<ObserverBroadcast<dyn PositionalUInt>>> +} + +impl View for PosUIntFromDigits { + type Msg = usize; +} + +impl SequenceView for PosUIntFromDigits { + type Item = u64; + + fn get(&self, idx: &usize) -> Option<u64> { + self.src_digits.get(idx) + } + + fn len(&self) -> Option<usize> { + self.src_digits.len() + } +} + +impl PositionalUInt for PosUIntFromDigits { + fn get_radix(&self) -> u64 { + self.radix + } +} + +impl Observer<dyn SequenceView<Item = u64>> for PosUIntFromDigits { + fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = u64>>>) { + self.src_digits = new_src; +// self.cast.write().unwrap().notify(0); + } + + fn notify(&mut self, idx: &usize) { + self.cast.write().unwrap().notify(idx); + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub trait DigitSeqProjection { + fn to_positional_uint(&self, radix: u64) -> OuterViewPort<dyn PositionalUInt>; +} + +impl DigitSeqProjection for OuterViewPort<dyn SequenceView<Item = u64>> { + fn to_positional_uint(&self, radix: u64) -> OuterViewPort<dyn PositionalUInt> { + let port = ViewPort::new(); + port.add_update_hook(Arc::new(self.0.clone())); + + let proj = Arc::new(RwLock::new(PosUIntFromDigits { + radix, + src_digits: None, + cast: port.inner().get_broadcast() + })); + + self.add_observer(proj.clone()); + port.set_view(Some(proj)); + port.into_outer() + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +struct PosUIntToDigits { + src: Option<Arc<dyn PositionalUInt>>, + cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = u64>>>> +} + +impl View for PosUIntToDigits { + type Msg = usize; +} + +impl SequenceView for PosUIntToDigits { + type Item = u64; + + fn get(&self, idx: &usize) -> Option<u64> { + self.src.get(idx) + } + + fn len(&self) -> Option<usize> { + self.src.len() + } +} + +impl Observer<dyn PositionalUInt> for PosUIntToDigits { + fn reset(&mut self, view: Option<Arc<dyn PositionalUInt>>) { + self.src = view; +// self.cast.notify_all(); + } + + fn notify(&mut self, idx: &usize) { + self.cast.notify(idx); + } +} + + diff --git a/lib-nested-core/src/editors/integer/radix.rs b/lib-nested-core/src/editors/integer/radix.rs new file mode 100644 index 0000000..685452b --- /dev/null +++ b/lib-nested-core/src/editors/integer/radix.rs @@ -0,0 +1,152 @@ +use { + r3vi::{ + view::{ + View, ViewPort, + InnerViewPort, Observer, OuterViewPort, + ObserverBroadcast, + sequence::*, + list::* + }, + buffer::{vec::*} + }, + crate::{ + editors::integer::{ + PositionalUInt + }, + repr_tree::{ReprTree, ReprLeaf} + }, + std::sync::{Arc, RwLock}, +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub trait PosIntProjections { + fn transform_radix(&self, dst_radix: u64) -> OuterViewPort<dyn SequenceView<Item = u64>>; +// fn to_digits(&self) -> OuterViewPort<dyn SequenceView<Item = usize>>; +} + +impl PosIntProjections for OuterViewPort<dyn PositionalUInt> { + fn transform_radix(&self, dst_radix: u64) -> OuterViewPort<dyn SequenceView<Item = u64>> { + let port = ViewPort::<dyn SequenceView<Item = u64>>::new(); + port.add_update_hook(Arc::new(self.0.clone())); + +// let mut vec_port = ViewPort::new(); + let proj = Arc::new(RwLock::new(RadixProjection { + src: None, + dst_radix, + dst_digits: VecBuffer::new(), + cast: port.inner().get_broadcast() + })); + + self.add_observer(proj.clone()); + port.set_view(Some(proj as Arc<dyn SequenceView<Item = u64>>)); + port.into_outer() + } +/* + fn to_digits(&self) -> OuterViewPort<dyn SequenceView<Item = usize>> { + let port = ViewPort::new(); + port.add_update_hook(Arc::new(self.0.clone())); + let proj = Arc::new(RwLock::new(PosUIntToDigits { + src: None, + cast: port.inner().get_broadcast() + })); + self.add_observer(proj.clone()); + port.inner().set_view(Some(proj)); + port.into_outer() + } + */ +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub struct RadixProjection { + src: Option<Arc<dyn PositionalUInt>>, + dst_radix: u64, + dst_digits: VecBuffer<u64>, + cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = u64>>>> +} + +impl View for RadixProjection { + type Msg = usize; +} + +impl SequenceView for RadixProjection { + type Item = u64; + + fn get(&self, idx: &usize) -> Option<u64> { + if *idx < self.dst_digits.len() { + Some(self.dst_digits.get(*idx)) + } else { + None + } + } + + fn len(&self) -> Option<usize> { + Some(self.dst_digits.len()) + } +} + +impl PositionalUInt for RadixProjection { + fn get_radix(&self) -> u64 { + self.dst_radix + } +} + +impl Observer< dyn PositionalUInt > for RadixProjection { + fn reset(&mut self, view: Option<Arc<dyn PositionalUInt>>) { + self.src = view; + self.update(); + } + + fn notify(&mut self, idx: &usize) { + self.update(); + // self.update_digit(idx) + } +} + +impl RadixProjection { + /// recalculate everything + fn update(&mut self) { +// let mut dst = self.dst_digits; + let old_len = self.dst_digits.len(); + self.dst_digits.clear(); + + if let Some(src) = self.src.as_ref() { + let mut val = src.get_value(); + if val == 0 { + self.dst_digits.push(0); + } else { + if self.dst_radix == 0 { + self.dst_digits.push(val); + } else { + while val > 0 { + self.dst_digits.push(val % self.dst_radix); + val /= self.dst_radix; + } + } + } + } + + let new_len = self.dst_digits.len(); + for i in 0 .. usize::max(old_len, new_len) { + self.cast.write().unwrap().notify(&i); + } + } + + fn _update_dst_digit(&mut self, _idx: usize) { + /* + let v = 0; // calculate new digit value + + // which src-digits are responsible? + + if idx < self.dst_digits.len() { + self.dst_digits.get_mut(idx) = v; + } else if idx == self.dst_digits.len() { + self.dst_digits.push(v); + } else { + // error + } + */ + } +} + diff --git a/nested/src/editors/list/cmd.rs b/lib-nested-core/src/editors/list/cmd.rs similarity index 89% rename from nested/src/editors/list/cmd.rs rename to lib-nested-core/src/editors/list/cmd.rs index 74c7fee..bbdd19c 100644 --- a/nested/src/editors/list/cmd.rs +++ b/lib-nested-core/src/editors/list/cmd.rs @@ -3,10 +3,9 @@ use { view::{singleton::*} }, crate::{ - editors::list::{ListEditor, ListCursor, ListCursorMode}, - type_system::{Context, ReprTree}, - tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, - commander::{ObjCommander} + editors::{list::{ListEditor, ListCursor, ListCursorMode}, ObjCommander}, + repr_tree::{Context, ReprTree}, + edit_tree::{EditTree, TreeNav, TreeNavResult, TreeCursor}, }, std::sync::{Arc, RwLock} }; @@ -23,11 +22,11 @@ pub enum ListCmd { } impl ListCmd { + // note: cant use Into becaue of ctx (maybe global typedict?) pub fn into_repr_tree(self, ctx: &Arc<RwLock<Context>>) -> Arc<RwLock<ReprTree>> { - let buf = r3vi::buffer::singleton::SingletonBuffer::new(self); - ReprTree::new_leaf( - Context::parse(ctx, "ListCmd"), - buf.get_port().into() + ReprTree::from_singleton_buffer( + Context::parse(ctx, "ListCmd"), + r3vi::buffer::singleton::SingletonBuffer::new(self) ) } } @@ -36,7 +35,7 @@ impl ObjCommander for ListEditor { fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { let cmd_repr = cmd_obj.read().unwrap(); - if let Some(view) = cmd_repr.get_view::<dyn SingletonView<Item = NestedNode>>() { + if let Some(view) = cmd_repr.get_view::<dyn SingletonView<Item = EditTree>>() { let node = view.get(); let cur = self.cursor.get(); @@ -58,7 +57,6 @@ impl ObjCommander for ListEditor { } else if let Some(cmd) = cmd_repr.get_view::<dyn SingletonView<Item = ListCmd>>() { - eprintln!("pty-list-editor some list cmmd"); let cur = self.cursor.get(); drop(cmd_repr); @@ -77,7 +75,6 @@ impl ObjCommander for ListEditor { match cmd.get() { ListCmd::DeletePxev => { - eprintln!("SELECT: delete pxev"); if idx > 0 && item_cur.tree_addr.iter().fold( true, @@ -119,7 +116,6 @@ impl ObjCommander for ListEditor { } } } else { - eprintln!("ptylist: no item"); TreeNavResult::Exit } }, @@ -127,7 +123,6 @@ impl ObjCommander for ListEditor { ListCursorMode::Insert => { match cmd.get() { ListCmd::DeletePxev => { - eprintln!("INSERT: delete pxev"); self.delete_pxev(); TreeNavResult::Continue } @@ -150,7 +145,6 @@ impl ObjCommander for ListEditor { } } } else { - eprintln!("ptylist: cursor has no idx"); TreeNavResult::Exit } } diff --git a/lib-nested-core/src/editors/list/ctx.rs b/lib-nested-core/src/editors/list/ctx.rs new file mode 100644 index 0000000..0d38e7a --- /dev/null +++ b/lib-nested-core/src/editors/list/ctx.rs @@ -0,0 +1,135 @@ +use { + r3vi::{ + view::{ + ViewPort, port::UpdateTask, + OuterViewPort, Observer, + singleton::*, + list::* + }, + buffer::{singleton::*, vec::*} + }, + laddertypes::{TypeTerm}, + crate::{ + repr_tree::{Context, ReprTree, ReprLeaf, ReprTreeExt, GenericReprTreeMorphism}, + edit_tree::{EditTree}, + editors::{ + char::{CharEditor}, + list::{ListEditor} + } + }, + std::sync::{Arc, RwLock} +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub fn init_ctx(ctx: Arc<RwLock<Context>>) { + ctx.write().unwrap().add_varname("Item"); + + let list_morph_editsetup1 = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<List Item>~<List EditTree>~<Vec EditTree>"), + Context::parse(&ctx, "<List Item>~EditTree"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let item_id = laddertypes::TypeID::Var( ctx.read().unwrap().get_var_typeid("Item").unwrap() ); + if let Some( item_type ) = σ.get( &item_id ) { + let mut item_vec_rt = src_rt + .descend( + Context::parse(&ctx, "<List Item~EditTree>~<Vec EditTree>") + .apply_substitution(&|id| σ.get(id).cloned()).clone() + ) + .expect("cant descend src repr"); + + let item_vec_buffer = item_vec_rt.vec_buffer::< Arc<RwLock<EditTree>> >(); + + let mut list_editor = ListEditor::with_data(ctx.clone(), item_type.clone(), item_vec_buffer); + let edittree_list = list_editor.into_node( + SingletonBuffer::<usize>::new(0).get_port() + ); + src_rt.insert_leaf( + Context::parse(&ctx, "<List Item> ~ EditTree") + .apply_substitution(&|id| σ.get(id).cloned()).clone(), + + ReprLeaf::from_singleton_buffer( + SingletonBuffer::new(Arc::new(RwLock::new(edittree_list))) + ) + ); + + ctx.read().unwrap().setup_edittree( &src_rt ); + } else { + eprintln!("no item type"); + } + } + } + ); + + let list_morph_editsetup3 = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<List Item> ~ EditTree"), + Context::parse(&ctx, "<List Item> ~ <List EditTree>"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let edittree = src_rt.edittree( &ctx ); + let list_edit = edittree.get().read().unwrap().get_edit::< ListEditor >().unwrap(); + let edittree_items = list_edit.read().unwrap().data.get_port().to_list(); + + eprintln!("edittree_items.len() = {:?}", edittree_items.get_view().unwrap().len()); + + src_rt.attach_leaf_to( + Context::parse(&ctx, "<List Item> ~ <List EditTree>") + .apply_substitution(&|x| σ.get(x).cloned()).clone(), + edittree_items + ); + } + } + ); + + let list_morph_to_vec_char = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<List Char>"), + Context::parse(&ctx, "<List Char>~<Vec Char>"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + src_rt.attach_leaf_to( + Context::parse(&ctx, "<Vec Char>"), + src_rt.view_list::<char>() + ); + } + } + ); + + let list_morph_from_vec_char = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<List Char>~<Vec Char>"), + Context::parse(&ctx, "<List Char>"), + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let src_port = src_rt.descend(Context::parse(&ctx, "<List Char>~<Vec Char>")).expect("descend") + .get_port::<RwLock<Vec<char>>>().unwrap(); + + src_rt.attach_leaf_to( Context::parse(&ctx, "<List Char>"), src_port.to_list() ); + } + } + ); + + + let list_morph_to_vec_edittree = GenericReprTreeMorphism::new( + Context::parse(&ctx, "<List EditTree>"), + Context::parse(&ctx, "<List EditTree> ~ <Vec EditTree>"), + + { + let ctx = ctx.clone(); + move |src_rt, σ| { + let list_port = src_rt.get_port::<dyn ListView< Arc<RwLock<EditTree>> >>().unwrap(); + src_rt.attach_leaf_to( Context::parse(&ctx, "<Vec EditTree>"), list_port ); + } + } + ); + + ctx.write().unwrap().morphisms.add_morphism( list_morph_editsetup1 ); + ctx.write().unwrap().morphisms.add_morphism( list_morph_editsetup3 ); + ctx.write().unwrap().morphisms.add_morphism( list_morph_from_vec_char ); + ctx.write().unwrap().morphisms.add_morphism( list_morph_to_vec_char ); + ctx.write().unwrap().morphisms.add_morphism( list_morph_to_vec_edittree ); +} + diff --git a/nested/src/editors/list/cursor.rs b/lib-nested-core/src/editors/list/cursor.rs similarity index 100% rename from nested/src/editors/list/cursor.rs rename to lib-nested-core/src/editors/list/cursor.rs diff --git a/nested/src/editors/list/editor.rs b/lib-nested-core/src/editors/list/editor.rs similarity index 80% rename from nested/src/editors/list/editor.rs rename to lib-nested-core/src/editors/list/editor.rs index 31c1f1b..6773891 100644 --- a/nested/src/editors/list/editor.rs +++ b/lib-nested-core/src/editors/list/editor.rs @@ -1,15 +1,14 @@ use { r3vi::{ - view::{ViewPort, OuterViewPort, singleton::*, sequence::*}, - buffer::{singleton::*, vec::*} + view::{OuterViewPort, singleton::*, sequence::*}, + buffer::{singleton::*, vec::*}, + projection::* }, laddertypes::{TypeTerm}, crate::{ - type_system::{Context, ReprTree}, - editors::list::{ListCursor, ListCursorMode, ListCmd}, - tree::{NestedNode, TreeNav, TreeCursor}, - diagnostics::Diagnostics, - commander::ObjCommander + repr_tree::{Context, ReprTree}, + edit_tree::{EditTree, TreeNav, TreeCursor, diagnostics::Diagnostics}, + editors::{list::{ListCursor, ListCursorMode, ListCmd}, ObjCommander}, }, std::sync::{Arc, RwLock} }; @@ -17,31 +16,42 @@ use { //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> pub struct ListEditor { - pub(super) cursor: SingletonBuffer<ListCursor>, + pub cursor: SingletonBuffer<ListCursor>, // todo: (?) remove RwLock<..> around NestedNode ?? - pub data: VecBuffer< Arc<RwLock<NestedNode>> >, + pub data: VecBuffer< Arc<RwLock<EditTree>> >, - pub spillbuf: Arc<RwLock<Vec<Arc<RwLock<NestedNode>>>>>, + pub spillbuf: Arc<RwLock<Vec<Arc<RwLock<EditTree>>>>>, pub(super) addr_port: OuterViewPort<dyn SequenceView<Item = isize>>, pub(super) mode_port: OuterViewPort<dyn SingletonView<Item = ListCursorMode>>, depth: OuterViewPort<dyn SingletonView<Item = usize>>, - pub(crate) ctx: Arc<RwLock<Context>>, + pub ctx: Arc<RwLock<Context>>, /// item type - pub(super) typ: TypeTerm, + pub typ: TypeTerm, } impl ListEditor { pub fn new( + ctx: Arc<RwLock<Context>>, + typ: TypeTerm + ) -> Self { + Self::with_data( + ctx, + typ, + VecBuffer::new() + ) + } + + pub fn with_data( ctx: Arc<RwLock<Context>>, typ: TypeTerm, + data: VecBuffer<Arc<RwLock<EditTree>>> ) -> Self { let cursor = SingletonBuffer::new(ListCursor::default()); - let data : VecBuffer<Arc<RwLock<NestedNode>>> = VecBuffer::new(); ListEditor { mode_port: cursor @@ -57,7 +67,6 @@ impl ListEditor { if idx >= 0 && idx < data.len() as isize { data.get(idx as usize).read().unwrap().get_mode_view() } else { - eprintln!("ListEditor::mode_port invalid cursor idx"); ip } } else { @@ -103,8 +112,7 @@ impl ListEditor { } } - pub fn into_node(mut self, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> NestedNode { - let data = self.get_data(); + pub fn into_node(mut self, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> EditTree { let ctx = self.ctx.clone(); self.depth = depth.clone(); @@ -112,31 +120,24 @@ impl ListEditor { let e = editor.read().unwrap(); - let mut node = NestedNode::new(ctx, data, depth) + let mut node = EditTree::new(ctx, depth) .set_editor(editor.clone()) .set_nav(editor.clone()) .set_cmd(editor.clone()) - .set_diag(e - .get_data_port() + .set_diag(e.get_data_port() .enumerate() - .map( - |(idx, item_editor)| { - let idx = *idx; - item_editor - .get_msg_port() - .map( - move |msg| { - let mut msg = msg.clone(); - msg.addr.insert(0, idx); - msg - } - ) - } - ) - .flatten() - ); + .map(|(idx, item_editor)| { + let idx = *idx; + item_editor.get_msg_port() + .map(move |msg| { + let mut msg = msg.clone(); + msg.addr.insert(0, idx); + msg + }) + }) + .flatten()); - node.spillbuf = e.spillbuf.clone(); + node.ctrl.spillbuf = e.spillbuf.clone(); node } @@ -155,12 +156,12 @@ impl ListEditor { self.cursor.get_port() } - pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> { - self.data.get_port().to_sequence().map( + pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = EditTree>> { + self.data.get_port().to_list().map( |x| x.read().unwrap().clone() - ) + ).to_sequence() } - +/* pub fn get_data(&self) -> Arc<RwLock<ReprTree>> { let data_view = self.get_data_port(); ReprTree::new_leaf( @@ -168,8 +169,8 @@ impl ListEditor { data_view.into() ) } - - pub fn get_item(&self) -> Option<NestedNode> { +*/ + pub fn get_item(&self) -> Option<EditTree> { if let Some(idx) = self.cursor.get().idx { let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize; if idx < self.data.len() { @@ -182,7 +183,7 @@ impl ListEditor { } } - pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<Arc<RwLock<NestedNode>>>> { + pub fn get_item_mut(&mut self) -> Option<MutableVecAccess<Arc<RwLock<EditTree>>>> { if let Some(idx) = self.cursor.get().idx { let idx = crate::utils::modulo(idx as isize, self.data.len() as isize) as usize; if idx < self.data.len() { @@ -233,10 +234,8 @@ impl ListEditor { } /// insert a new element - pub fn insert(&mut self, item: Arc<RwLock<NestedNode>>) { - eprintln!("list insert"); - - item.read().unwrap().depth.0.set_view( + pub fn insert(&mut self, item: Arc<RwLock<EditTree>>) { + item.read().unwrap().disp.depth.0.set_view( self.depth.map(|d| d+1).get_view() ); @@ -248,7 +247,6 @@ impl ListEditor { if self.is_listlist() { cur.mode = ListCursorMode::Select; } else { - eprintln!("list insert: is not a listlist ({:?})", self.typ); item.write().unwrap().goto(TreeCursor::none()); cur.idx = Some(idx + 1); } @@ -264,13 +262,11 @@ impl ListEditor { self.cursor.set(cur); } else { - //eprintln!("insert: no cursor"); } } /// split the list off at the current cursor position and return the second half pub fn split(&mut self) { - eprintln!("split"); let cur = self.cursor.get(); if let Some(idx) = cur.idx { let idx = idx as usize; @@ -305,7 +301,6 @@ impl ListEditor { } pub fn listlist_split(&mut self) { - eprintln!("listlist split"); let cur = self.get_cursor(); if let Some(mut item) = self.get_item().clone() { @@ -317,22 +312,29 @@ impl ListEditor { self.set_leaf_mode(ListCursorMode::Insert); self.nexd(); - let mut b = item.spillbuf.write().unwrap(); - let mut tail_node = Context::make_node(&self.ctx, self.typ.clone(), self.depth.map(|d| d+1)).unwrap(); + let mut b = item.ctrl.spillbuf.write().unwrap(); + + let rt = ReprTree::new_arc(self.typ.clone()); + let mut et = self.ctx.read().unwrap().setup_edittree(&rt); + + if let Some(edittree) = et.as_mut(){ + + let mut tail_node = edittree.get(); + let mut tail_node = tail_node.write().unwrap(); tail_node.goto(TreeCursor::home()); for node in b.iter() { - eprintln!("splid :send to tail node"); tail_node .send_cmd_obj( - ReprTree::new_leaf( - Context::parse(&self.ctx, "NestedNode"), - SingletonBuffer::<NestedNode>::new( + ReprTree::from_singleton_buffer( + Context::parse(&self.ctx, "EditTree"), + SingletonBuffer::<EditTree>::new( node.read().unwrap().clone() - ).get_port().into() + ) ) ); } + b.clear(); drop(b); drop(item); @@ -341,11 +343,14 @@ impl ListEditor { if cur.tree_addr.len() > 1 { tail_node.dn(); } + drop(tail_node); self.insert( - Arc::new(RwLock::new(tail_node)) + edittree.value.read().unwrap().clone() ); + } + } else { self.up(); self.listlist_split(); @@ -376,14 +381,14 @@ impl ListEditor { let old_cur = pxv_editor.get_cursor(); - let data = cur_editor.spillbuf.read().unwrap(); + let data = cur_editor.ctrl.spillbuf.read().unwrap(); for x in data.iter() { pxv_editor.send_cmd_obj( - ReprTree::new_leaf( - Context::parse(&self.ctx, "NestedNode"), - SingletonBuffer::<NestedNode>::new( + ReprTree::from_singleton_buffer( + Context::parse(&self.ctx, "EditTree"), + SingletonBuffer::<EditTree>::new( x.read().unwrap().clone() - ).get_port().into() + ) ) ); } @@ -434,15 +439,15 @@ impl ListEditor { leaf_mode: ListCursorMode::Insert }); - let data = nxd_editor.spillbuf.read().unwrap(); + let data = nxd_editor.ctrl.spillbuf.read().unwrap(); for x in data.iter() { cur_editor.send_cmd_obj( - ReprTree::new_leaf( - Context::parse(&self.ctx, "NestedNode"), - SingletonBuffer::<NestedNode>::new( + ReprTree::from_singleton_buffer( + Context::parse(&self.ctx, "EditTree"), + SingletonBuffer::<EditTree>::new( x.read().unwrap().clone() - ).get_port().into() + ) ) ); } diff --git a/nested/src/editors/list/mod.rs b/lib-nested-core/src/editors/list/mod.rs similarity index 77% rename from nested/src/editors/list/mod.rs rename to lib-nested-core/src/editors/list/mod.rs index c929369..b788aae 100644 --- a/nested/src/editors/list/mod.rs +++ b/lib-nested-core/src/editors/list/mod.rs @@ -1,10 +1,8 @@ - pub mod cursor; pub mod editor; pub mod nav; pub mod segment; -pub mod pty_editor; pub mod cmd; pub mod ctx; @@ -12,7 +10,6 @@ pub use { cursor::{ListCursor, ListCursorMode}, editor::ListEditor, segment::{ListSegment, ListSegmentSequence}, - pty_editor::{PTYListStyle, PTYListController}, cmd::ListCmd, ctx::init_ctx }; diff --git a/nested/src/editors/list/nav.rs b/lib-nested-core/src/editors/list/nav.rs similarity index 96% rename from nested/src/editors/list/nav.rs rename to lib-nested-core/src/editors/list/nav.rs index 31d0cc2..b92cc8f 100644 --- a/nested/src/editors/list/nav.rs +++ b/lib-nested-core/src/editors/list/nav.rs @@ -11,7 +11,7 @@ use { ListCursor, ListCursorMode, editor::ListEditor }, - tree::{TreeCursor, TreeNav, TreeNavResult, TreeHeightOp} + edit_tree::{TreeCursor, TreeNav, TreeNavResult, TreeHeightOp} }, cgmath::Vector2 }; @@ -195,7 +195,6 @@ impl TreeNav for ListEditor { TreeNavResult::Exit } else if direction.y > 0 { // dn - eprintln!("dn: data.len() = {}", self.data.len()); self.cursor.set(ListCursor { mode: if self.data.len() > 0 { cur.leaf_mode } else { ListCursorMode::Insert }, idx: Some(0) @@ -367,7 +366,6 @@ impl TreeNav for ListEditor { depth as isize - 1 }; - eprintln!("<- LEFT CROSS: pxv_height = {}, cur_height = {}, dist_from_ground = {}, n_steps_down = {}", pxv_height, cur_height, dist_from_ground, n_steps_down); new_addr.push( cur.tree_addr[0] - 1 ); for _i in 0..n_steps_down { new_addr.push( -1 ); @@ -387,7 +385,6 @@ impl TreeNav for ListEditor { depth as isize - 1 }; - eprintln!("-> RIGHT CROSS: cur_height = {}, nxd_height = {}, dist_from_ground = {}, n_steps_down = {}", cur_height, nxd_height, dist_from_ground, n_steps_down); new_addr.push( cur.tree_addr[0] + 1 ); for _i in 0..n_steps_down { new_addr.push( 0 ); @@ -396,7 +393,6 @@ impl TreeNav for ListEditor { drop(cur_item); - eprintln!("CROSS: goto {:?}", new_addr); cur.tree_addr = new_addr; self.goto(cur) } else { diff --git a/nested/src/editors/list/segment.rs b/lib-nested-core/src/editors/list/segment.rs similarity index 70% rename from nested/src/editors/list/segment.rs rename to lib-nested-core/src/editors/list/segment.rs index 4ae0368..4cd495b 100644 --- a/nested/src/editors/list/segment.rs +++ b/lib-nested-core/src/editors/list/segment.rs @@ -9,10 +9,7 @@ use { }, crate::{ editors::list::{ListCursor, ListCursorMode}, - terminal::{TerminalView, TerminalStyle, make_label}, - tree::{NestedNode, TreeNav}, - utils::color::{bg_style_from_depth, fg_style_from_depth}, - PtySegment + edit_tree::{EditTree} }, std::sync::Arc, std::sync::RwLock, @@ -21,46 +18,13 @@ use { pub enum ListSegment { InsertCursor, Item { - editor: NestedNode, + editor: EditTree, cur_dist: isize, } } -impl PtySegment for ListSegment { - fn pty_view(&self) -> OuterViewPort<dyn TerminalView> { - match self { - ListSegment::InsertCursor => { - make_label("|") - .map_item(move |_pt, atom| { - atom.add_style_front(TerminalStyle::fg_color((150,80,230))) - .add_style_front(TerminalStyle::bold(true)) - }) - } - ListSegment::Item{ editor, cur_dist } => { - let e = editor.clone(); - let cur_dist = *cur_dist; - editor.get_view().map_item(move |_pt, atom| { - let c = e.get_cursor(); - let cur_depth = c.tree_addr.len(); - let select = - if cur_dist == 0 { - cur_depth - } else { - usize::MAX - }; - - atom - .add_style_back(bg_style_from_depth(select)) - .add_style_back(TerminalStyle::bold(select==1)) - .add_style_back(fg_style_from_depth(e.depth.get_view().get())) - }) - } - } - } -} - pub struct ListSegmentSequence { - data: Arc<dyn SequenceView<Item = NestedNode>>, + data: Arc<dyn SequenceView<Item = EditTree>>, cursor: Arc<dyn SingletonView<Item = ListCursor>>, cur_cursor: ListCursor, @@ -78,11 +42,12 @@ impl SequenceView for ListSegmentSequence { type Item = ListSegment; fn len(&self) -> Option<usize> { + let l = self.data.len()?; match self.cur_cursor.mode { ListCursorMode::Insert => { - Some(self.data.len()? + if self.cur_cursor.idx.is_some() { 1 } else { 0 }) + Some(l + if self.cur_cursor.idx.is_some() { 1 } else { 0 }) } - _ => self.data.len(), + _ => Some(l), } } @@ -124,7 +89,7 @@ impl SequenceView for ListSegmentSequence { impl ListSegmentSequence { pub fn new( cursor_port: OuterViewPort<dyn SingletonView<Item = ListCursor>>, - data_port: OuterViewPort<dyn SequenceView<Item = NestedNode>>, + data_port: OuterViewPort<dyn SequenceView<Item = EditTree>>, ) -> Arc<RwLock<Self>> { let out_port = ViewPort::new(); let mut proj_helper = ProjectionHelper::new(out_port.update_hooks.clone()); diff --git a/nested/src/commander.rs b/lib-nested-core/src/editors/mod.rs similarity index 57% rename from nested/src/commander.rs rename to lib-nested-core/src/editors/mod.rs index fdbeaee..4de5274 100644 --- a/nested/src/commander.rs +++ b/lib-nested-core/src/editors/mod.rs @@ -1,4 +1,14 @@ +pub mod list; +//pub mod product; +//pub mod sum; + +pub mod char; +pub mod digit; +pub mod integer; +//pub mod typeterm; + + pub trait Commander { type Cmd; @@ -7,11 +17,12 @@ pub trait Commander { use std::sync::{Arc, RwLock}; use crate::{ - type_system::ReprTree, - tree::{nav::TreeNavResult} + repr_tree::ReprTree, + edit_tree::nav::TreeNavResult }; pub trait ObjCommander { fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult; } + diff --git a/nested/src/editors/product/editor.rs b/lib-nested-core/src/editors/product/editor.rs similarity index 98% rename from nested/src/editors/product/editor.rs rename to lib-nested-core/src/editors/product/editor.rs index d3bdd9a..80acc24 100644 --- a/nested/src/editors/product/editor.rs +++ b/lib-nested-core/src/editors/product/editor.rs @@ -12,10 +12,6 @@ use { laddertypes::{TypeTerm}, crate::{ type_system::{Context}, - terminal::{ - TerminalEditor, TerminalEditorResult, - TerminalEvent, TerminalView - }, editors::{ list::ListCursorMode, product::{ diff --git a/nested/src/editors/product/mod.rs b/lib-nested-core/src/editors/product/mod.rs similarity index 100% rename from nested/src/editors/product/mod.rs rename to lib-nested-core/src/editors/product/mod.rs diff --git a/nested/src/editors/product/nav.rs b/lib-nested-core/src/editors/product/nav.rs similarity index 100% rename from nested/src/editors/product/nav.rs rename to lib-nested-core/src/editors/product/nav.rs diff --git a/nested/src/editors/product/segment.rs b/lib-nested-core/src/editors/product/segment.rs similarity index 96% rename from nested/src/editors/product/segment.rs rename to lib-nested-core/src/editors/product/segment.rs index 0b223f5..a9c9318 100644 --- a/nested/src/editors/product/segment.rs +++ b/lib-nested-core/src/editors/product/segment.rs @@ -19,7 +19,10 @@ use { #[derive(Clone)] pub enum ProductEditorSegment { + /// Terminal Node, i.e. literal, immutable string T( String, usize ), + + /// Nonterminal Node, i.e. sub-editor for type t N { t: TypeTerm, editor: Option<NestedNode>, diff --git a/nested/src/editors/sum/editor.rs b/lib-nested-core/src/editors/sum/editor.rs similarity index 84% rename from nested/src/editors/sum/editor.rs rename to lib-nested-core/src/editors/sum/editor.rs index 14b7798..b995da5 100644 --- a/nested/src/editors/sum/editor.rs +++ b/lib-nested-core/src/editors/sum/editor.rs @@ -8,14 +8,9 @@ use { }, laddertypes::{TypeTerm}, crate::{ - terminal::TerminalView, - editors::list::ListCursorMode, - type_system::{Context, ReprTree}, - tree::{TreeNav, TreeCursor, TreeNavResult}, - diagnostics::{Diagnostics, Message}, - tree::NestedNode, - commander::{ObjCommander}, - PtySegment + editors::{list::ListCursorMode, ObjCommander}, + repr_tree::{Context, ReprTree}, + edit_tree::{TreeNav, TreeCursor, TreeNavResult, diagnostics::{Diagnostics, Message}, NestedNode}, }, cgmath::{Vector2}, std::sync::{Arc, RwLock} @@ -28,7 +23,7 @@ pub struct SumEditor { addr_port: ViewPort< dyn SequenceView<Item = isize> >, mode_port: ViewPort< dyn SingletonView<Item = ListCursorMode> >, - port: ViewPort< dyn TerminalView >, +// port: ViewPort< dyn TerminalView >, diag_port: ViewPort< dyn SequenceView<Item = Message> > } @@ -36,12 +31,12 @@ impl SumEditor { pub fn new( editors: Vec< NestedNode > ) -> Self { - let port = ViewPort::new(); +// let port = ViewPort::new(); SumEditor { cur: 0, editors, - port, +// port, diag_port: ViewPort::new(), @@ -55,15 +50,15 @@ impl SumEditor { } pub fn into_node(self, ctx: Arc<RwLock<Context>>) -> NestedNode { - let view = self.pty_view(); +// let view = self.pty_view(); let editor = Arc::new(RwLock::new(self)); NestedNode::new( ctx.clone(), - ReprTree::new_arc(TypeTerm::TypeID(ctx.read().unwrap().get_typeid("Sum").unwrap())), +// ReprTree::new_arc(TypeTerm::TypeID(ctx.read().unwrap().get_typeid("Sum").unwrap())), r3vi::buffer::singleton::SingletonBuffer::new(0).get_port() ) - .set_view(view) +// .set_view(view) .set_editor(editor.clone()) .set_cmd(editor.clone()) .set_nav(editor.clone()) @@ -76,6 +71,7 @@ impl SumEditor { pub fn select(&mut self, idx: usize) { self.cur = idx; +/* FIXME let tv = self.editors[ self.cur ].get_view(); tv.add_observer( self.port.get_cast() ); @@ -100,6 +96,7 @@ impl SumEditor { self.mode_port.update_hooks.write().unwrap().clear(); self.mode_port.add_update_hook( Arc::new(dv.0.clone()) ); self.mode_port.set_view( Some(dv.get_view_arc()) ); + */ } } @@ -129,12 +126,6 @@ impl TreeNav for SumEditor { } } -impl PtySegment for SumEditor { - fn pty_view(&self) -> OuterViewPort<dyn TerminalView> { - self.port.outer() - } -} - impl ObjCommander for SumEditor { fn send_cmd_obj(&mut self, obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { self.editors[ self.cur ].send_cmd_obj( obj ) diff --git a/nested/src/editors/sum/mod.rs b/lib-nested-core/src/editors/sum/mod.rs similarity index 100% rename from nested/src/editors/sum/mod.rs rename to lib-nested-core/src/editors/sum/mod.rs diff --git a/nested/src/editors/typeterm/cmd.rs b/lib-nested-core/src/editors/typeterm/cmd.rs similarity index 97% rename from nested/src/editors/typeterm/cmd.rs rename to lib-nested-core/src/editors/typeterm/cmd.rs index e219cc8..4420115 100644 --- a/nested/src/editors/typeterm/cmd.rs +++ b/lib-nested-core/src/editors/typeterm/cmd.rs @@ -3,10 +3,9 @@ use { view::{singleton::*} }, crate::{ - type_system::{Context, ReprTree}, - editors::{list::{ListEditor, ListCmd, ListCursorMode}}, - tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, - commander::ObjCommander + repr_tree::{Context, ReprTree}, + edit_tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, + editors::{list::{ListEditor, ListCmd, ListCursorMode}, ObjCommander}, }, std::{sync::{Arc, RwLock}}, @@ -241,7 +240,6 @@ impl ObjCommander for TypeTermEditor { self.set_state( State::Ladder ); } } else { - eprintln!("ERROR"); } } else { self.set_state( State::AnySymbol ); diff --git a/nested/src/editors/typeterm/ctx.rs b/lib-nested-core/src/editors/typeterm/ctx.rs similarity index 94% rename from nested/src/editors/typeterm/ctx.rs rename to lib-nested-core/src/editors/typeterm/ctx.rs index 4ad5b55..00d851e 100644 --- a/nested/src/editors/typeterm/ctx.rs +++ b/lib-nested-core/src/editors/typeterm/ctx.rs @@ -4,13 +4,11 @@ use { }, laddertypes::{TypeTerm}, crate::{ - type_system::{Context, MorphismTypePattern}, - terminal::{TerminalStyle, TerminalProjections}, + repr_tree::{Context, MorphismType}, editors::{ - list::{PTYListStyle, PTYListController, ListEditor, ListSegmentSequence}, + list::{ListEditor, ListSegmentSequence}, typeterm::{State, TypeTermEditor} - }, - PtySegment + } }, std::{sync::{Arc, RwLock}}, cgmath::{Point2} @@ -27,8 +25,9 @@ pub fn init_ctx(ctx: &mut Context) { ctx.add_list_typename("Type::App".into()); // = <T1 T2 ...> ctx.add_list_typename("Type::Ladder".into()); // = T1~T2~... +/* ctx.add_morphism( - MorphismTypePattern { src_tyid: ctx.get_typeid("List"), dst_tyid: ctx.get_typeid("Type").unwrap() }, + MorphismType { src_tyid: Context::parse(&ctx, "<List T>"), dst_tyid: Context::parse(&ctx, "Type") }, Arc::new(move |node, _dst_type:_| { let ctx : Arc<RwLock<Context>> = Arc::new(RwLock::new(Context::with_parent(Some(node.ctx.clone())))); ctx.write().unwrap().meta_chars.push('~'); @@ -36,7 +35,8 @@ pub fn init_ctx(ctx: &mut Context) { let new_node = TypeTermEditor::with_node( ctx, node.clone(), State::Any ); Some(new_node) })); - + */ +/* ctx.add_morphism( MorphismTypePattern { src_tyid: ctx.get_typeid("List"), dst_tyid: ctx.get_typeid("Type::Ladder").unwrap() }, Arc::new(|mut node, _dst_type: _| { @@ -140,5 +140,6 @@ pub fn init_ctx(ctx: &mut Context) { |ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>| { Some(TypeTermEditor::new_node(ctx, depth)) })); + */ } diff --git a/nested/src/editors/typeterm/mod.rs b/lib-nested-core/src/editors/typeterm/mod.rs similarity index 94% rename from nested/src/editors/typeterm/mod.rs rename to lib-nested-core/src/editors/typeterm/mod.rs index d15cbb4..abaaaab 100644 --- a/nested/src/editors/typeterm/mod.rs +++ b/lib-nested-core/src/editors/typeterm/mod.rs @@ -11,10 +11,9 @@ use { }, laddertypes::{TypeID, TypeTerm}, crate::{ - type_system::{Context, ReprTree}, - editors::{list::{ListCursorMode, ListEditor, ListCmd}}, - tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, - commander::ObjCommander + repr_tree::{Context, ReprTree}, + edit_tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, + editors::{list::{ListCursorMode, ListEditor, ListCmd}, ObjCommander}, }, std::{sync::{Arc, RwLock}} }; @@ -169,8 +168,8 @@ impl TypeTermEditor { node.goto(TreeCursor::home()); - let _editor = node.editor.get(); - self.close_char.set(node.close_char.get()); + let _editor = node.edit.editor.get(); + self.close_char.set(node.edit.close_char.get()); self.cur_node.set(node); self.state = new_state; } @@ -205,9 +204,9 @@ impl TypeTermEditor { cur_node: SingletonBuffer::new(cur_node.clone()), close_char: SingletonBuffer::new(None), spillbuf: Arc::new(RwLock::new(Vec::new())), - depth: cur_node.depth.clone() + depth: cur_node.disp.depth.clone() }; - +/* FIXME let view = editor.cur_node .get_port() .map(|node| { @@ -215,24 +214,25 @@ impl TypeTermEditor { }) .to_grid() .flatten(); - let _cc = editor.cur_node.get().close_char; + */ + let _cc = editor.cur_node.get().edit.close_char; let editor = Arc::new(RwLock::new(editor)); - let mut super_node = NestedNode::new(ctx, data, cur_node.depth) - .set_view(view) + let mut super_node = NestedNode::new(ctx, data, cur_node.disp.depth) +// .set_view(view) .set_nav(editor.clone()) .set_cmd(editor.clone()) .set_editor(editor.clone()); - editor.write().unwrap().close_char = super_node.close_char.clone(); - super_node.spillbuf = editor.read().unwrap().spillbuf.clone(); + editor.write().unwrap().close_char = super_node.edit.close_char.clone(); + super_node.edit.spillbuf = editor.read().unwrap().spillbuf.clone(); super_node } fn forward_spill(&mut self) { let node = self.cur_node.get(); - let mut buf = node.spillbuf.write().unwrap(); + let mut buf = node.edit.spillbuf.write().unwrap(); for n in buf.iter() { self.spillbuf.write().unwrap().push(n.clone()); } @@ -285,7 +285,6 @@ impl TypeTermEditor { } pub fn normalize_empty(&mut self) { - eprintln!("normalize singleton"); let subladder_list_node = self.cur_node.get().clone(); let subladder_list_edit = subladder_list_node.get_edit::<ListEditor>().unwrap(); @@ -298,7 +297,6 @@ impl TypeTermEditor { /* unwrap a ladder if it only contains one element */ pub fn normalize_singleton(&mut self) { - eprintln!("normalize singleton"); if self.state == State::Ladder { let subladder_list_node = self.cur_node.get().clone(); @@ -362,7 +360,6 @@ impl TypeTermEditor { /* replace with new list-node (ladder/app) with self as first element */ pub(super) fn morph_to_list(&mut self, state: State) { - eprintln!("morph into ladder"); let mut old_node = self.cur_node.get().clone(); @@ -374,7 +371,7 @@ impl TypeTermEditor { * that has same state & child-node as current node. */ let old_edit_node = TypeTermEditor::new_node( self.ctx.clone(), SingletonBuffer::new(0).get_port() ); - old_node.depth.0.set_view( old_edit_node.depth.map(|x|x).get_view() ); + old_node.disp.depth.0.set_view( old_edit_node.disp.depth.map(|x|x).get_view() ); let old_edit_clone = old_edit_node.get_edit::<TypeTermEditor>().unwrap(); old_edit_clone.write().unwrap().set_state( self.state ); diff --git a/nested/src/editors/typeterm/nav.rs b/lib-nested-core/src/editors/typeterm/nav.rs similarity index 94% rename from nested/src/editors/typeterm/nav.rs rename to lib-nested-core/src/editors/typeterm/nav.rs index 6fb7bf1..b4f2175 100644 --- a/nested/src/editors/typeterm/nav.rs +++ b/lib-nested-core/src/editors/typeterm/nav.rs @@ -7,7 +7,7 @@ use { } }, crate::{ - tree::{TreeNav, TreeCursor, TreeNavResult, TreeHeightOp}, + edit_tree::{TreeNav, TreeCursor, TreeNavResult, TreeHeightOp}, editors::{typeterm::TypeTermEditor, list::ListCursorMode} }, cgmath::Vector2 diff --git a/lib-nested-core/src/lib.rs b/lib-nested-core/src/lib.rs new file mode 100644 index 0000000..b942062 --- /dev/null +++ b/lib-nested-core/src/lib.rs @@ -0,0 +1,8 @@ + +#![feature(trait_upcasting)] + +pub mod repr_tree; +pub mod edit_tree; +pub mod editors; +pub mod utils; + diff --git a/lib-nested-core/src/repr_tree/context.rs b/lib-nested-core/src/repr_tree/context.rs new file mode 100644 index 0000000..b592ae0 --- /dev/null +++ b/lib-nested-core/src/repr_tree/context.rs @@ -0,0 +1,274 @@ +use { + r3vi::{view::{OuterViewPort, singleton::*}, buffer::{singleton::*}}, + laddertypes::{TypeDict, TypeTerm, TypeID, MorphismType, MorphismBase, Morphism}, + crate::{ + repr_tree::{ReprTree, ReprTreeExt, GenericReprTreeMorphism}, + edit_tree::EditTree + }, + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + } +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub static TYPEID_edittree : TypeID = TypeID::Fun(0); +pub static TYPEID_char : TypeID = TypeID::Fun(1); +pub static TYPEID_u64 : TypeID = TypeID::Fun(2); +pub static TYPEID_list : TypeID = TypeID::Fun(3); +pub static TYPEID_vec : TypeID = TypeID::Fun(4); + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[derive(Clone)] +pub struct Context { + /// assigns a name to every type + pub type_dict: Arc<RwLock<TypeDict>>, + + pub morphisms: laddertypes::morphism::MorphismBase< GenericReprTreeMorphism >, + + /// named vertices of the graph + nodes: HashMap< String, Arc<RwLock<ReprTree>> >, + + /// todo: beautify + /// types that can be edited as lists + /// do we really need this? + pub list_types: Vec< TypeID >, + pub meta_chars: Vec< char >, + + edittree_hook: Arc< dyn Fn(&mut EditTree, TypeTerm) + Send +Sync +'static >, + + /// recursion + parent: Option<Arc<RwLock<Context>>>, +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl Context { + pub fn with_parent( + parent: Option<Arc<RwLock<Context>>> + ) -> Self { + Context { + type_dict: match parent.as_ref() { + Some(p) => p.read().unwrap().type_dict.clone(), + None => { + let mut dict = TypeDict::new(); + assert_eq!( TYPEID_edittree, dict.add_typename("EditTree".into()) ); + assert_eq!( TYPEID_char, dict.add_typename("Char".into()) ); + assert_eq!( TYPEID_u64, dict.add_typename("machine.UInt64".into()) ); + assert_eq!( TYPEID_list, dict.add_typename("List".into()) ); + assert_eq!( TYPEID_vec, dict.add_typename("Vec".into()) ); + + Arc::new(RwLock::new(dict)) + } + }, + morphisms: MorphismBase::new( TYPEID_list ), + nodes: HashMap::new(), + list_types: match parent.as_ref() { + Some(p) => p.read().unwrap().list_types.clone(), + None => Vec::new() + }, + meta_chars: match parent.as_ref() { + Some(p) => p.read().unwrap().meta_chars.clone(), + None => Vec::new() + }, + parent, + edittree_hook: Arc::new(|_et, _t| {}) + } + } + + pub fn new() -> Self { + Context::with_parent(None) + } + + pub fn set_edittree_hook(&mut self, hook: Arc< dyn Fn(&mut EditTree, TypeTerm) + Send +Sync +'static >) { + self.edittree_hook = hook; + } + + pub fn depth(&self) -> usize { + if let Some(parent) = self.parent.as_ref() { + parent.read().unwrap().depth() + 1 + } else { + 0 + } + } + + pub fn apply_morphism( &self, rt: &Arc<RwLock<ReprTree>>, ty: &MorphismType ) { + if let Some(path) + = self.morphisms.find_morphism_path( ty.clone().normalize() ) + { + let mut path = path.into_iter(); + if let Some(mut src_type) = path.next() { + for dst_type in path { + if let Some(( m, mut τ, σ )) = + self.morphisms.find_morphism_with_subtyping( + &laddertypes::MorphismType { + src_type: src_type.clone(), + dst_type: dst_type.clone() + } + ) { + let mut rt = rt.descend( τ ).expect("descend src repr"); + (m.setup_projection)( &mut rt, &σ ); + } + + src_type = dst_type; + } + } + } else { + eprintln!("no path found"); + } + } + + pub fn build_repr_tree( + &self, + rt: &Arc<RwLock<ReprTree>>, + root: TypeTerm, + leaves: Vec< TypeTerm > + ) { + let mut st_problem = laddertypes::steiner_tree::PathApproxSteinerTreeSolver::new( + root, + leaves + ); + + if let Some( steiner_tree ) = st_problem.solve( &self.morphisms ) { + for morphism_type in steiner_tree.into_edges() { + eprintln!("--> apply morph to {}", self.type_term_to_str(&morphism_type.dst_type)); + if let Some(( morphism, mut τ, σ )) = + self.morphisms.find_morphism_with_subtyping( &morphism_type ) + { + let mut rt = rt.descend( τ ).expect("descend src repr"); + (morphism.setup_projection)( &mut rt, &σ ); + } + } + } else { + eprintln!("could not find steiner tree to build the requested repr tree"); + } + } + + pub fn make_repr(ctx: &Arc<RwLock<Self>>, t: &TypeTerm) -> Arc<RwLock<ReprTree>> { + let rt = Arc::new(RwLock::new(ReprTree::new( TypeTerm::unit() ))); + ctx.read().unwrap().apply_morphism( &rt, &MorphismType{ src_type: TypeTerm::unit(), dst_type: t.clone() } ); + rt + } + + pub fn parse(ctx: &Arc<RwLock<Self>>, s: &str) -> TypeTerm { + ctx.read().unwrap().type_term_from_str(s).expect("could not parse type term") + } + + pub fn add_typename(&mut self, tn: &str) -> TypeID { + self.type_dict.write().unwrap().add_typename(tn.to_string()) + } + + pub fn add_varname(&mut self, vn: &str) -> TypeID { + self.type_dict.write().unwrap().add_varname(vn.to_string()) + } + + pub fn add_synonym(&mut self, new: &str, old: &str) { + self.type_dict.write().unwrap().add_synonym(new.to_string(), old.to_string()); + } + + pub fn add_list_typename(&mut self, tn: &str) { + let tid = self.add_typename(tn); + self.list_types.push( tid ); + } + + pub fn is_list_type(&self, t: &TypeTerm) -> bool { + match t { + TypeTerm::TypeID(id) => { + self.list_types.contains(id) + } + TypeTerm::Ladder(args) | + TypeTerm::App(args) => { + if args.len() > 0 { + if self.is_list_type(&args[0]) { + true + } else { + false + } + } else { + false + } + } + _ => false + } + } + + pub fn get_typeid(&self, tn: &str) -> Option<TypeID> { + self.type_dict.read().unwrap().get_typeid(&tn.into()) + } + + pub fn get_fun_typeid(&self, tn: &str) -> Option<u64> { + match self.get_typeid(tn) { + Some(TypeID::Fun(x)) => Some(x), + _ => None + } + } + + pub fn get_typename(&self, tid: &TypeID) -> Option<String> { + self.type_dict.read().unwrap().get_typename(tid) + } + + pub fn get_var_typeid(&self, tn: &str) -> Option<u64> { + match self.get_typeid(tn) { + Some(TypeID::Var(x)) => Some(x), + _ => None + } + } + + pub fn type_term_from_str(&self, tn: &str) -> Result<TypeTerm, laddertypes::parser::ParseError> { + self.type_dict.write().unwrap().parse(&tn) + } + + pub fn type_term_to_str(&self, t: &TypeTerm) -> String { + self.type_dict.read().unwrap().unparse(&t) + } + + /// adds an object without any representations + pub fn add_obj(ctx: Arc<RwLock<Context>>, name: String, typename: &str) { + let type_tag = ctx.read().unwrap() + .type_dict.write().unwrap() + .parse(typename).unwrap(); +/* + if let Some(node) = Context::make_node(&ctx, type_tag, SingletonBuffer::new(0).get_port()) { + ctx.write().unwrap().nodes.insert(name, node); + } +*/ + } + + pub fn get_obj(&self, name: &String) -> Option< Arc<RwLock<ReprTree>> > { + if let Some(obj) = self.nodes.get(name) { + Some(obj.clone()) + } else if let Some(parent) = self.parent.as_ref() { + parent.read().unwrap().get_obj(name) + } else { + None + } + } + + pub fn setup_edittree( + &self, + rt: &Arc<RwLock<ReprTree>> + ) -> Option<SingletonBuffer<Arc<RwLock<EditTree>>>> { + if let Some(new_edittree) = + rt.descend(self.type_term_from_str("EditTree").unwrap()) + { + let typ = rt.read().unwrap().get_type().clone(); + let buf = new_edittree.singleton_buffer::<Arc<RwLock<EditTree>>>(); + (*self.edittree_hook)( + &mut *buf.get().write().unwrap(), + typ + ); + Some(buf) + } else { + eprintln!("cant find edit tree repr {} ~Ψ~ {}", + self.type_term_to_str(rt.read().unwrap().get_halo_type()), + self.type_term_to_str(rt.read().unwrap().get_type()) + ); + None + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + diff --git a/lib-nested-core/src/repr_tree/leaf.rs b/lib-nested-core/src/repr_tree/leaf.rs new file mode 100644 index 0000000..6a12440 --- /dev/null +++ b/lib-nested-core/src/repr_tree/leaf.rs @@ -0,0 +1,216 @@ +use { + r3vi::{ + view::{ + ViewPort, OuterViewPort, + AnyViewPort, AnyInnerViewPort, AnyOuterViewPort, + port::UpdateTask, + View, Observer, + singleton::*, + sequence::*, + list::* + }, + buffer::{singleton::*, vec::*} + }, + laddertypes::{TypeTerm}, + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + any::Any + }, +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[derive(Clone)] +pub struct ReprLeaf { + out_port: AnyViewPort, + in_port: AnyInnerViewPort, + data: Option< Arc<dyn Any + Send + Sync> >, + + /// keepalive for the observer that updates the buffer from in_port + keepalive: Option<Arc<dyn Any + Send + Sync>>, + in_keepalive: Option<Arc<dyn Any + Send + Sync>>, +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl ReprLeaf { + pub fn from_view<V>( src_port: OuterViewPort<V> ) -> Self + where V: View + ?Sized + 'static, + V::Msg: Clone + { + let mut in_port = ViewPort::<V>::new(); + let in_keepalive = in_port.attach_to(src_port); + + let mut out_port = ViewPort::<V>::new(); + let out_keepalive = out_port.attach_to(in_port.outer()); + + ReprLeaf { + keepalive: Some(out_keepalive), + in_keepalive: Some(in_keepalive), + in_port: in_port.inner().into(), + out_port: out_port.into(), + data: None, + } + } + + pub fn detach<V>(&mut self) + where V: View + ?Sized + 'static, + V::Msg: Clone + { + self.keepalive = None; + self.in_keepalive = None; + + let ip = self.in_port.clone() + .downcast::<V>().ok() + .unwrap(); + ip.0.detach(); + + if self.data.is_none() { + let mut op = self.out_port.clone() + .downcast::<V>().ok() + .unwrap(); + + op.detach(); + self.keepalive = Some(op.attach_to(ip.0.outer())); + } + } + + pub fn detach_vec<Item>(&mut self) + where Item: Clone + Send + Sync + 'static + { + self.keepalive = None; + self.in_keepalive = None; + + let ip = self.in_port.clone() + .downcast::<dyn ListView<Item>>().ok() + .unwrap(); + + ip.0.detach(); + + if let Some(data) = self.data.as_mut() { + let mut op = self.out_port.clone() + .downcast::<RwLock<Vec<Item>>>().ok() + .unwrap(); + op.detach(); + + let data = data.clone().downcast::< RwLock<Vec<Item>> >().ok().unwrap(); + let buffer = VecBuffer::with_data_arc_port(data, op.inner()); + self.keepalive = Some(buffer.attach_to(ip.0.outer())) + } + } + + pub fn attach_to<V>(&mut self, src_port: OuterViewPort<V>) + where V: View + ?Sized + 'static, + V::Msg: Clone + { + self.in_keepalive = Some(self.in_port.clone() + .downcast::<V>().ok().unwrap() + .0.attach_to( src_port )); + } + + pub fn from_singleton_buffer<T>( buffer: SingletonBuffer<T> ) -> Self + where T: Clone + Send + Sync + 'static + { + let in_port = ViewPort::<dyn SingletonView<Item = T>>::new(); + ReprLeaf { + in_keepalive: None, + keepalive: Some(buffer.attach_to(in_port.outer())), + in_port: in_port.inner().into(), + out_port: buffer.get_port().0.into(), + data: Some(buffer.into_inner()) + } + } + + pub fn from_vec_buffer<T>( buffer: VecBuffer<T> ) -> Self + where T: Clone + Send + Sync + 'static + { + let in_port = ViewPort::< dyn ListView<T> >::new(); + ReprLeaf { + in_keepalive: None, + keepalive: Some(buffer.attach_to(in_port.outer())), + in_port: in_port.inner().into(), + out_port: buffer.get_port().0.into(), + data: Some(buffer.into_inner()) + } + } + + pub fn as_singleton_buffer<T>(&mut self) -> Option<SingletonBuffer<T>> + where T: Clone + Send + Sync + 'static + { + let sgl_port = self.get_port::< dyn SingletonView<Item = T> >().unwrap().0; + + let data_arc = + if let Some(data) = self.data.as_ref() { + data.clone().downcast::<RwLock<T>>().ok() + } else { + sgl_port.update(); + let value = sgl_port.outer().get_view().unwrap().get(); + eprintln!("make new data ARC from old value"); + Some(Arc::new(RwLock::new( value ))) + }; + + if let Some(data_arc) = data_arc { + self.data = Some(data_arc.clone() as Arc<dyn Any + Send + Sync>); + let buf = SingletonBuffer { + value: data_arc, + port: sgl_port.inner() + }; + self.keepalive = Some(buf.attach_to( + self.in_port.0.clone() + .downcast::<dyn SingletonView<Item = T>>() + .ok().unwrap() + .outer() + )); + Some(buf) + } else { + None + } + } + + pub fn as_vec_buffer<T>(&mut self) -> Option<VecBuffer<T>> + where T: Clone + Send + Sync + 'static + { + let vec_port = self.get_port::< RwLock<Vec<T>> >().unwrap().0; + + let data_arc = + if let Some(data) = self.data.as_ref() { + data.clone().downcast::<RwLock<Vec<T>>>().ok() + } else { + vec_port.update(); + if let Some(value) = vec_port.outer().get_view() { + let value = value.read().unwrap().clone(); + eprintln!("make new data ARC from old VECTOR-value"); + Some(Arc::new(RwLock::new( value ))) + } else { + eprintln!("no data vec"); + Some(Arc::new(RwLock::new( Vec::new() ))) +// None + } + }; + + if let Some(data_arc) = data_arc { + self.data = Some(data_arc.clone() as Arc<dyn Any + Send + Sync>); + let buf = VecBuffer::with_data_arc_port(data_arc, vec_port.inner()); + self.keepalive = Some(buf.attach_to( + self.in_port.0.clone() + .downcast::< dyn ListView<T> >() + .ok().unwrap() + .outer() + )); + Some(buf) + } else { + None + } + } + + pub fn get_port<V>(&self) -> Option<OuterViewPort<V>> + where V: View + ?Sized + 'static, + V::Msg: Clone + { + self.out_port.clone().downcast::<V>().ok().map(|p| p.outer()) + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + diff --git a/lib-nested-core/src/repr_tree/mod.rs b/lib-nested-core/src/repr_tree/mod.rs new file mode 100644 index 0000000..8af48f8 --- /dev/null +++ b/lib-nested-core/src/repr_tree/mod.rs @@ -0,0 +1,145 @@ +pub mod node; +pub mod leaf; +pub mod context; +pub mod morphism; + +#[cfg(test)] +mod tests; + +pub use { + context::{Context}, + leaf::ReprLeaf, + node::ReprTree, + morphism::{GenericReprTreeMorphism} +}; + +use { + r3vi::{ + view::{ + ViewPort, OuterViewPort, + AnyViewPort, AnyInnerViewPort, AnyOuterViewPort, + port::UpdateTask, + View, Observer, + singleton::*, + sequence::*, + list::* + }, + buffer::{singleton::*, vec::*} + }, + laddertypes::{TypeTerm}, + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + any::Any + }, +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub trait ReprTreeExt { + fn get_type(&self) -> TypeTerm; + + fn insert_leaf(&mut self, type_ladder: impl Into<TypeTerm>, leaf: ReprLeaf); + fn insert_branch(&mut self, repr: Arc<RwLock<ReprTree>>); + fn create_branch(&mut self, rung: impl Into<TypeTerm>); + fn descend(&self, target_type: impl Into<TypeTerm>) -> Option<Arc<RwLock<ReprTree>>>; + + fn attach_leaf_to<V: View + ?Sized + 'static>(&self, t: impl Into<TypeTerm>, v: OuterViewPort<V>) where V::Msg: Clone; + fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>> where V::Msg: Clone; + + fn view_char(&self) -> OuterViewPort<dyn SingletonView<Item = char>>; + fn view_u8(&self) -> OuterViewPort<dyn SingletonView<Item = u8>>; + fn view_u64(&self) -> OuterViewPort<dyn SingletonView<Item = u64>>; + fn view_usize(&self) -> OuterViewPort<dyn SingletonView<Item = usize>>; + + fn view_singleton<T: Send + Sync + 'static>(&self) -> OuterViewPort<dyn SingletonView<Item = T>>; + fn view_seq<T: Send + Sync + 'static>(&self) -> OuterViewPort<dyn SequenceView<Item = T>>; + fn view_list<T: Clone + Send + Sync + 'static>(&self) -> OuterViewPort<dyn ListView<T>>; + + fn singleton_buffer<T: Clone + Send + Sync + 'static>(&self) -> SingletonBuffer<T>; + fn vec_buffer<T: Clone + Send + Sync + 'static>(&self) -> VecBuffer<T>; + + fn edittree(&self, ctx: &Arc<RwLock<Context>>) -> SingletonBuffer< Arc<RwLock<crate::edit_tree::EditTree>> > { + self.descend(Context::parse(&ctx, "EditTree")).unwrap() + .singleton_buffer() + } +} + +impl ReprTreeExt for Arc<RwLock<ReprTree>> { + fn get_type(&self) -> TypeTerm { + self.read().unwrap().get_type().clone() + } + + fn insert_leaf(&mut self, type_ladder: impl Into<TypeTerm>, leaf: ReprLeaf) { + self.write().unwrap().insert_leaf(type_ladder.into().get_lnf_vec().into_iter(), leaf) + } + + fn insert_branch(&mut self, repr: Arc<RwLock<ReprTree>>) { + self.write().unwrap().insert_branch(repr) + } + + fn create_branch(&mut self, rung: impl Into<TypeTerm>) { + let mut lnf = rung.into().get_lnf_vec().into_iter(); + if let Some(rung) = lnf.next() { + let mut parent = ReprTree::new_arc( rung ); + self.insert_branch( parent.clone() ); + + for rung in lnf { + let r = ReprTree::new_arc( rung ); + parent.insert_branch(r.clone()); + parent = r; + } + } + } + + fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>> where V::Msg: Clone { + self.read().unwrap().get_port::<V>() + } + + fn attach_leaf_to<V: View + ?Sized + 'static>(&self, type_ladder: impl Into<TypeTerm>, v: OuterViewPort<V>) where V::Msg: Clone { + self.write().unwrap().attach_leaf_to::<V>(type_ladder.into().get_lnf_vec().into_iter(), v) + } + + fn descend(&self, target_type: impl Into<TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { + ReprTree::descend( self, target_type ) + } + + fn view_char(&self) -> OuterViewPort<dyn SingletonView<Item = char>> { + self.read().unwrap().view_char() + } + + fn view_u8(&self) -> OuterViewPort<dyn SingletonView<Item = u8>> { + self.read().unwrap().view_u8() + } + + fn view_u64(&self) -> OuterViewPort<dyn SingletonView<Item = u64>> { + self.read().unwrap().view_u64() + } + + fn view_usize(&self) -> OuterViewPort<dyn SingletonView<Item = usize>> { + self.read().unwrap().view_usize() + } + + fn view_singleton<T: Send + Sync + 'static>(&self) -> OuterViewPort<dyn SingletonView<Item = T>> { + self.read().unwrap().view_singleton::<T>() + } + + fn view_seq<T: Send + Sync + 'static>(&self) -> OuterViewPort<dyn SequenceView<Item = T>> { + self.read().unwrap().view_seq::<T>() + } + + fn view_list<T: Clone + Send + Sync + 'static>(&self) -> OuterViewPort<dyn ListView<T>> { + self.read().unwrap().view_list::<T>() + } + + fn singleton_buffer<T: Clone + Send + Sync + 'static>(&self) -> SingletonBuffer<T> { + self.write().unwrap().singleton_buffer::<T>().expect("") + } + + fn vec_buffer<T: Clone + Send + Sync + 'static>(&self) -> VecBuffer<T> { + self.write().unwrap().vec_buffer::<T>().expect("") + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + diff --git a/lib-nested-core/src/repr_tree/morphism.rs b/lib-nested-core/src/repr_tree/morphism.rs new file mode 100644 index 0000000..fe59b6f --- /dev/null +++ b/lib-nested-core/src/repr_tree/morphism.rs @@ -0,0 +1,207 @@ +use { + laddertypes::{TypeTerm, TypeID, morphism::Morphism}, + r3vi::view::{AnyOuterViewPort, port::*, list::*}, + crate::{ + repr_tree::{ + ReprTree, ReprTreeExt, ReprLeaf, + context::{*} + }, + }, + std::{ + sync::{Arc, RwLock}, + collections::HashMap + } +}; + +pub use laddertypes::morphism::MorphismType; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[derive(Clone)] +pub struct GenericReprTreeMorphism { + pub(super) morph_type: MorphismType, + pub(super) setup_projection: Arc< + dyn Fn( &mut Arc<RwLock<ReprTree>>, &HashMap<TypeID, TypeTerm> ) +// -> Result< ReprLeaf, () > + + Send + Sync + > +} + +impl Morphism for GenericReprTreeMorphism { + fn get_type(&self) -> MorphismType { + self.morph_type.clone() + } + + fn list_map_morphism(&self, list_typeid: TypeID) -> Option< GenericReprTreeMorphism > { + self.into_list_map_dyn(list_typeid) + } +} + +impl GenericReprTreeMorphism { + pub fn new( + src_type: TypeTerm, + dst_type: TypeTerm, + + setup: impl Fn( &mut Arc<RwLock<ReprTree>>, &HashMap<TypeID, TypeTerm> ) + + Send + Sync + 'static + ) -> Self { + GenericReprTreeMorphism { + morph_type: MorphismType { + src_type, dst_type + }.normalize(), + + setup_projection: Arc::new(setup) + } + } + + pub fn into_list_map< SrcItem, DstItem >(&self, list_typeid: TypeID) + -> GenericReprTreeMorphism + where + SrcItem: Clone + Send + Sync + 'static, + DstItem: Clone + Send + Sync + 'static + { + let mut lst_map_type = MorphismType { + src_type: TypeTerm::App(vec![ + TypeTerm::TypeID(list_typeid), + self.morph_type.src_type.clone() + ]), + dst_type: TypeTerm::App(vec![ + TypeTerm::TypeID(list_typeid), + self.morph_type.dst_type.clone() + ]) + }.normalize(); + + let item_morph = self.clone(); + + GenericReprTreeMorphism{ + morph_type: lst_map_type.clone(), + setup_projection: Arc::new(move |repr_tree, subst| { + let mut lst_map_type = lst_map_type.clone(); + lst_map_type.src_type.apply_substitution( &|x| subst.get(x).cloned() ); + lst_map_type.dst_type.apply_substitution( &|x| subst.get(x).cloned() ); + + eprintln!( + "lst map type : {:?}", lst_map_type + ); + + let src_port = repr_tree + .descend( lst_map_type.src_type.clone() ) + .expect("descend src seq") + .view_list::<SrcItem>(); + + let subst = subst.clone(); + let item_morph = item_morph.clone(); + + let dst_view = src_port.map( + move |x| { + let mut item_ladder = item_morph.morph_type.src_type.clone().get_lnf_vec(); + let mut item_rt = ReprTree::from_singleton_buffer( + item_ladder.remove( item_ladder.len() - 1 ), + r3vi::buffer::singleton::SingletonBuffer::new(x.clone()) + ); + + // TODO: required? + while item_ladder.len() > 0 { + let mut n = ReprTree::new_arc( item_ladder.remove( item_ladder.len() - 1) ); + n.insert_branch( item_rt ); + item_rt = n; + } + + (item_morph.setup_projection)( &mut item_rt, &subst ); + item_rt.descend( item_morph.morph_type.dst_type.clone() ).expect("descend to item rt") + .view_singleton::< DstItem >() + .get_view().unwrap() + .get() + } + ); + + repr_tree.attach_leaf_to( + lst_map_type.dst_type.clone(), + dst_view as r3vi::view::OuterViewPort::< dyn r3vi::view::list::ListView<DstItem> > + ); + }) + } + } + + pub fn into_list_map_dyn(&self, typeid_list: TypeID) + -> Option< GenericReprTreeMorphism > + { + let src_item_type_lnf = self.morph_type.src_type.clone().get_lnf_vec(); + let dst_item_type_lnf = self.morph_type.dst_type.clone().get_lnf_vec(); + + eprintln!("into list map dyn"); + + if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) + { + Some( self.into_list_map::< char, char >(TYPEID_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_u64)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_u64)) + { + Some( self.into_list_map::< u64, u64 >(TYPEID_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_u64)) + { + Some( self.into_list_map::< char, u64 >(TYPEID_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_u64)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) + { + Some( self.into_list_map::< u64, char >(TYPEID_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_edittree)) + { + Some( self.into_list_map::< char, Arc<RwLock<crate::edit_tree::EditTree>> >(TYPEID_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_edittree)) && + dst_item_type_lnf.last() == Some(&TypeTerm::TypeID(TYPEID_char)) + { + Some( self.into_list_map::< Arc<RwLock<crate::edit_tree::EditTree>>, char >(TYPEID_list) ) + } +/* + else if src_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_char) ])) && + dst_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_char) ])) + { + Some( self.into_list_map::< char, char >(typeid_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_u64) ])) && + dst_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_u64) ])) + { + Some( self.into_list_map::< u64, u64 >(typeid_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_char) ])) && + dst_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_u64) ])) + { + Some( self.into_list_map::< OuterViewPort<dyn ListView<char>>, OuterViewPort<dyn ListView<u64>> >(typeid_list) ) + } + else if src_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_u64) ])) && + dst_item_type_lnf.last() == Some(&TypeTerm::App(vec![ TypeTerm::TypeID(typeid_list), TypeTerm::TypeID(typeid_char) ])) + { + Some( self.into_list_map::< OuterViewPort<dyn ListView<u64>>, OuterViewPort<dyn ListView<char>> >(typeid_list) ) + } +*/ + else + { + eprintln!("no list map type for {:?}", dst_item_type_lnf.last()); + None + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> +/* +impl MorphismType { + pub fn to_str(&self, ctx: &Context) -> String { + format!("{:?} -> {:?}", + if let Some(t) = self.src_type.as_ref() { + ctx.type_dict.read().unwrap().unparse(t) + } else { + "None".into() + }, + ctx.type_dict.read().unwrap().unparse(&self.dst_type)) + } +} +*/ diff --git a/lib-nested-core/src/repr_tree/node.rs b/lib-nested-core/src/repr_tree/node.rs new file mode 100644 index 0000000..bc51906 --- /dev/null +++ b/lib-nested-core/src/repr_tree/node.rs @@ -0,0 +1,453 @@ + + +use { + r3vi::{ + view::{ + ViewPort, OuterViewPort, + AnyViewPort, AnyInnerViewPort, AnyOuterViewPort, + port::UpdateTask, + View, Observer, + singleton::*, + sequence::*, + list::* + }, + buffer::{singleton::*, vec::*} + }, + laddertypes::{TypeTerm, TypeID}, + std::{ + collections::HashMap, + sync::{Arc, RwLock}, + any::Any + }, + super::{Context, ReprLeaf, ReprTreeExt, context::{TYPEID_list, TYPEID_vec, TYPEID_char, TYPEID_u64, TYPEID_edittree}} +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[derive(Clone)] +pub struct ReprTree { + halo: TypeTerm, + type_tag: TypeTerm, + branches: HashMap<TypeTerm, Arc<RwLock<ReprTree>>>, + leaf: Option< ReprLeaf > +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl std::fmt::Debug for ReprTree { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "| type: {:?}", self.type_tag)?; + + for (_k,x) in self.branches.iter() { + writeln!(f, "|--> child: {:?}", x)?; + } + writeln!(f, ""); + + Ok(()) + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl ReprTree { + pub fn new(type_tag: impl Into<TypeTerm>) -> Self { + let type_tag = type_tag.into(); + + assert!(type_tag.is_flat()); + + ReprTree { + halo: TypeTerm::unit(), + type_tag: type_tag.clone(), + branches: HashMap::new(), + leaf: None + } + } + + pub fn new_arc(type_tag: impl Into<TypeTerm>) -> Arc<RwLock<Self>> { + Arc::new(RwLock::new(Self::new(type_tag))) + } + + pub fn get_type(&self) -> &TypeTerm { + &self.type_tag + } + + pub fn set_halo(&mut self, halo_type: impl Into<TypeTerm>) { + self.halo = halo_type.into(); + for (branch_type, branch) in self.branches.iter() { + branch.write().unwrap().set_halo( TypeTerm::Ladder(vec![ + self.halo.clone(), + self.type_tag.clone() + ]).normalize() + ); + } + } + + pub fn get_halo_type(&self) -> &TypeTerm { + &self.halo + } + + pub fn get_leaf_types(&self) -> Vec< TypeTerm > { + let mut leaf_types = Vec::new(); + if self.leaf.is_some() { + leaf_types.push( self.get_type().clone() ); + } + for (branch_type, branch) in self.branches.iter() { + for t in branch.read().unwrap().get_leaf_types() { + leaf_types.push(TypeTerm::Ladder(vec![ + self.get_type().clone(), + t + ]).normalize()) + } + } + leaf_types + } + + pub fn insert_branch(&mut self, repr: Arc<RwLock<ReprTree>>) { + let branch_type = repr.read().unwrap().get_type().clone(); + + assert!(branch_type.is_flat()); + + repr.write().unwrap().set_halo( TypeTerm::Ladder(vec![ + self.halo.clone(), + self.type_tag.clone() + ]).normalize() ); + + self.branches.insert(branch_type, repr.clone()); + } + + pub fn from_char(ctx: &Arc<RwLock<Context>>, c: char ) -> Arc<RwLock<Self>> { + ReprTree::from_singleton_buffer( + Context::parse(ctx, "Char"), + SingletonBuffer::new(c) + ) + } + + pub fn from_view<V>( type_tag: impl Into<TypeTerm>, view: OuterViewPort<V> ) -> Arc<RwLock<Self>> + where V: View + ?Sized + 'static, + V::Msg: Clone + { + let mut rt = ReprTree::new(type_tag); + rt.leaf = Some(ReprLeaf::from_view(view)); + Arc::new(RwLock::new(rt)) + } + + pub fn from_singleton_buffer<T>( type_tag: impl Into<TypeTerm>, buf: SingletonBuffer<T> ) -> Arc<RwLock<Self>> + where T: Clone + Send + Sync + 'static + { + let mut rt = ReprTree::new(type_tag); + rt.leaf = Some(ReprLeaf::from_singleton_buffer(buf)); + Arc::new(RwLock::new(rt)) + } + + pub fn from_str( + type_tag: impl Into<TypeTerm>, + val: &str + ) -> Arc<RwLock<Self>> { + let mut lnf = type_tag.into().get_lnf_vec(); + + let mut rt = ReprTree::from_vec_buffer( + lnf.pop().unwrap(), + VecBuffer::with_data( val.chars().collect() ) + ); + + while let Some(t) = lnf.pop() { + let mut new_rt = ReprTree::new_arc(t); + new_rt.insert_branch(rt); + rt = new_rt; + } + + rt + } + + pub fn from_vec_buffer<T>( type_tag: impl Into<TypeTerm>, buf: VecBuffer<T> ) -> Arc<RwLock<Self>> + where T: Clone + Send + Sync + 'static + { + let mut rt = ReprTree::new(type_tag); + rt.leaf = Some(ReprLeaf::from_vec_buffer(buf)); + Arc::new(RwLock::new(rt)) + } + + pub fn attach_to<V>( + &mut self, + src_port: OuterViewPort<V> + ) + where V: View + ?Sized + 'static, + V::Msg: Clone + { + if let Some(leaf) = self.leaf.as_mut() { + leaf.attach_to(src_port); + } else { + eprintln!("cant attach branch without leaf"); + } + } + + /// find, and if necessary, create corresponding path in repr-tree. + /// Attach src_port to input of that node + pub fn attach_leaf_to<V>( + &mut self, + mut type_ladder: impl Iterator<Item = TypeTerm>, + src_port: OuterViewPort<V> + ) + where V: View + ?Sized + 'static, + V::Msg: Clone + { + while let Some(rung_type) = type_ladder.next() { + if &rung_type != self.get_type() { + if let Some(next_repr) = self.branches.get(&rung_type) { + next_repr.write().unwrap().attach_leaf_to(type_ladder, src_port); + } else { + let mut next_repr = ReprTree::new(rung_type.clone()); + next_repr.attach_leaf_to(type_ladder, src_port); + self.insert_branch(Arc::new(RwLock::new(next_repr))); + } + return; + } + } + + if let Some(leaf) = self.leaf.as_mut() { + leaf.attach_to(src_port); + } else { + if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_edittree) + ]) { + let mut leaf = ReprLeaf::from_vec_buffer( + VecBuffer::< + Arc<RwLock<crate::edit_tree::EditTree>> + >::new() + ); + + leaf.attach_to(src_port); + self.leaf = Some(leaf); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_char) + ]) { + let mut leaf = ReprLeaf::from_vec_buffer( + VecBuffer::<char>::new() + ); + + leaf.attach_to(src_port); + self.leaf = Some(leaf); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_u64) + ]) { + let mut leaf = ReprLeaf::from_vec_buffer( + VecBuffer::<u64>::new() + ); + + leaf.attach_to(src_port); + self.leaf = Some(leaf); + } else { + self.leaf = Some(ReprLeaf::from_view(src_port)); + } + } + } + + pub fn detach(&mut self, ctx: &Arc<RwLock<Context>>) { + if let Some(leaf) = self.leaf.as_mut() { + if self.type_tag == + TypeTerm::TypeID(TYPEID_edittree) + { + leaf.detach::< dyn SingletonView< + Item = Arc<RwLock< crate::edit_tree::EditTree >> + > >(); + } + else if self.type_tag == + TypeTerm::TypeID(TYPEID_char) + { + leaf.detach::< dyn SingletonView<Item = char> >(); + } + else if self.type_tag == TypeTerm::TypeID(TYPEID_u64) + { + leaf.detach::< dyn SingletonView<Item = u64> >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_edittree), + ]) { + leaf.detach_vec::< + Arc<RwLock< crate::edit_tree::EditTree >> + >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_char), + ]) { + leaf.detach_vec::< char >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_vec), + TypeTerm::TypeID(TYPEID_u64), + ]) { + leaf.detach_vec::< u64 >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_list), + TypeTerm::TypeID(TYPEID_edittree), + ]) { + leaf.detach::< dyn ListView<Arc<RwLock<crate::edit_tree::EditTree>>> >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_list), + TypeTerm::TypeID(TYPEID_char), + ]) { + leaf.detach::< dyn ListView<char> >(); + } + else if self.type_tag == TypeTerm::App(vec![ + TypeTerm::TypeID(TYPEID_list), + TypeTerm::TypeID(TYPEID_u64), + ]) { + leaf.detach::< dyn ListView<u64> >(); + } + else { + eprintln!("cant detach type {}", ctx.read().unwrap().type_term_to_str(&self.type_tag)); + } + } + + for (t,b) in self.branches.iter_mut() { + b.write().unwrap().detach(&ctx); + } + } + + pub fn insert_leaf( + &mut self, + mut type_ladder: impl Iterator<Item = TypeTerm>, + leaf: ReprLeaf + ) { + while let Some(type_term) = type_ladder.next() { + if &type_term != self.get_type() { + if let Some(next_repr) = self.branches.get(&type_term) { + next_repr.write().unwrap().insert_leaf(type_ladder, leaf.clone()); + } else { + let mut next_repr = ReprTree::new(type_term.clone()); + next_repr.insert_leaf(type_ladder, leaf.clone()); + self.insert_branch(Arc::new(RwLock::new(next_repr))); + } + return; + } + } + + self.leaf = Some(leaf); + } + + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + + pub fn descend_one(&self, dst_type: impl Into<TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { + let dst_type = dst_type.into(); + assert!( dst_type.is_flat() ); + self.branches.get(&dst_type).cloned() + } + + pub fn descend_ladder(rt: &Arc<RwLock<Self>>, mut repr_ladder: impl Iterator<Item = TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { + if let Some(first) = repr_ladder.next() { + let rt = rt.read().unwrap(); + repr_ladder.fold( + rt.descend_one(first), + |s, t| s?.descend(t)) + } else { + Some(rt.clone()) + } + } + + pub fn descend(rt: &Arc<RwLock<Self>>, dst_type: impl Into<TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { + let mut lnf = dst_type.into().get_lnf_vec(); + if lnf.len() > 0 { + if lnf[0] == rt.get_type() { + lnf.remove(0); + } + ReprTree::descend_ladder(rt, lnf.into_iter()) + } else { + Some(rt.clone()) + } + } + + pub fn ascend(rt: &Arc<RwLock<Self>>, type_term: impl Into<TypeTerm>) -> Arc<RwLock<ReprTree>> { + let mut n = Self::new(type_term); + n.insert_branch(rt.clone()); + Arc::new(RwLock::new(n)) + } + + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + + pub fn singleton_buffer<T: Clone + Send + Sync + 'static>(&mut self) -> Option<SingletonBuffer<T>> { + if let Some(leaf) = self.leaf.as_mut() { + leaf.as_singleton_buffer::<T>() + } else { + // create new singleton buffer + /* + // default value?? + let buf = SingletonBuffer::<T>::default(); + self.leaf = Some(ReprLeaf::from_singleton_buffer(buf.clone())); + Some(buf) + */ + None + } + } + + pub fn vec_buffer<T: Clone + Send + Sync + 'static>(&mut self) -> Option<VecBuffer<T>> { + if let Some(leaf) = self.leaf.as_mut() { + leaf.as_vec_buffer::<T>() + } else { + None + } + } + + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + + pub fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>> + where + V::Msg: Clone, + { + if let Some(leaf) = self.leaf.as_ref() { + leaf.get_port::<V>() + } else { + None + } + } + + pub fn get_view<V: View + ?Sized + 'static>(&self) -> Option<Arc<V>> + where + V::Msg: Clone, + { + self.get_port::<V>()? + .get_view() + } + + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + + pub fn view_singleton<T: 'static>(&self) -> OuterViewPort<dyn SingletonView<Item = T>> { + self.get_port::<dyn SingletonView<Item = T>>().expect("no singleton-view available") + } + + pub fn view_seq<T: 'static>(&self) -> OuterViewPort<dyn SequenceView<Item = T>> { + self.get_port::<dyn SequenceView<Item = T>>().expect("no sequence-view available") + } + + pub fn view_list<T: Clone + Send + Sync + 'static>(&self) -> OuterViewPort<dyn ListView<T>> { + self.get_port::<dyn ListView<T>>().expect("no list-view available") + } + + pub fn view_char(&self) -> OuterViewPort<dyn SingletonView<Item = char>> { + self.get_port::<dyn SingletonView<Item = char>>().expect("no char-view available") + } + + pub fn view_u8(&self) -> OuterViewPort<dyn SingletonView<Item = u8>> { + self.get_port::<dyn SingletonView<Item = u8>>().expect("no u8-view available") + } + + pub fn view_u64(&self) -> OuterViewPort<dyn SingletonView<Item = u64>> { + self.get_port::<dyn SingletonView<Item = u64>>().expect("no u64-view available") + } + + pub fn view_usize(&self) -> OuterViewPort<dyn SingletonView<Item = usize>> { + self.get_port::<dyn SingletonView<Item = usize>>().expect("no usize-view available") + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + + diff --git a/lib-nested-core/src/repr_tree/tests.rs b/lib-nested-core/src/repr_tree/tests.rs new file mode 100644 index 0000000..8663cb7 --- /dev/null +++ b/lib-nested-core/src/repr_tree/tests.rs @@ -0,0 +1,198 @@ + +use { + r3vi::{ + buffer::singleton::{ + SingletonBuffer + }, + view::port::UpdateTask + }, + crate::{ + repr_tree::{Context, ReprTreeExt, ReprTree, ReprLeaf} + }, + std::sync::{Arc, RwLock} +}; + +#[test] +fn halo_type() { + let ctx = Arc::new(RwLock::new(Context::new())); + + let mut rt1 = ReprTree::new_arc(Context::parse(&ctx, "ℕ")); + let mut rt2 = ReprTree::new_arc(Context::parse(&ctx, "<PosInt 10 BigEndian>")); + rt1.insert_branch( rt2.clone() ); + assert_eq!( rt2.read().unwrap().get_halo_type(), &Context::parse(&ctx, "ℕ") ); + + let mut rt3 = ReprTree::new_arc(Context::parse(&ctx, "<Seq <Digit 10>>")); + rt2.insert_branch( rt3.clone() ); + assert_eq!( rt3.read().unwrap().get_halo_type(), &Context::parse(&ctx, "ℕ~<PosInt 10 BigEndian>") ); + + let rt4 = ReprTree::new_arc(Context::parse(&ctx, "<List <Digit 10>>")); + rt3.insert_branch( rt4.clone() ); + assert_eq!( rt4.read().unwrap().get_halo_type(), &Context::parse(&ctx, "ℕ~<PosInt 10 BigEndian>~<Seq <Digit 10>>") ); + + + let mut r = ReprTree::new_arc(Context::parse(&ctx, "ℕ")); + r.create_branch(Context::parse(&ctx, "<PosInt 10 BigEndian>~<Seq <Digit 10>>")); + assert_eq!( r.descend(Context::parse(&ctx, "<PosInt 10 BigEndian>")).unwrap().read().unwrap().get_halo_type(), &Context::parse(&ctx, "ℕ") ); + assert_eq!( r.descend(Context::parse(&ctx, "<PosInt 10 BigEndian>~<Seq <Digit 10>>")).unwrap().read().unwrap().get_halo_type(), &Context::parse(&ctx, "ℕ~<PosInt 10 BigEndian>") ); +} + +#[test] +fn char_view() { + let ctx = Arc::new(RwLock::new(Context::new())); + crate::editors::digit::init_ctx( ctx.clone() ); + + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "<Digit 16>") ); + rt_digit.insert_leaf( + Context::parse(&ctx, "Char"), + ReprLeaf::from_singleton_buffer( SingletonBuffer::new('5') ) + ); + + //<><><><> + let mut digit_char_buffer = rt_digit + .descend( Context::parse(&ctx, "Char") ).unwrap() + .singleton_buffer::<char>(); + + assert_eq!( digit_char_buffer.get(), '5' ); + //<><><><> + + let digit_char_view = rt_digit + .descend(Context::parse(&ctx, "Char")).unwrap() + .view_char(); + + assert_eq!( digit_char_view.get_view().unwrap().get(), '5' ); + + + //<><><><> + // `Char-view` is correctly coupled to `char-buffer` + digit_char_buffer.set('2'); + assert_eq!( digit_char_view.get_view().unwrap().get(), '2' ); +} + +#[test] +fn digit_projection_char_to_u64() { + let ctx = Arc::new(RwLock::new(Context::new())); + crate::editors::digit::init_ctx( ctx.clone() ); + + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "<Digit 16>") ); + + rt_digit.insert_leaf( + Context::parse(&ctx, "Char"), + ReprLeaf::from_singleton_buffer( SingletonBuffer::new('5') ) + ); + + //<><><><> + // add another representation + + ctx.read().unwrap().apply_morphism( + rt_digit.clone(), + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<Digit 16>~Char"), + dst_type: Context::parse(&ctx, "<Digit 16>~ℤ_2^64~machine.UInt64") + } + ); + + let digit_u64_view = rt_digit + .descend(Context::parse(&ctx, "ℤ_2^64~machine.UInt64")).unwrap() + .view_u64(); + + assert_eq!( digit_u64_view.get_view().unwrap().get(), 5 as u64 ); + + + // projection behaves accordingly , when buffer is changed + + let mut digit_char_buffer = rt_digit + .descend( Context::parse(&ctx, "Char") ).unwrap() + .singleton_buffer::<char>(); + + digit_char_buffer.set('2'); + assert_eq!( digit_u64_view.get_view().unwrap().get(), 2 as u64 ); +} + +#[test] +fn digit_projection_u64_to_char() { + let ctx = Arc::new(RwLock::new(Context::new())); + crate::editors::digit::init_ctx( ctx.clone() ); + + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "<Digit 16>") ); + + rt_digit.insert_leaf( + Context::parse(&ctx, "ℤ_2^64~machine.UInt64"), + ReprLeaf::from_singleton_buffer( SingletonBuffer::new(5 as u64) ) + ); + + //<><><><> + // add another representation + + ctx.read().unwrap().apply_morphism( + rt_digit.clone(), + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<Digit 16>~ℤ_2^64~machine.UInt64"), + dst_type: Context::parse(&ctx, "<Digit 16>~Char") + } + ); + + let digit_u64_view = rt_digit + .descend(Context::parse(&ctx, "Char")).unwrap() + .view_char(); + + assert_eq!( digit_u64_view.get_view().unwrap().get(), '5' ); +} + + +#[test] +fn char_buffered_projection() { + let ctx = Arc::new(RwLock::new(Context::new())); + crate::editors::digit::init_ctx( ctx.clone() ); + + let mut rt_digit = ReprTree::new_arc( Context::parse(&ctx, "<Digit 16>") ); + + rt_digit.insert_leaf( + Context::parse(&ctx, "ℤ_2^64~machine.UInt64"), + ReprLeaf::from_singleton_buffer( SingletonBuffer::new(8 as u64) ) + ); + + let mut digit_u64_buffer = rt_digit + .descend(Context::parse(&ctx, "ℤ_2^64~machine.UInt64")).unwrap() + .singleton_buffer::<u64>(); + + assert_eq!( digit_u64_buffer.get(), 8 ); + + rt_digit.insert_leaf( + Context::parse(&ctx, "Char"), + ReprLeaf::from_singleton_buffer( SingletonBuffer::new('5') ) + ); + + let digit_char_buf = rt_digit + .descend(Context::parse(&ctx, "Char")).unwrap() + .singleton_buffer::<char>(); + let digit_char_view = rt_digit + .descend(Context::parse(&ctx, "Char")).unwrap() + .view_char(); + + // before setting up the morphism, char-view remains as initialized + assert_eq!( digit_char_buf.get(), '5' ); + assert_eq!( digit_char_view.get_view().unwrap().get(), '5' ); + + // now we attach the char-repr to the u64-repr + ctx.read().unwrap().apply_morphism( + rt_digit.clone(), + &laddertypes::MorphismType { + src_type: Context::parse(&ctx, "<Digit 16>~ℤ_2^64~machine.UInt64"), + dst_type: Context::parse(&ctx, "<Digit 16>~Char") + } + ); + + // char buffer and view should now follow the u64-buffer + assert_eq!( digit_char_view.get_view().unwrap().get(), '8' ); + assert_eq!( digit_char_buf.get(), '8' ); + + // now u64-buffer changes, and char-buffer should change accordingly + digit_u64_buffer.set(3); + assert_eq!( digit_u64_buffer.get(), 3 ); + + // char buffer should follow + digit_char_view.0.update(); + assert_eq!( digit_char_buf.get(), '3' ); + assert_eq!( digit_char_view.get_view().unwrap().get(), '3' ); +} + diff --git a/lib-nested-core/src/utils/mod.rs b/lib-nested-core/src/utils/mod.rs new file mode 100644 index 0000000..f97b6e5 --- /dev/null +++ b/lib-nested-core/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod modulo; +pub use modulo::modulo; diff --git a/nested/src/utils/modulo.rs b/lib-nested-core/src/utils/modulo.rs similarity index 100% rename from nested/src/utils/modulo.rs rename to lib-nested-core/src/utils/modulo.rs diff --git a/nested/Cargo.toml b/lib-nested-tty/Cargo.toml similarity index 58% rename from nested/Cargo.toml rename to lib-nested-tty/Cargo.toml index 8814165..0e5b412 100644 --- a/nested/Cargo.toml +++ b/lib-nested-tty/Cargo.toml @@ -1,24 +1,23 @@ [package] authors = ["Michael Sippel <micha@fragmental.art>"] -edition = "2018" -name = "nested" +name = "nested-tty" version = "0.1.0" +edition = "2018" [dependencies] -#r3vi = { git = "https://git.exobiont.de/senvas/lib-r3vi.git" } r3vi = { path = "../../lib-r3vi" } laddertypes = { path = "../../lib-laddertypes" } -no_deadlocks = "*" +nested = { path = "../lib-nested-core" } cgmath = { version = "0.18.0", features = ["serde"] } -termion = "2.0.1" +serde = { version = "1.0", features = ["serde_derive"] } +termion = "2.0.3" vte = "0.10.1" ansi_colours = "1.0" -signal-hook = "0.3.1" -signal-hook-async-std = "0.2.0" -serde = { version = "1.0", features = ["derive"] } -bincode = "1.3.3" -serde_json = "*" +signal-hook = "*" +signal-hook-async-std = "*" [dependencies.async-std] version = "1.9.0" features = ["unstable", "attributes"] + + diff --git a/nested/src/terminal/ansi_parser.rs b/lib-nested-tty/src/ansi_parser.rs similarity index 99% rename from nested/src/terminal/ansi_parser.rs rename to lib-nested-tty/src/ansi_parser.rs index 669ee06..399bf15 100644 --- a/nested/src/terminal/ansi_parser.rs +++ b/lib-nested-tty/src/ansi_parser.rs @@ -10,7 +10,8 @@ use { projection::projection_helper::ProjectionHelper, }, crate::{ - terminal::{TerminalAtom, TerminalStyle, TerminalView}, + atom::{TerminalAtom, TerminalStyle}, + TerminalView, }, cgmath::{Point2, Vector2}, std::io::Read, diff --git a/nested/src/terminal/atom.rs b/lib-nested-tty/src/atom/mod.rs similarity index 93% rename from nested/src/terminal/atom.rs rename to lib-nested-tty/src/atom/mod.rs index 2cd4d29..0bc55f1 100644 --- a/nested/src/terminal/atom.rs +++ b/lib-nested-tty/src/atom/mod.rs @@ -1,7 +1,7 @@ -use { - super::TerminalStyle, - serde::{Deserialize, Serialize}, -}; +pub mod style; +pub use style::TerminalStyle; + +use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub struct TerminalAtom { diff --git a/nested/src/terminal/style.rs b/lib-nested-tty/src/atom/style.rs similarity index 100% rename from nested/src/terminal/style.rs rename to lib-nested-tty/src/atom/style.rs diff --git a/nested/src/terminal/compositor.rs b/lib-nested-tty/src/compositor.rs similarity index 97% rename from nested/src/terminal/compositor.rs rename to lib-nested-tty/src/compositor.rs index d8a53e4..e0774d6 100644 --- a/nested/src/terminal/compositor.rs +++ b/lib-nested-tty/src/compositor.rs @@ -6,7 +6,7 @@ use { }, projection::projection_helper::*, }, - crate::{terminal::{TerminalAtom, TerminalView}}, + crate::{TerminalAtom, TerminalView}, cgmath::Point2, std::sync::Arc, std::sync::RwLock, diff --git a/nested/src/utils/color.rs b/lib-nested-tty/src/edit_tree/color.rs similarity index 96% rename from nested/src/utils/color.rs rename to lib-nested-tty/src/edit_tree/color.rs index 532a7fe..42f36fc 100644 --- a/nested/src/utils/color.rs +++ b/lib-nested-tty/src/edit_tree/color.rs @@ -1,5 +1,5 @@ use { - crate::terminal::TerminalStyle, + crate::atom::TerminalStyle, }; pub fn bg_style_from_depth(depth: usize) -> TerminalStyle { diff --git a/lib-nested-tty/src/edit_tree/cursor_widget.rs b/lib-nested-tty/src/edit_tree/cursor_widget.rs new file mode 100644 index 0000000..2504428 --- /dev/null +++ b/lib-nested-tty/src/edit_tree/cursor_widget.rs @@ -0,0 +1,33 @@ + +impl TreeNav { + fn get_cursor_widget(&self) -> OuterViewPort<dyn TerminalView> { + VecBuffer::with_data( + vec![ + make_label("@").with_fg_color((150, 80,230)), + self.get_addr_view() + .map(|i| + make_label(&format!("{}", i)).with_fg_color((0, 100, 20))) + .separate(make_label(".").with_fg_color((150, 80,230))) + .to_grid_horizontal() + .flatten(), + make_label(":").with_fg_color((150, 80,230)), + self.get_mode_view() + .map(|mode| { + make_label( + match mode { + ListCursorMode::Insert => "INSERT", + ListCursorMode::Select => "SELECT" + }) + .with_fg_color((200, 200, 20)) + }) + .to_grid() + .flatten(), + make_label(":").with_fg_color((150, 80,230)) + ] + ).get_port() + .to_sequence() + .to_grid_horizontal() + .flatten() + } +} + diff --git a/nested/src/diagnostics.rs b/lib-nested-tty/src/edit_tree/diagnostics.rs similarity index 82% rename from nested/src/diagnostics.rs rename to lib-nested-tty/src/edit_tree/diagnostics.rs index c1230c5..6ffad73 100644 --- a/nested/src/diagnostics.rs +++ b/lib-nested-tty/src/edit_tree/diagnostics.rs @@ -1,27 +1,3 @@ -use { - r3vi::{ - view::{OuterViewPort, sequence::*}, - buffer::{vec::*, index_hashmap::*} - }, - crate::{ - terminal::{ - TerminalView, TerminalStyle, make_label - } - }, - cgmath::Point2 -}; - -#[derive(Clone)] -pub struct Message { - pub addr: Vec<usize>, - pub port: OuterViewPort<dyn TerminalView> -} - -pub trait Diagnostics { - fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { - VecBuffer::new().get_port().to_sequence() - } -} pub fn make_error(msg: OuterViewPort<dyn TerminalView>) -> Message { let mut mb = IndexBuffer::new(); diff --git a/lib-nested-tty/src/edit_tree/keymap.rs b/lib-nested-tty/src/edit_tree/keymap.rs new file mode 100644 index 0000000..09a3609 --- /dev/null +++ b/lib-nested-tty/src/edit_tree/keymap.rs @@ -0,0 +1,110 @@ +use { + termion::event::{Event, Key}, + r3vi::{ + buffer::singleton::* + }, + nested::{ + repr_tree::{Context, ReprTree}, + editors::list::ListCmd, + edit_tree::nav::TreeNavCmd + }, + crate::{ + TerminalEvent + }, + std::sync::{Arc, RwLock} +}; + +fn neo2_treenav_keymap( key: &Key ) -> Option<TreeNavCmd> { + match key { + Key::Ctrl(c) => { + match c { + + // left hand + 'l' => Some(TreeNavCmd::up), + 'i' => Some(TreeNavCmd::qnexd), + 'a' => Some(TreeNavCmd::dn), + 'e' => Some(TreeNavCmd::pxev), + + // right hand + 'n' => Some(TreeNavCmd::nexd), + 'r' => Some(TreeNavCmd::dn_pxev), + 't' => Some(TreeNavCmd::qnexd), + 'g' => Some(TreeNavCmd::up_nexd), + + _ => None + } + } + _ => None + } +} + +fn universal_treenav_keymap( key: &Key ) -> Option<TreeNavCmd> { + match key { + Key::Left => Some(TreeNavCmd::pxev), + Key::Right => Some(TreeNavCmd::nexd), + Key::Up => Some(TreeNavCmd::up), + Key::Down => Some(TreeNavCmd::dn), + Key::Home => Some(TreeNavCmd::qpxev), + Key::End => Some(TreeNavCmd::qnexd), + Key::PageUp => Some(TreeNavCmd::up_nexd), + Key::PageDown => Some(TreeNavCmd::pxev_dn_qnexd), + _ => None + } +} + +fn tty_list_keymap( key: &Key ) -> Option<ListCmd> { + match key { +// Key::Char('\t') => Some( ListCmd::ToggleLeafMode ), + + Key::Backspace => Some( ListCmd::DeletePxev ), + Key::Delete => Some( ListCmd::DeleteNexd ), + + _ => None + } +} + +impl TerminalEvent { + pub fn to_repr_tree( &self, ctx: &Arc<RwLock<Context>> ) -> Arc<RwLock<ReprTree>> { + match self { + TerminalEvent::Input(Event::Key(key)) => { + if let Some(tree_nav_cmd) = neo2_treenav_keymap(key) { + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "TreeNavCmd"), + SingletonBuffer::new(tree_nav_cmd) + ) + } else if let Some(tree_nav_cmd) = universal_treenav_keymap(key) { + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "TreeNavCmd"), + SingletonBuffer::new(tree_nav_cmd) + ) + } else { + if let Some(list_cmd) = tty_list_keymap(key) { + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "ListCmd"), + SingletonBuffer::new(list_cmd) + ) + } else { + match key { + Key::Char(c) => { + ReprTree::from_char(&ctx, *c) + } + _ => { + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "TerminalEvent"), + SingletonBuffer::new(self.clone()) + ) + } + } + } + } + } + _ => { + ReprTree::from_singleton_buffer( + Context::parse(&ctx, "TerminalEvent"), + SingletonBuffer::new(self.clone()) + ) + } + } + } +} + diff --git a/lib-nested-tty/src/edit_tree/mod.rs b/lib-nested-tty/src/edit_tree/mod.rs new file mode 100644 index 0000000..fdf1de4 --- /dev/null +++ b/lib-nested-tty/src/edit_tree/mod.rs @@ -0,0 +1,4 @@ + +pub mod color; +pub mod keymap; + diff --git a/lib-nested-tty/src/editors/char.rs b/lib-nested-tty/src/editors/char.rs new file mode 100644 index 0000000..e69de29 diff --git a/nested/src/editors/list/pty_editor.rs b/lib-nested-tty/src/editors/list.rs similarity index 57% rename from nested/src/editors/list/pty_editor.rs rename to lib-nested-tty/src/editors/list.rs index 829aef4..e55172c 100644 --- a/nested/src/editors/list/pty_editor.rs +++ b/lib-nested-tty/src/editors/list.rs @@ -3,13 +3,17 @@ use { view::{ViewPort, OuterViewPort, sequence::*}, projection::decorate_sequence::*, }, - crate::{ - type_system::{Context, ReprTree}, + nested::{ + repr_tree::{Context, ReprTree}, editors::list::*, - terminal::{TerminalEvent, TerminalView, make_label}, - tree::{TreeCursor, TreeNav, TreeNavResult}, - tree::NestedNode, - PtySegment + edit_tree::{TreeCursor, TreeNav, TreeNavResult, EditTree}, + repr_tree::{ReprTreeExt, ReprLeaf} + }, + crate::{ + DisplaySegment, + TerminalStyle, + TerminalEvent, TerminalView, make_label, + edit_tree::color::{bg_style_from_depth, fg_style_from_depth} }, std::sync::{Arc, RwLock}, termion::event::{Event, Key} @@ -17,6 +21,41 @@ use { //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> +impl DisplaySegment for ListSegment { + fn display_view(&self) -> OuterViewPort<dyn TerminalView> { + match self { + ListSegment::InsertCursor => { + make_label("|") + .map_item(move |_pt, atom| { + atom.add_style_front(TerminalStyle::fg_color((150,80,230))) + .add_style_front(TerminalStyle::bold(true)) + }) + } + ListSegment::Item{ editor, cur_dist } => { + let e = editor.clone(); + let cur_dist = *cur_dist; + editor.display_view().map_item(move |_pt, atom| { + let c = e.get_cursor(); + let cur_depth = c.tree_addr.len(); + let select = + if cur_dist == 0 { + cur_depth + } else { + usize::MAX + }; + + atom + .add_style_back(bg_style_from_depth(select)) + .add_style_back(TerminalStyle::bold(select==1)) + .add_style_back(fg_style_from_depth(e.disp.depth.get_view().get())) + }) + } + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + pub struct PTYListStyle { style: (String, String, String) } @@ -34,7 +73,7 @@ impl PTYListStyle { editor.get_data_port() ); let se = seg_seq.read().unwrap(); - se.get_view().map(move |segment| segment.pty_view()) + se.get_view().map(move |segment| segment.display_view()) } pub fn pty_view(&self, editor: &ListEditor) -> OuterViewPort<dyn TerminalView> { @@ -42,24 +81,28 @@ impl PTYListStyle { editor.get_cursor_port(), editor.get_data_port() ); - let seg_seq = seg_seq.read().unwrap(); + + let seg_seq0 = seg_seq.read().unwrap(); + let seg_seq = seg_seq0.get_view(); + drop(seg_seq0); seg_seq - .get_view() - .map(move |segment| segment.pty_view()) + .map(move |segment| segment.display_view()) .separate(make_label(&self.style.1)) .wrap(make_label(&self.style.0), make_label(&self.style.2)) .to_grid_horizontal() .flatten() } - pub fn for_node(node: &mut NestedNode, style: (&str, &str, &str)) { - node.view = Some( - Self::new(style) - .pty_view( - &node.get_edit::<ListEditor>().unwrap().read().unwrap() - ) - ); + pub fn for_node(node: &mut EditTree, style: (&str, &str, &str)) { + let editor = node.get_edit::<ListEditor>().unwrap(); + let editor = editor.read().unwrap(); + let pty_view = Self::new(style).pty_view(&editor); + node.disp.view + .attach_leaf_to( + Context::parse(&node.ctx, "TerminalView"), + pty_view + ); } } @@ -94,10 +137,11 @@ impl PTYListController { } pub fn for_node( - node: &mut NestedNode, + node: &mut EditTree, split_char: Option<char>, close_char: Option<char> ) { +/* { let ctx = node.ctx.as_ref(); let mut ctx = ctx.write().unwrap(); @@ -109,15 +153,15 @@ impl PTYListController { ctx.meta_chars.push(*c); } } - +*/ let editor = node.get_edit::<ListEditor>().unwrap(); - let controller = Arc::new(RwLock::new(PTYListController::from_editor( editor, split_char, close_char, node.depth.clone() ))); + let controller = Arc::new(RwLock::new(PTYListController::from_editor( editor, split_char, close_char, node.disp.depth.clone() ))); - node.cmd.set(Some(controller.clone())); - node.close_char.set(close_char); + node.ctrl.cmd.set(Some(controller.clone())); + node.ctrl.close_char.set(close_char); } - pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = NestedNode>> { + pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = EditTree>> { self.editor.read().unwrap().get_data_port() } @@ -125,31 +169,38 @@ impl PTYListController { self.editor.write().unwrap().clear(); } - pub fn get_item(&self) -> Option<NestedNode> { + pub fn get_item(&self) -> Option<EditTree> { self.editor.read().unwrap().get_item() } - pub fn handle_term_event(&mut self, event: &TerminalEvent, _cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { + pub fn handle_term_event(&mut self, event: &TerminalEvent, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { let mut e = self.editor.write().unwrap(); match event { TerminalEvent::Input(Event::Key(Key::Insert)) => { e.toggle_leaf_mode(); TreeNavResult::Continue } - _ => TreeNavResult::Continue - } + TerminalEvent::Input(Event::Key(Key::Char(c))) => { + let ctx = e.ctx.clone(); + drop(e); + self.handle_any_event( + ReprTree::from_char(&ctx, *c) + ) + } + _ => TreeNavResult::Continue + } } pub fn handle_meta_char(&mut self, c: char, child_close_char: Option<char>) -> TreeNavResult { - eprintln!("handle meta char: got '{}', child_close={:?}, self.close={:?}, split={:?}", c, child_close_char, self.close_char, self.split_char); +// eprintln!("handle meta char: got '{}', child_close={:?}, self.close={:?}, split={:?}", c, child_close_char, self.close_char, self.split_char); let mut e = self.editor.write().unwrap(); let cur = e.cursor.get(); - + if Some(c) == self.split_char // || Some(c) == child_close_char { e.listlist_split(); - eprintln!("done listlist split"); + // eprintln!("done listlist split"); TreeNavResult::Continue } else if Some(c) == child_close_char { e.goto(TreeCursor::none()); @@ -171,23 +222,47 @@ impl PTYListController { match cur.mode { ListCursorMode::Insert => { - let mut new_edit = Context::make_node(&e.ctx, e.typ.clone(), self.depth.map(|d| d+1)).unwrap(); - new_edit.goto(TreeCursor::home()); + let rt = ReprTree::new_arc(e.typ.clone()); - match new_edit.send_cmd_obj(cmd_obj.clone()) { - TreeNavResult::Continue => { - e.insert(Arc::new(RwLock::new(new_edit.clone()))); - TreeNavResult::Continue + let src_ladder = laddertypes::TypeTerm::Ladder(vec![ + rt.read().unwrap().get_type().clone() + ]); + let dst_ladder = laddertypes::TypeTerm::Ladder(vec![ + rt.read().unwrap().get_type().clone(), + ctx.type_term_from_str("EditTree").expect("") + ]); + ctx.apply_morphism( + &rt, + &laddertypes::MorphismType { + src_type: src_ladder, + dst_type: dst_ladder } - TreeNavResult::Exit => { - TreeNavResult::Exit + ); + + let new_edittree = ctx.setup_edittree( &rt ); + + if let Some(new_edittree) = new_edittree { + let mut ne = new_edittree.get(); + let mut ne = ne.write().unwrap(); + match ne.send_cmd_obj(cmd_obj.clone()) { + TreeNavResult::Continue => { + drop(ne); + e.insert(new_edittree.value.read().unwrap().clone()); + TreeNavResult::Continue + } + TreeNavResult::Exit => { + TreeNavResult::Exit + } } + } else { + panic!("cant get edit tree"); + TreeNavResult::Continue } }, ListCursorMode::Select => { if let Some(item) = e.get_item_mut() { let res = item.write().unwrap().send_cmd_obj(cmd_obj.clone()); - let child_close_char = item.read().unwrap().close_char.get(); + let child_close_char = item.read().unwrap().ctrl.close_char.get(); match res { TreeNavResult::Continue => TreeNavResult::Continue, @@ -218,7 +293,7 @@ impl PTYListController { } use r3vi::view::singleton::SingletonView; -use crate::commander::ObjCommander; +use nested::editors::ObjCommander; impl ObjCommander for PTYListController { fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { @@ -226,7 +301,7 @@ impl ObjCommander for PTYListController { let cmd_type = cmd_obj.read().unwrap().get_type().clone(); if cmd_type == Context::parse(&e.ctx, "ListCmd").into() - || cmd_type == Context::parse(&e.ctx, "NestedNode").into() + || cmd_type == Context::parse(&e.ctx, "EditTree").into() { e.send_cmd_obj( cmd_obj ) } diff --git a/lib-nested-tty/src/editors/mod.rs b/lib-nested-tty/src/editors/mod.rs new file mode 100644 index 0000000..669aab7 --- /dev/null +++ b/lib-nested-tty/src/editors/mod.rs @@ -0,0 +1,85 @@ + +pub mod list; + +use { + nested::{ + edit_tree::{EditTree}, + repr_tree::{ReprTree, Context} + }, + r3vi::{ + view::{singleton::*, sequence::*}, + projection::decorate_sequence::* + }, + crate::{ + make_label, + DisplaySegment, + atom::{TerminalAtom, TerminalStyle} + } +}; + +pub fn edittree_make_char_view( + node: EditTree +) -> EditTree { + node.disp.view + .write().unwrap() + .insert_branch(ReprTree::from_view( + Context::parse(&node.ctx, "TerminalView"), + node.get_edit::< nested::editors::char::CharEditor >() + .unwrap() + .read() + .unwrap() + .get_port() + .map(move |c| TerminalAtom::from(if c == '\0' { ' ' } else { c })) + .to_grid() + )); + + node +} + +pub fn edittree_make_digit_view( + node: EditTree +) -> EditTree { + node.disp.view + .write().unwrap() + .insert_branch(ReprTree::from_view( + Context::parse(&node.ctx, "TerminalView"), + node.get_edit::< nested::editors::digit::DigitEditor >() + .unwrap() + .read() + .unwrap() + .get_data_port() + .map(move |digit| + match digit { + Ok(digit) => TerminalAtom::new( char::from_digit(digit, 16).unwrap_or('?'), TerminalStyle::fg_color((220, 220, 0)) ), + Err(c) => TerminalAtom::new( c, TerminalStyle::fg_color((220, 0, 0)) ) + } + ) + .to_grid() + )); + + node +} + +/* +pub fn edittree_make_seq_view( + mut node: EditTree +) -> EditTree { + node.disp.view + .write().unwrap() + .insert_branch(ReprTree::new_leaf( + Context::parse(&node.ctx, "TerminalView"), + node.get_edit::< nested::editors::list::ListEditor >() + .unwrap() + .read().unwrap() + .get_data_port() + .map(move |item_edittree| + edittree_make_tty_view( item_edittree ).display_view() + ) + .wrap(make_label("("), make_label(")")) + .to_grid_horizontal() + .flatten() + .into() + )); + node +} +*/ diff --git a/lib-nested-tty/src/editors/product.rs b/lib-nested-tty/src/editors/product.rs new file mode 100644 index 0000000..e69de29 diff --git a/lib-nested-tty/src/editors/singleton.rs b/lib-nested-tty/src/editors/singleton.rs new file mode 100644 index 0000000..e69de29 diff --git a/lib-nested-tty/src/editors/sum.rs b/lib-nested-tty/src/editors/sum.rs new file mode 100644 index 0000000..626f249 --- /dev/null +++ b/lib-nested-tty/src/editors/sum.rs @@ -0,0 +1,8 @@ + + +impl PtySegment for SumEditor { + fn pty_view(&self) -> OuterViewPort<dyn TerminalView> { + self.port.outer() + } +} + diff --git a/lib-nested-tty/src/lib.rs b/lib-nested-tty/src/lib.rs new file mode 100644 index 0000000..0e12095 --- /dev/null +++ b/lib-nested-tty/src/lib.rs @@ -0,0 +1,180 @@ + +#![feature(trait_alias)] + +// <<<<>>>><<>><><<>><<< * >>><<>><><<>><<<<>>>> \\ + +pub mod atom; + +pub mod compositor; +pub mod ansi_parser; + +pub mod terminal; +pub mod tty_application; + +pub mod editors; +pub mod edit_tree; +//pub mod widgets; + +// <<<<>>>><<>><><<>><<< * >>><<>><><<>><<<<>>>> \\ + +pub use { + atom::{TerminalAtom, TerminalStyle}, + terminal::{Terminal, TerminalEvent}, + tty_application::TTYApplication, + compositor::TerminalCompositor, +}; + +use r3vi::view::grid::*; + +// <<<<>>>><<>><><<>><<< * >>><<>><><<>><<<<>>>> \\ + +pub trait TerminalView = GridView<Item = TerminalAtom>; + +// <<<<>>>><<>><><<>><<< * >>><<>><><<>><<<<>>>> \\ + +use r3vi::view::OuterViewPort; + +pub trait DisplaySegment { + fn display_view(&self) -> OuterViewPort<dyn TerminalView>; +} + + +use nested::repr_tree::{Context, ReprTreeExt}; +use std::sync::{Arc, RwLock}; + +impl DisplaySegment for nested::edit_tree::EditTree { + fn display_view(&self) -> OuterViewPort<dyn TerminalView> { + if let Some( tv_repr ) = self.disp.view + .descend( Context::parse(&self.ctx, "TerminalView") ) + { + if let Some(port) = + tv_repr + .read().unwrap() + .get_port::<dyn TerminalView>() { + port + } + + else { + make_label("# could not get ViewPort #") + } + } else { + make_label("# No TTY View available #") + .map_item(|_p,a| a.add_style_back(TerminalStyle::fg_color((220, 30, 30)))) + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +use { + r3vi::{ + buffer::vec::*, + }, + cgmath::Point2, +}; + +pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> { + let label = VecBuffer::with_data(s.chars().collect()); + + let v = label.get_port() + .to_sequence() + .map(|c| TerminalAtom::from(c)) + .to_index() + .map_key( + |idx| Point2::new(*idx as i16, 0), + |pt| if pt.y == 0 { Some(pt.x as usize) } else { None }, + ); + + v +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub trait TerminalProjections { + fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView>; + fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>; + fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>; +} + +impl TerminalProjections for OuterViewPort<dyn TerminalView> { + fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> { + self.map_item( + move |_idx, a| + a.add_style_front(style) + ) + } + + fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> { + self.with_style(TerminalStyle::fg_color(col)) + } + + fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> { + self.with_style(TerminalStyle::bg_color(col)) + } +} + + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub fn setup_edittree_hook(ctx: &Arc<RwLock<Context>>) { + + let char_type = Context::parse(&ctx, "Char"); + let digit_type = Context::parse(&ctx, "<Digit Radix>"); + let list_type = Context::parse(&ctx, "<List Item>"); + let posint_bin_type = Context::parse(&ctx, "<PosInt 2 BigEndian>"); + let posint_oct_type = Context::parse(&ctx, "<PosInt 8 BigEndian>"); + let posint_dec_type = Context::parse(&ctx, "<PosInt 10 BigEndian>"); + let posint_hex_type = Context::parse(&ctx, "<PosInt 16 BigEndian>"); + 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| { + 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_bin_type) { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("0b", "", "")); + crate::editors::list::PTYListController::for_node( &mut *et, None, None ); + } + else if let Ok(σ) = laddertypes::unify(&t, &posint_oct_type) { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("0o", "", "")); + crate::editors::list::PTYListController::for_node( &mut *et, None, None ); + } + else if let Ok(σ) = laddertypes::unify(&t, &posint_dec_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, &posint_hex_type) { + crate::editors::list::PTYListStyle::for_node( &mut *et, ("0x", "", "")); + 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()); + } + } + ) + ); + +} + diff --git a/nested/src/terminal/terminal.rs b/lib-nested-tty/src/terminal.rs similarity index 98% rename from nested/src/terminal/terminal.rs rename to lib-nested-tty/src/terminal.rs index c03e588..4cfa510 100644 --- a/nested/src/terminal/terminal.rs +++ b/lib-nested-tty/src/terminal.rs @@ -7,7 +7,8 @@ use { index::*, } }, - super::{TerminalStyle, TerminalView}, + crate::atom::{TerminalStyle}, + crate::{TerminalView}, async_std::{stream::StreamExt, task}, cgmath::{Point2, Vector2}, signal_hook, @@ -24,7 +25,7 @@ use { }, }; -#[derive(PartialEq, Eq, Clone)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum TerminalEvent { Resize(Vector2<i16>), Input(termion::event::Event), diff --git a/lib-nested-tty/src/tty_application.rs b/lib-nested-tty/src/tty_application.rs new file mode 100644 index 0000000..aade2bb --- /dev/null +++ b/lib-nested-tty/src/tty_application.rs @@ -0,0 +1,71 @@ +use { + cgmath::Vector2, + nested::{ + edit_tree::EditTree, + repr_tree::{Context, ReprTree}, + }, + crate::{ + terminal::TermOutWriter, DisplaySegment, Terminal, TerminalAtom, TerminalCompositor, + TerminalEvent, TerminalStyle, TerminalView, + }, + r3vi::{ + buffer::singleton::*, + view::{port::UpdateTask, singleton::*, ViewPort}, + }, + std::sync::{Arc, Mutex, RwLock}, + termion::event::{Event, Key}, +}; + +pub struct TTYApplication { + pub port: ViewPort<dyn TerminalView>, + term_writer: Arc<TermOutWriter>, +} + +impl TTYApplication { + pub fn new(event_handler: impl Fn(TerminalEvent) + Send + Sync + 'static) -> Self { + let port = ViewPort::new(); + let portmutex = Mutex::new(()); + let term = Terminal::new(port.outer()); + let term_writer = term.get_writer(); + + async_std::task::spawn(TTYApplication::event_loop(term, port.clone(), Arc::new(event_handler))); + async_std::task::spawn(TTYApplication::update_loop(port.clone())); + + TTYApplication { + port, + term_writer, + } + } + + /* this task handles all terminal events (e.g. key press, resize) + */ + async fn event_loop(mut term: Terminal, port: ViewPort<dyn TerminalView>, event_handler: Arc<dyn Fn(TerminalEvent) + Send + Sync>) { + loop { + let ev = term.next_event().await; + if ev == TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) { + break; + } + + event_handler( ev ); + port.update(); + } + } + + /* this task will continuously pull forward + * all notifications which are influencing + * the view in `term_port` + */ + async fn update_loop(port: ViewPort<dyn TerminalView>) { + loop { + port.update(); + async_std::task::sleep(std::time::Duration::from_millis(50)).await; + } + } + + /* write the changes in the view of `term_port` to the terminal + */ + pub async fn show(&self) -> Result<(), std::io::Error> { + self.term_writer.show().await + } +} + diff --git a/nested/src/terminal/widgets/ascii_box.rs b/lib-nested-tty/src/widgets/ascii_box.rs similarity index 100% rename from nested/src/terminal/widgets/ascii_box.rs rename to lib-nested-tty/src/widgets/ascii_box.rs diff --git a/nested/src/terminal/widgets/mod.rs b/lib-nested-tty/src/widgets/mod.rs similarity index 100% rename from nested/src/terminal/widgets/mod.rs rename to lib-nested-tty/src/widgets/mod.rs diff --git a/nested/src/terminal/widgets/monstera.rs b/lib-nested-tty/src/widgets/monstera.rs similarity index 100% rename from nested/src/terminal/widgets/monstera.rs rename to lib-nested-tty/src/widgets/monstera.rs diff --git a/nested/src/terminal/widgets/plot.rs b/lib-nested-tty/src/widgets/plot.rs similarity index 100% rename from nested/src/terminal/widgets/plot.rs rename to lib-nested-tty/src/widgets/plot.rs diff --git a/math/fib/Cargo.toml b/math/fib/Cargo.toml deleted file mode 100644 index 7f4efbb..0000000 --- a/math/fib/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "fib" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -nested = { path = "../../nested" } diff --git a/math/fib/src/main.rs b/math/fib/src/main.rs deleted file mode 100644 index b528448..0000000 --- a/math/fib/src/main.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::{ - fs::File, - io::{Read, Write}, - os::unix::io::FromRawFd, -}; - -fn fib(n: u64) -> u64 { - let mut y = 0; - let mut y1 = 1; - let mut y2 = 0; - - for _ in 0..n { - y = y1 + y2; - y2 = y1; - y1 = y; - } - - y -} - -fn main() { - nested::magic_header(); - - eprintln!(" Fibonacci Sequence"); - - nested::magic_header(); - - eprintln!( - " -interface (Sequence ℕ) 0 1" - ); - - let mut f0 = unsafe { File::from_raw_fd(0) }; - eprintln!( - " ->0: n - ( ℕ ) - ( MachineInt ) - ( MachineWord ) - ( Stream MachineSyllab ) -" - ); - - let mut f1 = unsafe { File::from_raw_fd(1) }; - eprintln!( - " -<1: n'th fibonacci number - ( ℕ ) - ( MachineInt ) - ( MachineWord ) - ( Stream MachineSyllab ) -" - ); - - nested::magic_header(); - - let mut bytes = [0 as u8; 8]; - f0.read_exact(&mut bytes).expect(""); - let n = u64::from_le_bytes(bytes); - bytes = fib(n).to_le_bytes(); - f1.write(&bytes).expect(""); -} diff --git a/math/int2str/Cargo.toml b/math/int2str/Cargo.toml deleted file mode 100644 index cdac039..0000000 --- a/math/int2str/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "int2str" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -nested = { path = "../../nested" } diff --git a/math/int2str/src/main.rs b/math/int2str/src/main.rs deleted file mode 100644 index 00cc669..0000000 --- a/math/int2str/src/main.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{fs::File, io::Read, os::unix::io::FromRawFd}; - -fn main() { - nested::magic_header(); - eprintln!(" Human-readably Print MachineInt"); - nested::magic_header(); - - let mut f0 = unsafe { File::from_raw_fd(0) }; - eprintln!( - " ->0: - ( ℕ ) - ( MachineInt ) - ( MachineWord ) - ( Stream MachineSyllab ) -" - ); - - eprintln!( - " -<1: - ( ℕ ) - ( PositionalInt 10 BigEndian ) - ( Sequence ( Digit 10 ) ) - ( Sequence UTF-8-Char ) - ( Stream UTF-8-Char ) - ( Stream MachineSyllab ) -" - ); - - nested::magic_header(); - - let mut bytes = [0 as u8; 8]; - f0.read_exact(&mut bytes).expect(""); - println!("{}", u64::from_le_bytes(bytes)); -} diff --git a/math/radix_transform/src/main.rs b/math/radix_transform/src/main.rs deleted file mode 100644 index b1b48ff..0000000 --- a/math/radix_transform/src/main.rs +++ /dev/null @@ -1,137 +0,0 @@ -use nested::{ - core::{TypeDict, ViewPort}, - integer::RadixProjection, - vec::VecBuffer, -}; - -#[async_std::main] -async fn main() { - let mut td = TypeDict::new(); - for tn in vec![ - "MachineWord", - "MachineInt", - "MachineSyllab", - "Vec", - "Stream", - "Json", - "Sequence", - "UTF-8-Char", - "PositionalInt", - "Digit", - "LittleEndian", - "BigEndian", - "DiffStream", - "ℕ", - "$src_radix", - "$dst_radix", - ] { - td.add_typename(tn.into()); - } - - let radix_types = vec![ - td.type_term_from_str("( ℕ )").unwrap(), - td.type_term_from_str("( PositionalInt 10 LittleEndian )") - .unwrap(), - td.type_term_from_str("( Sequence ( Digit 10 ) )").unwrap(), - td.type_term_from_str("( Sequence UTF-8-Char )").unwrap(), - td.type_term_from_str("( Sequence MachineSyllab )").unwrap(), - ]; - - let src_types = vec![ - td.type_term_from_str("( ℕ )").unwrap(), - td.type_term_from_str("( PositionalInt $src_radix LittleEndian )") - .unwrap(), - td.type_term_from_str("( Sequence ( Digit $src_radix ) )") - .unwrap(), - td.type_term_from_str("( Sequence MachineInt )").unwrap(), - td.type_term_from_str("( DiffStream ( Vec MachineInt ) )") - .unwrap(), - td.type_term_from_str("( Json )").unwrap(), - td.type_term_from_str("( Stream UTF-8-Char )").unwrap(), - td.type_term_from_str("( Stream MachineSyllab )").unwrap(), - ]; - - let dst_types = vec![ - td.type_term_from_str("( ℕ )").unwrap(), - td.type_term_from_str("( PositionalInt $dst_radix LittleEndian )") - .unwrap(), - td.type_term_from_str("( Sequence ( Digit $dst_radix ) )") - .unwrap(), - td.type_term_from_str("( Sequence MachineInt )").unwrap(), - td.type_term_from_str("( DiffStream ( Vec MachineInt ) )") - .unwrap(), - td.type_term_from_str("( Json )").unwrap(), - td.type_term_from_str("( Stream UTF-8-Char )").unwrap(), - td.type_term_from_str("( Stream MachineSyllab )").unwrap(), - ]; - - nested::magic_header(); - eprintln!(" Convert Radix of Positional Integer"); - nested::magic_header(); - - eprintln!("\n$1: src_radix"); - for t in radix_types.iter() { - eprintln!(" {}", td.type_term_to_str(t)); - } - - eprintln!("\n$2: dst_radix"); - for t in radix_types.iter() { - eprintln!(" {}", td.type_term_to_str(t)); - } - - eprintln!("\n>0: n"); - for t in src_types.iter() { - eprintln!(" {}", td.type_term_to_str(t)); - } - - eprintln!("\n<1: n"); - for t in dst_types.iter() { - eprintln!(" {}", td.type_term_to_str(t)); - } - - nested::magic_header(); - - let mut args = std::env::args(); - args.next().expect("Arg $0 missing!"); - - let src_radix_str = args.next().expect("Arg $1 required!"); - let dst_radix_str = args.next().expect("Arg $2 required!"); - - let src_radix = usize::from_str_radix(&src_radix_str, 10).expect("could not parse src_radix"); - let dst_radix = usize::from_str_radix(&dst_radix_str, 10).expect("could not parse dst_radix"); - - assert!(src_radix > 1); - assert!(dst_radix > 1); - - let src_digits_port = ViewPort::new(); - let dst_digits_port = ViewPort::new(); - - let mut src_digits = VecBuffer::<usize>::new(src_digits_port.inner()); - - let _proj = RadixProjection::new( - src_radix, - dst_radix, - src_digits_port.outer().to_sequence(), - dst_digits_port.inner(), - ); - - // output dst digits - let writer = { - use std::os::unix::io::FromRawFd; - - dst_digits_port - .outer() - .serialize_json(unsafe { std::fs::File::from_raw_fd(1) }) - }; - - // start reading src digits - { - use async_std::os::unix::io::FromRawFd; - - src_digits - .from_json(unsafe { async_std::fs::File::from_raw_fd(0) }) - .await; - } - - drop(writer); -} diff --git a/math/str2int/Cargo.toml b/math/str2int/Cargo.toml deleted file mode 100644 index b85bed6..0000000 --- a/math/str2int/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "str2int" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -nested = { path = "../../nested" } diff --git a/math/str2int/src/main.rs b/math/str2int/src/main.rs deleted file mode 100644 index fa900b5..0000000 --- a/math/str2int/src/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::{ - fs::File, - io::{Read, Write}, - os::unix::io::FromRawFd, -}; - -fn main() { - nested::magic_header(); - eprintln!(" Parse MachineInt from String"); - nested::magic_header(); - - eprintln!( - " -$1: radix - ( ℕ ) - ( PositionalInt 10 BigEndian ) - ( Sequence ( Digit 10 ) ) - ( Sequence UTF-8-Char ) - ( Sequence MachineSyllab ) -" - ); - - eprintln!( - " ->0: n - ( ℕ ) - ( PositionalInt $radix BigEndian ) - ( Sequence ( Digit $radix ) ) - ( Sequence UTF-8-Char ) - ( Stream UTF-8-Char ) - ( Stream MachineSyllab ) -" - ); - - eprintln!( - " -<1: n - ( ℕ ) - ( MachineInt ) - ( MachineWord ) - ( Stream MachineSyllab ) -" - ); - - nested::magic_header(); - - let mut f0 = unsafe { File::from_raw_fd(0) }; - let mut f1 = unsafe { File::from_raw_fd(1) }; - - let mut args = std::env::args(); - args.next().expect("Arg $0 missing!"); - - let radix_str = args.next().expect("Arg $1 required!"); - - let radix = u32::from_str_radix(&radix_str, 10).expect("could not parse radix"); - if radix > 16 { - panic!("invalid radix! (radix<=16 required)"); - } - - let mut chars = Vec::new(); - f0.read_to_end(&mut chars).expect(""); - chars.retain(|c| (*c as char).is_alphanumeric()); - f1.write( - &u64::from_str_radix(&String::from_utf8_lossy(&chars), radix) - .unwrap() - .to_le_bytes(), - ) - .expect(""); -} diff --git a/nested/src/editors/char/mod.rs b/nested/src/editors/char/mod.rs deleted file mode 100644 index 2521cb1..0000000 --- a/nested/src/editors/char/mod.rs +++ /dev/null @@ -1,102 +0,0 @@ -use { - r3vi::{ - view::{ - OuterViewPort, - singleton::*, - }, - buffer::singleton::* - }, - laddertypes::{TypeTerm}, - crate::{ - type_system::{Context, ReprTree}, - terminal::{TerminalAtom}, - tree::{NestedNode, TreeNavResult}, - commander::{ObjCommander} - }, - std::sync::Arc, - std::sync::RwLock -}; - -pub fn init_ctx( ctx: &mut Context ) { - ctx.add_node_ctor( - "Char", - Arc::new(|ctx: Arc<RwLock<Context>>, _ty: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>| { - Some(CharEditor::new_node(ctx, depth)) - })); -} - -pub struct CharEditor { - ctx: Arc<RwLock<Context>>, - data: SingletonBuffer<char> -} - -impl ObjCommander for CharEditor { - fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { - let cmd_obj = cmd_obj.read().unwrap(); - let cmd_type = cmd_obj.get_type().clone(); - - if cmd_type == Context::parse(&self.ctx, "Char") { - if let Some(cmd_view) = cmd_obj.get_view::<dyn SingletonView<Item = char>>() { - let value = cmd_view.get(); - - if self.ctx.read().unwrap().meta_chars.contains(&value) { - TreeNavResult::Exit - } else { - self.data.set(value); - TreeNavResult::Continue - } - } else { - TreeNavResult::Exit - } - } else { - TreeNavResult::Exit - } - } -} - -impl CharEditor { - pub fn new(ctx: Arc<RwLock<Context>>) -> Self { - CharEditor { - ctx, - data: SingletonBuffer::new('\0') - } - } - - pub fn get_port(&self) -> OuterViewPort<dyn SingletonView<Item = char>> { - self.data.get_port() - } - - pub fn get(&self) -> char { - self.get_port().get_view().unwrap().get() - } - - pub fn new_node(ctx0: Arc<RwLock<Context>>, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> NestedNode { - let data = SingletonBuffer::new('\0'); - let ctx = ctx0.clone(); - let editor = Arc::new(RwLock::new(CharEditor{ ctx, data: data.clone() })); - - NestedNode::new( - ctx0.clone(), - ReprTree::new_leaf( - ctx0.read().unwrap().type_term_from_str("Char").unwrap(), - data.get_port().into() - ), - depth - ) - .set_view(data - .get_port() - .map(move |c| TerminalAtom::from(if c == '\0' { ' ' } else { c })) - .to_grid() - ) - .set_cmd( editor.clone() ) - .set_editor( editor.clone() ) - } -} -/* -use crate::StringGen; -impl StringGen for CharEditor { - fn get_string(&self) -> String { - String::from(self.get()) - } -} -*/ diff --git a/nested/src/editors/integer/ctx.rs b/nested/src/editors/integer/ctx.rs deleted file mode 100644 index 99c9aa7..0000000 --- a/nested/src/editors/integer/ctx.rs +++ /dev/null @@ -1,139 +0,0 @@ - -use { - r3vi::{ - view::{OuterViewPort, singleton::*} - }, - laddertypes::{TypeTerm}, - crate::{ - type_system::{Context}, - editors::{ - list::*, - integer::* - }, - type_system::{MorphismTypePattern}, - }, - std::sync::{Arc, RwLock} -}; - -pub fn init_ctx(ctx: &mut Context) { - ctx.add_typename("MachineInt".into()); - ctx.add_typename("u32".into()); - ctx.add_typename("u64".into()); - ctx.add_typename("LittleEndian".into()); - ctx.add_typename("BigEndian".into()); - - ctx.add_node_ctor( - "Digit", Arc::new( - |ctx: Arc<RwLock<Context>>, ty: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>| { - match ty { - TypeTerm::App(args) => { - if args.len() > 1 { - match args[1] { - TypeTerm::Num(radix) => { - let node = DigitEditor::new(ctx.clone(), radix as u32).into_node(depth); - Some( - node - ) - }, - _ => None - } - } else { - None - } - } - _ => None - } - } - ) - ); - - ctx.add_list_typename("PosInt".into()); - let pattern = MorphismTypePattern { - src_tyid: ctx.get_typeid("List"), - dst_tyid: ctx.get_typeid("PosInt").unwrap() - }; - ctx.add_morphism(pattern, - Arc::new( - |mut node, dst_type| { - // todo: check src_type parameter to be ( Digit radix ) - - match dst_type { - TypeTerm::App(args) => { - if args.len() > 1 { - match args[1] { - TypeTerm::Num(_radix) => { - PTYListController::for_node( - &mut node, - Some(','), - None, - ); - - PTYListStyle::for_node( - &mut node, - ("0d", "", "") - ); - - Some(node) - }, - _ => None - } - } else { - None - } - } - _ => None - } - } - ) - ); - - ctx.add_node_ctor( - "PosInt", Arc::new( - |ctx0: Arc<RwLock<Context>>, dst_typ: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>| { - match dst_typ.clone() { - TypeTerm::App(args) => { - if args.len() > 1 { - match args[1] { - TypeTerm::Num(radix) => { - let ctx = ctx0.read().unwrap(); - let mut node = Context::make_node( - &ctx0, - TypeTerm::App(vec![ - TypeTerm::TypeID(ctx.get_typeid("List").unwrap()), - TypeTerm::TypeID( - ctx.get_typeid("Digit").unwrap() - ) - .num_arg(radix) - .clone() - .into() - ]), - depth.map(|d| d+1) - ).unwrap(); - - node = node.morph(dst_typ); - - Some(node) - } - _ => None - } - } else { - None - } - } - _ => None - } - } - ) - ); - - ctx.add_typename("Date".into()); - ctx.add_typename("ISO-8601".into()); - ctx.add_typename("TimeSince".into()); - ctx.add_typename("UnixEpoch".into()); - ctx.add_typename("AnnoDomini".into()); - ctx.add_typename("Epoch".into()); - ctx.add_typename("Duration".into()); - ctx.add_typename("Seconds".into()); - ctx.add_typename("ℕ".into()); -} - diff --git a/nested/src/editors/integer/editor.rs b/nested/src/editors/integer/editor.rs deleted file mode 100644 index 3e11b34..0000000 --- a/nested/src/editors/integer/editor.rs +++ /dev/null @@ -1,239 +0,0 @@ -use { - r3vi::{ - view::{ - OuterViewPort, - singleton::*, - }, - buffer::{ - singleton::*, - vec::*, - index_hashmap::* - } - }, - laddertypes::{TypeTerm}, - crate::{ - type_system::{Context, ReprTree}, - editors::list::{ListCmd, PTYListController, PTYListStyle}, - terminal::{ - TerminalAtom, TerminalStyle, make_label - }, - diagnostics::{Message}, - tree::{NestedNode, TreeNav, TreeNavResult, TreeCursor}, - commander::ObjCommander - }, - std::sync::Arc, - std::sync::RwLock, - std::iter::FromIterator, - cgmath::{Point2} -}; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -pub struct DigitEditor { - ctx: Arc<RwLock<Context>>, - radix: u32, - data: SingletonBuffer<Option<char>>, - msg: VecBuffer<Message>, -} - -impl ObjCommander for DigitEditor { - fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { - let cmd_obj = cmd_obj.read().unwrap(); - let cmd_type = cmd_obj.get_type().clone(); - - if cmd_type == Context::parse(&self.ctx, "Char") { - if let Some(cmd_view) = cmd_obj.get_view::<dyn SingletonView<Item = char>>() { - let c = cmd_view.get(); - - self.msg.clear(); - - if self.ctx.read().unwrap().meta_chars.contains(&c) { - eprintln!("digitedit: meta char"); - return TreeNavResult::Exit; - - } else if c.to_digit(self.radix).is_none() { - /* in case the character c is not in the range of digit-chars, - add a message to the diagnostics view - */ - - let message = IndexBuffer::from_iter(vec![ - (Point2::new(1, 0), make_label("invalid digit '")), - (Point2::new(2, 0), make_label(&format!("{}", c)) - .map_item(|_p,a| a.add_style_back(TerminalStyle::fg_color((140,140,250))))), - (Point2::new(3, 0), make_label("'")) - ]); - - self.msg.push(crate::diagnostics::make_error(message.get_port().flatten())); - self.data.set(Some(c)); - } else { - self.data.set(Some(c)); - } - } - } - - TreeNavResult::Continue - } -} - -impl DigitEditor { - pub fn new(ctx: Arc<RwLock<Context>>, radix: u32) -> Self { - DigitEditor { - ctx, - radix, - data: SingletonBuffer::new(None), - msg: VecBuffer::new(), - } - } - - pub fn into_node(self, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> NestedNode { - let data = self.get_data(); - let editor = Arc::new(RwLock::new(self)); - let ed = editor.write().unwrap(); - let r = ed.radix; - - NestedNode::new(ed.ctx.clone(), data, depth) - .set_cmd(editor.clone()) - .set_view( - ed.data - .get_port() - .map(move |c| { - TerminalAtom::new( - c.unwrap_or('?'), - if c.unwrap_or('?').to_digit(r).is_some() { - TerminalStyle::fg_color((90, 160, 90)) - } else { - //TerminalStyle::bg_color((90, 10, 10)) - TerminalStyle::fg_color((200, 40, 40)) - }, - ) - }) - .to_grid() - ) - .set_diag( - ed.msg.get_port().to_sequence() - ) - } - - pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<u32>>> { - let radix = self.radix; - self.data.get_port().map(move |c| c?.to_digit(radix)) - } - - pub fn get_type(&self) -> TypeTerm { - TypeTerm::TypeID(self.ctx.read().unwrap().get_typeid("Digit").unwrap()) - } - - pub fn get_data(&self) -> Arc<RwLock<ReprTree>> { - ReprTree::ascend( - &ReprTree::new_leaf( - self.ctx.read().unwrap().type_term_from_str("<Seq u32>").unwrap(), - self.get_data_port().into() - ), - self.get_type() - ) - } -} - - -pub struct PosIntEditor { - radix: u32, - digits: NestedNode, - - // todo: endianness -} - -impl PosIntEditor { - pub fn new(ctx: Arc<RwLock<Context>>, radix: u32) -> Self { - let mut node = Context::make_node( - &ctx, - Context::parse(&ctx, format!("<List <Digit {}>>", radix).as_str()), - r3vi::buffer::singleton::SingletonBuffer::new(0).get_port() - ).unwrap(); - - // Set Type - node.data = ReprTree::ascend( - &node.data.clone(), - TypeTerm::App(vec![ - TypeTerm::TypeID(ctx.read().unwrap().get_typeid("PosInt").unwrap()), - TypeTerm::Num(radix as i64).into(), - TypeTerm::TypeID(ctx.read().unwrap().get_typeid("BigEndian").unwrap()) - ] - )); - - PTYListController::for_node( &mut node, Some(' '), None ); - PTYListStyle::for_node( &mut node, - ( - match radix { - 2 => "0b".into(), - 8 => "0o".into(), - 10 => "0d".into(), - 16 => "0x".into(), - _ => "".into() - }, - "".into(), - "".into() - ) - ); - - PosIntEditor { - radix, - digits: node - } - } - - pub fn from_u64(ctx: Arc<RwLock<Context>>, radix: u32, value: u64) -> Self { - let mut edit = PosIntEditor::new(ctx, radix); - edit.set_value_u64( value ); - edit - } - - pub fn set_value_u64(&mut self, mut value: u64) { - self.digits.send_cmd_obj(ListCmd::Clear.into_repr_tree(&self.digits.ctx)); - - while value > 0 { - let digit_val = (value % self.radix as u64) as u32; - value /= self.radix as u64; - - // if BigEndian - self.digits.goto(TreeCursor::home()); - - self.digits.send_cmd_obj(ReprTree::from_char(&self.digits.ctx, char::from_digit(digit_val, self.radix).expect("invalid digit"))); - } - self.digits.goto(TreeCursor::none()); - } - - pub fn into_node(self) -> NestedNode { - self.digits - } - -/* - pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = u32>> { - let radix = self.radix; - self.digits - .get_data_port() - .filter_map(move |digit_editor| { - digit_editor.read().unwrap().data.get()?.to_digit(radix) - }) - } - - pub fn get_value(&self) -> u32 { - let mut value = 0; - let mut weight = 1; - for digit_value in self - .get_data_port() - .get_view() - .unwrap() - .iter() - .collect::<Vec<_>>() - .into_iter() - .rev() - { - value += digit_value * weight; - weight *= self.radix; - } - - value -} -*/ -} - diff --git a/nested/src/editors/integer/mod.rs b/nested/src/editors/integer/mod.rs deleted file mode 100644 index bdbf565..0000000 --- a/nested/src/editors/integer/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod add; -pub mod editor; -pub mod radix; -pub mod ctx; - -pub use { - add::Add, - editor::{DigitEditor, PosIntEditor}, - radix::RadixProjection, - ctx::init_ctx -}; - diff --git a/nested/src/editors/integer/radix.rs b/nested/src/editors/integer/radix.rs deleted file mode 100644 index bcc12da..0000000 --- a/nested/src/editors/integer/radix.rs +++ /dev/null @@ -1,101 +0,0 @@ -use { - r3vi::{ - view::{ - InnerViewPort, Observer, OuterViewPort, - sequence::*, - }, - buffer::{vec::*} - }, - std::sync::{Arc, RwLock}, -}; - -pub struct RadixProjection { - src_radix: usize, - dst_radix: usize, - src_digits: Option<Arc<dyn SequenceView<Item = usize>>>, - dst_digits: RwLock<VecBuffer<usize>>, -} - -impl RadixProjection { - pub fn new( - // static parameters - //--- - src_radix: usize, - dst_radix: usize, - //--- - - // dynamic parameters - //--- - // input - src_digits: OuterViewPort<dyn SequenceView<Item = usize>>, - // output - dst_digits: InnerViewPort<RwLock<Vec<usize>>>, - //--- - ) -> Arc<RwLock<Self>> { - dst_digits.0.add_update_hook(Arc::new(src_digits.0.clone())); - let proj = Arc::new(RwLock::new(RadixProjection { - src_radix, - dst_radix, - src_digits: None, - dst_digits: RwLock::new(VecBuffer::with_port(dst_digits)), - })); - src_digits.add_observer(proj.clone()); - proj - } - - fn machine_int(&self) -> usize { - let mut val = 0; - let mut r = 1; - for i in 0..self.src_digits.len().unwrap_or(0) { - val += r * self.src_digits.get(&i).unwrap(); - r *= self.src_radix; - } - - val - } - - // recalculate everything - fn update(&self) { - let mut dst = self.dst_digits.write().unwrap(); - dst.clear(); - - let mut val = self.machine_int(); - - while val > 0 { - dst.push(val % self.dst_radix); - val /= self.dst_radix; - } - } - - fn _update_dst_digit(&mut self, _idx: usize) { - /* - let v = 0; // calculate new digit value - - // which src-digits are responsible? - - if idx < self.dst_digits.len() { - self.dst_digits.get_mut(idx) = v; - } else if idx == self.dst_digits.len() { - self.dst_digits.push(v); - } else { - // error - } - */ - } -} - -impl Observer<dyn SequenceView<Item = usize>> for RadixProjection { - fn reset(&mut self, view: Option<Arc<dyn SequenceView<Item = usize>>>) { - self.src_digits = view; - } - - fn notify(&mut self, _idx: &usize) { - // todo: - // src digit i changed. - // which dst-digits does it affect? - // update dst-digit j: - - // ...but for now the easy way - self.update(); - } -} diff --git a/nested/src/editors/list/ctx.rs b/nested/src/editors/list/ctx.rs deleted file mode 100644 index 91474f0..0000000 --- a/nested/src/editors/list/ctx.rs +++ /dev/null @@ -1,41 +0,0 @@ -use { - r3vi::{view::{OuterViewPort, singleton::*}}, - laddertypes::{TypeTerm}, - crate::{ - type_system::{Context}, - editors::list::{ListEditor, PTYListController, PTYListStyle} - }, - std::sync::{Arc, RwLock} -}; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -pub fn init_ctx(ctx: &mut Context) { - ctx.add_typename("ListCmd".into()); - ctx.add_list_typename("List".into()); - - ctx.add_node_ctor( - "List", Arc::new( - |ctx: Arc<RwLock<Context>>, ty: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>| { - match ty { - TypeTerm::App(args) => { - if args.len() > 1 { - let typ = args[1].clone(); - - let mut node = ListEditor::new(ctx.clone(), typ).into_node(depth); - - PTYListController::for_node( &mut node, Some(','), Some('}') ); - PTYListStyle::for_node( &mut node, ("{",", ","}") ); - - Some(node) - } else { - None - } - } - _ => None - } - } - ) - ); -} - diff --git a/nested/src/editors/mod.rs b/nested/src/editors/mod.rs deleted file mode 100644 index a93800c..0000000 --- a/nested/src/editors/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ - -pub mod list; -pub mod product; -pub mod sum; - -pub mod char; -pub mod integer; -pub mod typeterm; - diff --git a/nested/src/lib.rs b/nested/src/lib.rs deleted file mode 100644 index c81e77d..0000000 --- a/nested/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![feature(trait_alias)] - -pub mod terminal; - -pub mod utils; -pub mod editors; -pub mod tree; -pub mod type_system; - -pub mod diagnostics; -pub mod commander; -//pub mod product; -//pub mod sum; -//pub mod list; - -pub fn magic_header() { - eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>"); -} - -/* -pub trait StringGen { - fn get_string(&self) -> String; -} - -use crate::{tree::{TreeNav}, diagnostics::Diagnostics, terminal::TerminalView, core::{OuterViewPort}}; - */ - -use r3vi::view::OuterViewPort; -use crate::terminal::TerminalView; - -pub trait PtySegment { - fn pty_view(&self) -> OuterViewPort<dyn TerminalView>; -} - diff --git a/nested/src/terminal/mod.rs b/nested/src/terminal/mod.rs deleted file mode 100644 index 61e41b2..0000000 --- a/nested/src/terminal/mod.rs +++ /dev/null @@ -1,80 +0,0 @@ -pub mod ansi_parser; -pub mod atom; -pub mod compositor; -pub mod style; -pub mod terminal; -pub mod widgets; - -pub use { - atom::TerminalAtom, - compositor::TerminalCompositor, - style::TerminalStyle, - terminal::{Terminal, TerminalEvent}, -}; - -use r3vi::view::grid::*; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -pub trait TerminalView = GridView<Item = TerminalAtom>; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -pub enum TerminalEditorResult { - Continue, - Exit, -} - -pub trait TerminalEditor { - fn get_term_view(&self) -> OuterViewPort<dyn TerminalView>; - fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult; -} - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -use { - r3vi::{ - view::{OuterViewPort}, - buffer::vec::*, - }, - cgmath::Point2, -}; - -pub fn make_label(s: &str) -> OuterViewPort<dyn TerminalView> { - let label = VecBuffer::with_data(s.chars().collect()); - - let v = label.get_port() - .to_sequence() - .map(|c| TerminalAtom::from(c)) - .to_index() - .map_key( - |idx| Point2::new(*idx as i16, 0), - |pt| if pt.y == 0 { Some(pt.x as usize) } else { None }, - ); - - v -} - -pub trait TerminalProjections { - fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView>; - fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>; - fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView>; -} - -impl TerminalProjections for OuterViewPort<dyn TerminalView> { - fn with_style(&self, style: TerminalStyle) -> OuterViewPort<dyn TerminalView> { - self.map_item( - move |_idx, a| - a.add_style_front(style) - ) - } - - fn with_fg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> { - self.with_style(TerminalStyle::fg_color(col)) - } - - fn with_bg_color(&self, col: (u8, u8, u8)) -> OuterViewPort<dyn TerminalView> { - self.with_style(TerminalStyle::bg_color(col)) - } -} - diff --git a/nested/src/tree/node.rs b/nested/src/tree/node.rs deleted file mode 100644 index 1406c96..0000000 --- a/nested/src/tree/node.rs +++ /dev/null @@ -1,343 +0,0 @@ -use { - std::{sync::{Arc, RwLock}, any::Any}, - cgmath::{Vector2, Point2}, - r3vi::{ - view::{View, ViewPort, OuterViewPort, AnyOuterViewPort, singleton::*, sequence::*}, - buffer::{singleton::*} - }, - laddertypes::{TypeTerm}, - crate::{ - type_system::{ReprTree, Context}, - terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult, TerminalAtom}, - diagnostics::{Diagnostics, Message}, - tree::{TreeNav, TreeCursor, TreeNavResult, TreeHeightOp}, - editors::list::{ListCursorMode}, - commander::ObjCommander, - } -}; - -/* TODO: refactoring proposal - -struct NestedNodeDisplay { - /// display view - pub view: Option< OuterViewPort<dyn TerminalView> >, - - /// diagnostics - pub diag: Option< OuterViewPort<dyn SequenceView<Item = Message>> >, - - /// depth - pub depth: SingletonBuffer< usize >, -} - -struct NestedNodeEdit { - /// abstract editor - pub editor: SingletonBuffer< - Option< Arc<dyn Any + Send + Sync> > - >, - - pub spillbuf: VecBuffer< NestedNode >, - - /// commander & navigation - pub cmd: SingletonBuffer< - Option< Arc<RwLock<dyn ObjCommander + Send + Sync>> > - >, - pub close_char: SingletonBuffer< Option< char > >, - - // could be replaced by cmd when TreeNav -CmdObjects are used - pub tree_nav: SingletonBuffer< - Option< Arc<RwLock<dyn TreeNav + Send + Sync>> > - >, -} - -pub struct NewNestedNode { - /// context - pub ctx: Arc<RwLock<Context>>, - - /// abstract data view - pub data: Arc<RwLock<ReprTree>>, - - /// viewports for terminal display - pub disp: NestedNodeDisplay, - - /// editor & commander objects - pub edit: NestedNodeEdit -} - -*/ - -#[derive(Clone)] -pub struct NestedNode { - /// context - pub ctx: Arc<RwLock<Context>>, - - /// abstract data view - pub data: Arc<RwLock<ReprTree>>, - - /// display view - pub view: Option< OuterViewPort<dyn TerminalView> >, - - /// diagnostics - pub diag: Option< OuterViewPort<dyn SequenceView<Item = Message>> >, - - /// depth - pub depth: OuterViewPort< dyn SingletonView<Item = usize> >, - - /// abstract editor - pub editor: SingletonBuffer< - Option< Arc<dyn Any + Send + Sync> > - >, - - pub spillbuf: Arc<RwLock<Vec<Arc<RwLock<NestedNode>>>>>, - - /// commander & navigation - pub cmd: SingletonBuffer< - Option< Arc<RwLock<dyn ObjCommander + Send + Sync>> > - >, - pub close_char: SingletonBuffer< - Option< char > - >, - pub tree_nav: SingletonBuffer< - Option< Arc<RwLock<dyn TreeNav + Send + Sync>> > - >, -} - -impl NestedNode { - pub fn new(ctx: Arc<RwLock<Context>>, data: Arc<RwLock<ReprTree>>, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> Self { - NestedNode { - ctx, - data, - view: None, - diag: None, - depth, - editor: SingletonBuffer::new(None), - spillbuf: Arc::new(RwLock::new(Vec::new())), - cmd: SingletonBuffer::new(None), - close_char: SingletonBuffer::new(None), - tree_nav: SingletonBuffer::new(None) - } - } - - /* TODO: move into separate file/module - */ - pub fn from_char(ctx: Arc<RwLock<Context>>, c: char) -> NestedNode { - let buf = r3vi::buffer::singleton::SingletonBuffer::<char>::new(c); - - NestedNode::new( - ctx.clone(), - ReprTree::new_leaf( - Context::parse(&ctx, "Char"), - buf.get_port().into() - ), - SingletonBuffer::new(0).get_port() - ) - .set_view(buf.get_port() - .map(|c| TerminalAtom::from(c)) - .to_index() - .map_key( - |_x| { - Point2::new(0, 0) - }, - |p| { - if *p == Point2::new(0,0) { Some(()) } else { None } - }) - ) - .set_editor(Arc::new(RwLock::new(buf))) - } - - - //\\//\\ - - pub fn morph(self, ty: TypeTerm) -> NestedNode { - Context::morph_node(self, ty) - } - - pub fn get_type(&self) -> TypeTerm { - self.data.read().unwrap().get_type().clone() - } - - //\\//\\ - - pub fn set_editor(mut self, editor: Arc<dyn Any + Send + Sync>) -> Self { - self.editor.set(Some(editor)); - self - } - - pub fn set_view(mut self, view: OuterViewPort<dyn TerminalView>) -> Self { - self.view = Some(view); - self - } - - pub fn set_cmd(mut self, cmd: Arc<RwLock<dyn ObjCommander + Send + Sync>>) -> Self { - self.cmd.set(Some(cmd)); - self - } - - pub fn set_nav(mut self, nav: Arc<RwLock<dyn TreeNav + Send + Sync>>) -> Self { - self.tree_nav.set(Some(nav)); - self - } - - pub fn set_diag(mut self, diag: OuterViewPort<dyn SequenceView<Item = Message>>) -> Self { - self.diag = Some(diag); - self - } - - //\\//\\ - - pub fn get_diag(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { - self.diag.clone().unwrap_or(ViewPort::new().into_outer()) - } - - pub fn get_view(&self) -> OuterViewPort<dyn TerminalView> { - self.view.clone().unwrap_or(ViewPort::new().into_outer()) - } - - pub fn get_data_port<'a, V: View + ?Sized + 'static>(&'a self, type_str: impl Iterator<Item = &'a str>) -> Option<OuterViewPort<V>> - where V::Msg: Clone { - let ctx = self.ctx.clone(); - let type_ladder = type_str.map(|s| Context::parse(&ctx, s)); - - let repr_tree = ReprTree::descend_ladder(&self.data, type_ladder)?; - repr_tree.clone().read().unwrap() - .get_port::<V>().clone() - } - - pub fn get_data_view<'a, V: View + ?Sized + 'static>(&'a self, type_str: impl Iterator<Item = &'a str>) -> Option<Arc<V>> - where V::Msg: Clone { - self.get_data_port::<V>(type_str)?.get_view() - } - - /* TODO - pub fn get_seq_view<'a, T: Clone>(&self, type_str: impl Iterator<Item = &'a str>) -> Option<OuterViewPort<dyn SingletonView<Item = T>>> { - self.get_data_view::<dyn SequenceView<Item = NestedNode>>(type_str) - .unwrap() - .map({ - move |node| { - node.get_data_view::<dyn SingletonView<Item = T>>().get() - } - }) - } - */ - - pub fn get_edit<T: Send + Sync + 'static>(&self) -> Option<Arc<RwLock<T>>> { - if let Some(edit) = self.editor.get() { - if let Ok(edit) = edit.downcast::<RwLock<T>>() { - Some(edit) - } else { - None - } - } else { - None - } - } -} - -/* -impl TreeType for NestedNode { - fn get_type(&self, addr: &TreeAddr) -> TypeLadder { - if let Some(editor) = self.editor { - editor.read().unwrap().get_type(addr) - } else { - vec![] - } - } -} - */ - -/* TODO: remove that at some point -*/ -impl TerminalEditor for NestedNode { - fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> { - self.get_view() - } - - fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { - let buf = SingletonBuffer::new(event.clone()); - - if let Some(cmd) = self.cmd.get() { - cmd.write().unwrap().send_cmd_obj( - ReprTree::new_leaf( - self.ctx.read().unwrap().type_term_from_str("TerminalEvent").unwrap(), - AnyOuterViewPort::from(buf.get_port()) - )); - } - - TerminalEditorResult::Continue - } -} - -impl TreeNav for NestedNode { - fn get_cursor(&self) -> TreeCursor { - if let Some(tn) = self.tree_nav.get() { - tn.read().unwrap().get_cursor() - } else { - TreeCursor::default() - } - } - - fn get_addr_view(&self) -> OuterViewPort<dyn SequenceView<Item = isize>> { - if let Some(tn) = self.tree_nav.get() { - tn.read().unwrap().get_addr_view() - } else { - OuterViewPort::default() - } - } - - fn get_mode_view(&self) -> OuterViewPort<dyn SingletonView<Item = ListCursorMode>> { - if let Some(tn) = self.tree_nav.get() { - tn.read().unwrap().get_mode_view() - } else { - OuterViewPort::default() - } - } - - fn get_cursor_warp(&self) -> TreeCursor { - if let Some(tn) = self.tree_nav.get() { - tn.read().unwrap().get_cursor_warp() - } else { - TreeCursor::default() - } - } - - fn get_height(&self, op: &TreeHeightOp) -> usize { - if let Some(tn) = self.tree_nav.get() { - tn.read().unwrap().get_height( op ) - } else { - 0 - } - } - - fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult { - if let Some(tn) = self.tree_nav.get() { - tn.write().unwrap().goby(direction) - } else { - TreeNavResult::Exit - } - } - - fn goto(&mut self, new_cursor: TreeCursor) -> TreeNavResult { - if let Some(tn) = self.tree_nav.get() { - tn.write().unwrap().goto(new_cursor) - } else { - TreeNavResult::Exit - } - } -} - -impl ObjCommander for NestedNode { - fn send_cmd_obj(&mut self, cmd_obj: Arc<RwLock<ReprTree>>) -> TreeNavResult { - if let Some(cmd) = self.cmd.get() { - // todo: filter out tree-nav cmds and send them to tree_nav - cmd.write().unwrap().send_cmd_obj(cmd_obj) - } else { - TreeNavResult::Exit - } - } -} - -impl Diagnostics for NestedNode { - fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = Message>> { - self.get_diag() - } -} - diff --git a/nested/src/type_system/context.rs b/nested/src/type_system/context.rs deleted file mode 100644 index bf4f8c4..0000000 --- a/nested/src/type_system/context.rs +++ /dev/null @@ -1,433 +0,0 @@ -use { - r3vi::{view::{OuterViewPort, singleton::*}, buffer::{singleton::*}}, - laddertypes::{TypeDict, TypeTerm, TypeID}, - crate::{ - type_system::{ReprTree}, - tree::NestedNode - }, - std::{ - collections::HashMap, - sync::{Arc, RwLock}, - } -}; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -#[derive(Clone, Copy, Hash, PartialEq, Eq)] -pub enum MorphismMode { - /// Isomorphism - /// e.g. `( PositionalInteger 10 BigEndian ) <~> ( PositionalInteger 16 LittleEndian )` - Iso, - - /// Monomorphism, i.e. injective functions, - /// upcast-view, downcast-control, semantic gain - /// e.g. `( Sequence ( Digit 16 ) ) ~> ( PositionalInteger 16 LittleEndian )` - Mono, - - /// Epimorphsim, i.e. surjective functions, - /// upcast-control, downcast-view, possible loss of entropy - /// e.g. `( Ascii ) ~> ( Digit 16 )` - Epi, - - /// Any other function - Any, -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub struct MorphismType { -// pub mode: MorphismMode, - pub src_type: Option<TypeTerm>, - pub dst_type: TypeTerm, -} - -#[derive(Clone, Hash, Eq, PartialEq)] -pub struct MorphismTypePattern { - pub src_tyid: Option<TypeID>, - pub dst_tyid: TypeID -} - -impl MorphismType { - pub fn to_str(&self, ctx: &Context) -> String { - format!("{:?} -> {:?}", - if let Some(t) = self.src_type.as_ref() { - ctx.type_term_to_str(t) - } else { - "None".into() - }, - ctx.type_term_to_str(&self.dst_type)) - } -} - -impl MorphismTypePattern { - pub fn to_str(&self, ctx: &Context) -> String { - format!("{:?} -> {:?}", - if let Some(t) = self.src_tyid.as_ref() { - ctx.type_term_to_str(&TypeTerm::TypeID(t.clone())) - } else { - "None".into() - }, - ctx.type_term_to_str(&TypeTerm::TypeID(self.dst_tyid.clone()))) - } -} - -impl From<MorphismType> for MorphismTypePattern { - fn from(value: MorphismType) -> MorphismTypePattern { - fn strip( x: &TypeTerm ) -> TypeID { - match x { - TypeTerm::TypeID(id) => id.clone(), - TypeTerm::App(args) => strip(&args[0]), - TypeTerm::Ladder(args) => strip(&args[0]), - _ => unreachable!() - } - } - - MorphismTypePattern { - src_tyid: value.src_type.map(|x| strip(&x)), - dst_tyid: strip(&value.dst_type) - } - } -} - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -#[derive(Clone)] -pub struct Context { - /// assigns a name to every type - pub type_dict: Arc<RwLock<TypeDict>>, - - /// named vertices of the graph - nodes: HashMap< String, NestedNode >, - - /// todo: beautify - /// types that can be edited as lists - pub list_types: Vec< TypeID >, - pub meta_chars: Vec< char >, - - /// graph constructors - /// TODO: move into separate struct MorphismMap or something - morphisms: HashMap< - MorphismTypePattern, - Arc< - dyn Fn( NestedNode, TypeTerm ) -> Option<NestedNode> - + Send + Sync - > - >, - - /// recursion - parent: Option<Arc<RwLock<Context>>>, -} - -impl Default for Context { - fn default() -> Context { - let mut ctx = Context::new(); - - ctx.add_list_typename("Sequence"); - ctx.add_synonym("Seq", "Sequence"); - ctx.add_list_typename("SepSeq"); - ctx.add_typename("NestedNode"); - ctx.add_typename("TerminalEvent"); - - crate::editors::list::init_ctx( &mut ctx ); - crate::editors::char::init_ctx( &mut ctx ); - crate::editors::integer::init_ctx( &mut ctx ); - crate::editors::typeterm::init_ctx( &mut ctx ); - - ctx - } -} - -impl Context { - pub fn with_parent(parent: Option<Arc<RwLock<Context>>>) -> Self { - Context { - type_dict: match parent.as_ref() { - Some(p) => p.read().unwrap().type_dict.clone(), - None => Arc::new(RwLock::new(TypeDict::new())) - }, - morphisms: HashMap::new(), - nodes: HashMap::new(), - list_types: match parent.as_ref() { - Some(p) => p.read().unwrap().list_types.clone(), - None => Vec::new() - }, - meta_chars: match parent.as_ref() { - Some(p) => p.read().unwrap().meta_chars.clone(), - None => Vec::new() - }, - parent, - } - } - - pub fn new() -> Self { - Context::with_parent(None) - } - - pub fn depth(&self) -> usize { - if let Some(parent) = self.parent.as_ref() { - parent.read().unwrap().depth() + 1 - } else { - 0 - } - } - - pub fn parse(ctx: &Arc<RwLock<Self>>, s: &str) -> TypeTerm { - ctx.read().unwrap().type_term_from_str(s).expect("could not parse type term") - } - - pub fn add_typename(&mut self, tn: &str) -> TypeID { - self.type_dict.write().unwrap().add_typename(tn.to_string()) - } - - pub fn add_varname(&mut self, vn: &str) -> TypeID { - self.type_dict.write().unwrap().add_varname(vn.to_string()) - } - - pub fn add_synonym(&mut self, new: &str, old: &str) { - self.type_dict.write().unwrap().add_synonym(new.to_string(), old.to_string()); - } - - pub fn add_list_typename(&mut self, tn: &str) { - let tid = self.add_typename(tn); - self.list_types.push( tid ); - } - - pub fn is_list_type(&self, t: &TypeTerm) -> bool { - match t { - TypeTerm::TypeID(id) => { - self.list_types.contains(id) - } - TypeTerm::Ladder(args) | - TypeTerm::App(args) => { - if args.len() > 0 { - if self.is_list_type(&args[0]) { - true - } else { - false - } - } else { - false - } - } - _ => false - } - } - - pub fn get_typeid(&self, tn: &str) -> Option<TypeID> { - self.type_dict.read().unwrap().get_typeid(&tn.into()) - } - - pub fn get_fun_typeid(&self, tn: &str) -> Option<u64> { - match self.get_typeid(tn) { - Some(TypeID::Fun(x)) => Some(x), - _ => None - } - } - - pub fn get_typename(&self, tid: &TypeID) -> Option<String> { - self.type_dict.read().unwrap().get_typename(tid) - } - - pub fn get_var_typeid(&self, tn: &str) -> Option<u64> { - match self.get_typeid(tn) { - Some(TypeID::Var(x)) => Some(x), - _ => None - } - } - - pub fn type_term_from_str(&self, tn: &str) -> Result<TypeTerm, laddertypes::parser::ParseError> { - self.type_dict.write().unwrap().parse(&tn) - } - - pub fn type_term_to_str(&self, t: &TypeTerm) -> String { - self.type_dict.read().unwrap().unparse(&t) - } - - pub fn add_node_ctor(&mut self, tn: &str, mk_editor: Arc<dyn Fn(Arc<RwLock<Self>>, TypeTerm, OuterViewPort<dyn SingletonView<Item = usize>>) -> Option<NestedNode> + Send + Sync>) { - let dict = self.type_dict.clone(); - let mut dict = dict.write().unwrap(); - - let tyid = - if let Some(tyid) = dict.get_typeid(&tn.into()) { - tyid - } else { - dict.add_typename(tn.into()) - }; - - let morphism_pattern = MorphismTypePattern { - src_tyid: None, - dst_tyid: tyid - }; - - drop(dict); - - self.add_morphism(morphism_pattern, Arc::new(move |node, dst_type| { - mk_editor(node.ctx.clone(), dst_type, node.depth) - })); - } - - pub fn add_morphism( - &mut self, - morph_type_pattern: MorphismTypePattern, - morph_fn: Arc< - dyn Fn( NestedNode, TypeTerm ) -> Option<NestedNode> - + Send + Sync - > - ) { - self.morphisms.insert(morph_type_pattern, morph_fn); - } - - pub fn get_morphism(&self, ty: MorphismType) -> Option<Arc<dyn Fn(NestedNode, TypeTerm) -> Option<NestedNode> + Send + Sync>> { - let pattern = MorphismTypePattern::from(ty.clone()); - - if let Some(morphism) = self.morphisms.get( &pattern ) { - Some(morphism.clone()) - } else { - self.parent.as_ref()? - .read().unwrap() - .get_morphism(ty) - } - } - - pub fn make_node(ctx: &Arc<RwLock<Self>>, type_term: TypeTerm, depth: OuterViewPort<dyn SingletonView<Item = usize>>) -> Option<NestedNode> { - let mk_node = ctx.read().unwrap().get_morphism(MorphismType { - src_type: None, - dst_type: type_term.clone() - }).expect(&format!("morphism {}", ctx.read().unwrap().type_term_to_str(&type_term))); - - /* create new context per node ?? too heavy.. whats the reason? TODO */ - - let new_ctx = Arc::new(RwLock::new(Context::with_parent(Some(ctx.clone())))); - - mk_node( - NestedNode::new(new_ctx, ReprTree::new_arc(type_term.clone()), depth), - type_term - ) - } - - pub fn morph_node(mut node: NestedNode, dst_type: TypeTerm) -> NestedNode { - let src_type = node.data.read().unwrap().get_type().clone(); - let pattern = MorphismType { src_type: Some(src_type), dst_type: dst_type.clone() }; - - /* it is not univesally true to always use ascend. - */ - node.data = - ReprTree::ascend( - &node.data, - dst_type.clone() - ); - - let m = node.ctx.read().unwrap().get_morphism(pattern.clone()); - if let Some(transform) = m { - if let Some(new_node) = transform(node.clone(), dst_type) { - new_node - } else { - node.clone() - } - } else { - eprintln!("could not find morphism {}", pattern.to_str(&node.ctx.read().unwrap())); - node - } - } - - /// adds an object without any representations - pub fn add_obj(ctx: Arc<RwLock<Context>>, name: String, typename: &str) { - let type_tag = ctx.read().unwrap() - .type_dict.write().unwrap() - .parse(typename).unwrap(); - - if let Some(node) = Context::make_node(&ctx, type_tag, SingletonBuffer::new(0).get_port()) { - ctx.write().unwrap().nodes.insert(name, node); - } - } - - pub fn get_obj(&self, name: &String) -> Option<NestedNode> { - if let Some(obj) = self.nodes.get(name) { - Some(obj.clone()) - } else if let Some(parent) = self.parent.as_ref() { - parent.read().unwrap().get_obj(name) - } else { - None - } - } - -/* - pub fn get_obj_port<'a, V: View + ?Sized + 'static>( - &self, - name: &str, - type_ladder: impl Iterator<Item = &'a str>, - ) -> Option<OuterViewPort<V>> - where - V::Msg: Clone, - { - self.get_obj(&name.into())? - .downcast_ladder(type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap()))? - .get_port() - } - - pub fn insert_repr<'a>( - &mut self, - name: &str, - type_ladder: impl Iterator<Item = &'a str>, - port: AnyOuterViewPort, - ) { - self.get_obj(&name.to_string()) - .unwrap() - .repr - .write() - .unwrap() - .insert_leaf( - type_ladder.map(|tn| self.type_dict.type_term_from_str(tn).unwrap()), - port, - ); - } - - pub fn epi_cast(&mut self, name: &str, typename: &str) { - let dst_type = self.type_dict.type_term_from_str(typename).unwrap(); - let old_obj = self.objects.get(&name.to_string()).unwrap().clone(); - let new_obj = if let Some(ctor) = self.morphism_constructors.get(&MorphismType { - mode: MorphismMode::Epi, - src_type: old_obj.type_tag.clone(), - dst_type: dst_type.clone(), - }) { - ctor(old_obj.clone()) - } else { - Arc::new(RwLock::new(ReprTree::new(dst_type))) - }; - - new_obj - .repr - .write() - .unwrap() - .insert_branch(old_obj.type_tag, old_obj.repr); - - self.objects.insert(name.to_string(), new_obj); - } - - pub fn mono_view<'a, V: View + ?Sized + 'static>( - &mut self, - name: &str, - type_ladder: impl Iterator<Item = &'a str>, - ) -> Option<OuterViewPort<V>> - where - V::Msg: Clone, - { - if let Some(p) = self.get_obj_port(name, type_ladder) { - Some(p) - } else { - // todo : add repr with morphism constructor (if one exists) - /* - if let Some(ctor) = self.morphism_constructors.get( - &MorphismType { - mode: MorphismMode::Mono, - src_type: old_obj.type_tag.clone(), - dst_type: - } - ) - */ - None - } -} - */ -} - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - diff --git a/nested/src/type_system/mod.rs b/nested/src/type_system/mod.rs deleted file mode 100644 index 6d52a5b..0000000 --- a/nested/src/type_system/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod context; -pub mod repr_tree; - -pub use { - context::{Context, MorphismMode, MorphismType, MorphismTypePattern}, - repr_tree::ReprTree -}; - diff --git a/nested/src/type_system/repr_tree.rs b/nested/src/type_system/repr_tree.rs deleted file mode 100644 index 611565c..0000000 --- a/nested/src/type_system/repr_tree.rs +++ /dev/null @@ -1,235 +0,0 @@ -use { - r3vi::view::{AnyOuterViewPort, OuterViewPort, View}, - laddertypes::{TypeTerm}, - crate::{ - type_system::{Context} - }, - std::{ - collections::HashMap, - sync::{Arc, RwLock}, - }, -}; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -#[derive(Clone)] -pub struct ReprTree { - type_tag: TypeTerm, - port: Option<AnyOuterViewPort>, - branches: HashMap<TypeTerm, Arc<RwLock<ReprTree>>>, -} - -impl std::fmt::Debug for ReprTree { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "type: {:?}", self.type_tag)?; - - for (_k,x) in self.branches.iter() { - write!(f, "child: {:?}", x)?; - } - - Ok(()) - } -} - -impl ReprTree { - pub fn new(type_tag: impl Into<TypeTerm>) -> Self { - ReprTree { - type_tag: type_tag.into(), - port: None, - branches: HashMap::new(), - } - } - - pub fn new_arc(type_tag: impl Into<TypeTerm>) -> Arc<RwLock<Self>> { - Arc::new(RwLock::new(Self::new(type_tag))) - } - - pub fn get_type(&self) -> &TypeTerm { - &self.type_tag - } - - pub fn from_char(ctx: &Arc<RwLock<Context>>, c: char) -> Arc<RwLock<Self>> { - let buf = r3vi::buffer::singleton::SingletonBuffer::<char>::new(c); - ReprTree::new_leaf( - Context::parse(ctx, "Char"), - buf.get_port().into() - ) - } - - pub fn new_leaf(type_tag: impl Into<TypeTerm>, port: AnyOuterViewPort) -> Arc<RwLock<Self>> { - let mut tree = ReprTree::new(type_tag.into()); - tree.insert_leaf(vec![].into_iter(), port); - Arc::new(RwLock::new(tree)) - } - - pub fn insert_branch(&mut self, repr: Arc<RwLock<ReprTree>>) { - self.branches.insert(repr.clone().read().unwrap().type_tag.clone(), repr.clone()); - } - - pub fn insert_leaf( - &mut self, - mut type_ladder: impl Iterator<Item = TypeTerm>, - port: AnyOuterViewPort, - ) { - if let Some(type_term) = type_ladder.next() { - if let Some(next_repr) = self.branches.get(&type_term) { - next_repr.write().unwrap().insert_leaf(type_ladder, port); - } else { - let mut next_repr = ReprTree::new(type_term.clone()); - next_repr.insert_leaf(type_ladder, port); - self.insert_branch(Arc::new(RwLock::new(next_repr))); - } - } else { - self.port = Some(port); - } - } - - //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - - pub fn get_port<V: View + ?Sized + 'static>(&self) -> Option<OuterViewPort<V>> - where - V::Msg: Clone, - { - Some( - self.port - .clone()? - .downcast::<V>() - .ok()? - ) - } - - pub fn get_view<V: View + ?Sized + 'static>(&self) -> Option<Arc<V>> - where - V::Msg: Clone, - { - self.get_port::<V>()? - .get_view() - } - - pub fn descend(&self, dst_type: impl Into<TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { - self.branches.get(&dst_type.into()).cloned() - } - - pub fn descend_ladder(rt: &Arc<RwLock<Self>>, mut repr_ladder: impl Iterator<Item = TypeTerm>) -> Option<Arc<RwLock<ReprTree>>> { - if let Some(first) = repr_ladder.next() { - let rt = rt.read().unwrap(); - repr_ladder.fold( - rt.descend(first), - |s, t| s?.read().unwrap().descend(t)) - } else { - Some(rt.clone()) - } - } - - pub fn ascend(rt: &Arc<RwLock<Self>>, type_term: impl Into<TypeTerm>) -> Arc<RwLock<ReprTree>> { - let mut n = Self::new(type_term); - n.insert_branch(rt.clone()); - Arc::new(RwLock::new(n)) - } - -/* - pub fn add_iso_repr( - &self, - type_ladder: impl Iterator<Item = TypeTerm>, - morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>, - ) { - let mut cur_repr = self.repr.clone(); - - for dst_type in type_ladder { - if let Some(next_repr) = self.repr.read().unwrap().branches.get(&dst_type) { - // go deeper - cur_repr = next_repr.clone(); - } else { - // search for morphism constructor and insert new repr - let mut obj = None; - - for src_type in cur_repr.read().unwrap().branches.keys() { - if let Some(ctor) = morphism_constructors.get(&MorphismType { - mode: MorphismMode::Iso, - src_type: src_type.clone(), - dst_type: dst_type.clone(), - }) { - let new_obj = ctor(Object { - type_tag: src_type.clone(), - repr: cur_repr - .read() - .unwrap() - .branches - .get(&src_type) - .unwrap() - .clone(), - }); - - assert!(new_obj.type_tag == dst_type); - - obj = Some(new_obj); - break; - } - } - - if let Some(obj) = obj { - cur_repr - .write() - .unwrap() - .insert_branch(obj.type_tag, obj.repr); - } else { - panic!("could not find matching isomorphism!"); - } - } - } - } - - pub fn add_mono_repr<'a>( - &self, - type_ladder: impl Iterator<Item = TypeTerm>, - morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>, - ) { - let mut cur_type = self.type_tag.clone(); - let mut cur_repr = self.repr.clone(); - - for dst_type in type_ladder { - if let Some(next_repr) = self.repr.read().unwrap().branches.get(&dst_type) { - // go deeper - cur_type = dst_type; - cur_repr = next_repr.clone(); - } else { - if let Some(constructor) = morphism_constructors.get(&MorphismType { - mode: MorphismMode::Mono, - src_type: cur_type.clone(), - dst_type: dst_type.clone(), - }) { - let new_obj = constructor(Object { - type_tag: cur_type.clone(), - repr: cur_repr - .read() - .unwrap() - .branches - .get(&cur_type) - .unwrap() - .clone(), - }); - - assert!(new_obj.type_tag == dst_type); - cur_repr - .write() - .unwrap() - .insert_branch(new_obj.type_tag.clone(), new_obj.repr.clone()); - - cur_type = new_obj.type_tag; - cur_repr = new_obj.repr; - } - } - } - } - - // replace with higher-level type in which self is a repr branch - pub fn epi_cast<'a>( - &self, - _type_ladder: impl Iterator<Item = TypeTerm>, - _morphism_constructors: &HashMap<MorphismType, Box<dyn Fn(Object) -> Object>>, - ) { - // todo -} - */ -} - diff --git a/nested/src/utils/bimap.rs b/nested/src/utils/bimap.rs deleted file mode 100644 index 8bd41b6..0000000 --- a/nested/src/utils/bimap.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::{collections::HashMap, hash::Hash}; - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> - -pub struct Bimap<V: Eq + Hash, Λ: Eq + Hash> { - pub mλ: HashMap<V, Λ>, - pub my: HashMap<Λ, V>, -} - -impl<V: Eq + Hash + Clone, Λ: Eq + Hash + Clone> Bimap<V, Λ> { - pub fn new() -> Self { - Bimap { - mλ: HashMap::new(), - my: HashMap::new(), - } - } - - pub fn insert(&mut self, y: V, λ: Λ) { - self.mλ.insert(y.clone(), λ.clone()); - self.my.insert(λ, y); - } -} - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> diff --git a/nested/src/utils/mod.rs b/nested/src/utils/mod.rs deleted file mode 100644 index fe10469..0000000 --- a/nested/src/utils/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod bimap; -pub mod modulo; -pub mod color; - -pub use modulo::modulo; -pub use bimap::Bimap; diff --git a/terminal/ansi_parser/Cargo.toml b/srv-pty-capture/Cargo.toml similarity index 71% rename from terminal/ansi_parser/Cargo.toml rename to srv-pty-capture/Cargo.toml index 2b1ca1d..3453d45 100644 --- a/terminal/ansi_parser/Cargo.toml +++ b/srv-pty-capture/Cargo.toml @@ -1,11 +1,12 @@ [package] authors = ["Michael Sippel <micha@fragmental.art>"] -name = "ansi_parser" +name = "srv-pty-capture" version = "0.1.0" edition = "2018" [dependencies] -nested = { path = "../../nested" } +nested = { path = "../lib-nested-core" } +nested-tty = { path = "../lib-nested-tty" } cgmath = { version = "0.18.0", features = ["serde"] } serde = { version = "1.0", features = ["serde_derive"] } bincode = "1.3.3" diff --git a/terminal/ansi_parser/src/main.rs b/srv-pty-capture/src/main.rs similarity index 99% rename from terminal/ansi_parser/src/main.rs rename to srv-pty-capture/src/main.rs index 0e4d532..5d531ac 100644 --- a/terminal/ansi_parser/src/main.rs +++ b/srv-pty-capture/src/main.rs @@ -2,7 +2,7 @@ use { cgmath::Point2, - nested::terminal::{TerminalAtom, TerminalStyle}, + nested_tty::{TerminalAtom, TerminalStyle}, std::{ fs::File, io::{stdin, Read, Write}, diff --git a/terminal/display_server/Cargo.toml b/srv-tty-output/Cargo.toml similarity index 70% rename from terminal/display_server/Cargo.toml rename to srv-tty-output/Cargo.toml index 4d933da..314e9f5 100644 --- a/terminal/display_server/Cargo.toml +++ b/srv-tty-output/Cargo.toml @@ -1,11 +1,12 @@ [package] authors = ["Michael Sippel <micha@fragmental.art>"] -name = "display_server" +name = "srv-tty-output" version = "0.1.0" edition = "2018" [dependencies] -nested = { path = "../../nested" } +nested = { path = "../lib-nested-core" } +nested-tty = { path = "../lib-nested-tty" } termion = "1.5.5" cgmath = { version = "0.18.0", features = ["serde"] } serde = { version = "1.0", features = ["serde_derive"] } diff --git a/terminal/display_server/src/main.rs b/srv-tty-output/src/main.rs similarity index 97% rename from terminal/display_server/src/main.rs rename to srv-tty-output/src/main.rs index a3f52fc..46f6c6e 100644 --- a/terminal/display_server/src/main.rs +++ b/srv-tty-output/src/main.rs @@ -1,6 +1,6 @@ use { cgmath::{Point2, Vector2}, - nested::terminal::{TerminalAtom, TerminalStyle}, + nested_tty::{TerminalAtom, TerminalStyle}, std::io::{stdout, Read, Write}, termion::raw::IntoRawMode, };