diff --git a/shell/src/list.rs b/shell/src/list.rs new file mode 100644 index 0000000..da29c73 --- /dev/null +++ b/shell/src/list.rs @@ -0,0 +1,167 @@ + +use { + std::sync::Arc, + std::sync::RwLock, + nested::{ + core::{ + View, + ViewPort, + OuterViewPort, + InnerViewPort, + Observer, + ObserverBroadcast + }, + sequence::{SequenceView, VecBuffer}, + terminal::{Terminal, TerminalAtom, TerminalStyle}, + projection::ProjectionHelper + } +}; + +pub struct ListDecorator { + opening_port: OuterViewPort>, + closing_port: OuterViewPort>, + delim_port: OuterViewPort>, + items: Arc>>>, + list_style: TerminalStyle, + item_style: TerminalStyle, + + cast: Arc>>>>>, + proj_helper: ProjectionHelper +} + +impl View for ListDecorator { + type Msg = usize; +} + +impl SequenceView for ListDecorator { + type Item = OuterViewPort>; + + fn len(&self) -> Option { + Some(self.items.len()? * 2 + 1) + } + + fn get(&self, idx: &usize) -> Option { + let item_idx = idx / 2; + let list_style = self.list_style.clone(); + let item_style = self.item_style.clone(); + Some( + if idx % 2 == 0 { + if item_idx == 0 { + self.opening_port.clone() + } else if item_idx == self.items.len().unwrap_or(0) { + self.closing_port.clone() + } else { + self.delim_port.clone() + } + .map(move |c| TerminalAtom::new(*c, list_style)) + } else { + self.items + .get(&item_idx)? + .map(move |atom| atom.add_style_back(item_style)) + } + ) + } +} + +impl ListDecorator { + pub fn new( + opening_port: OuterViewPort>, + closing_port: OuterViewPort>, + delim_port: OuterViewPort>, + items_port: OuterViewPort>>>, + list_style: TerminalStyle, + item_style: TerminalStyle, + out_port: InnerViewPort>>> + ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); + + let li = Arc::new(RwLock::new(ListDecorator { + opening_port, + closing_port, + delim_port, + items: proj_helper.new_sequence_arg( + items_port, + |s: &mut Self, item_idx| { + s.cast.notify(&(item_idx * 2)); + s.cast.notify(&(item_idx * 2 + 1)); + } + ), + list_style, + item_style, + cast: out_port.get_broadcast(), + proj_helper + })); + + out_port.set_view(Some(li.clone())); + li + } + + pub fn lisp_style( + level: usize, + items_port: OuterViewPort>>>, + out_port: InnerViewPort>>> + ) -> Arc> { + let opening_port = ViewPort::new(); + let opening = VecBuffer::::with_data("(".chars().collect(), opening_port.inner()); + + let closing_port = ViewPort::new(); + let closing = VecBuffer::::with_data(")".chars().collect(), closing_port.inner()); + + let delim_port = ViewPort::new(); + let delim = VecBuffer::::with_data(" ".chars().collect(), delim_port.inner()); + + Self::new( + opening_port.outer().to_sequence(), + closing_port.outer().to_sequence(), + delim_port.outer().to_sequence(), + items_port, + TerminalStyle::fg_color( + match level { + 0 => (200, 120, 10), + 1 => (120, 200, 10), + _ => (255, 255, 255) + } + ), + TerminalStyle::fg_color( + match level { + _ => (255, 255, 255) + } + ), + out_port + ) + } + + pub fn c_style( + level: usize, + items_port: OuterViewPort>>>, + out_port: InnerViewPort>>> + ) -> Arc> { + let opening_port = ViewPort::new(); + let opening = VecBuffer::::with_data("{".chars().collect(), opening_port.inner()); + + let closing_port = ViewPort::new(); + let closing = VecBuffer::::with_data("}".chars().collect(), closing_port.inner()); + + let delim_port = ViewPort::new(); + let delim = VecBuffer::::with_data(", ".chars().collect(), delim_port.inner()); + + Self::new( + opening_port.outer().to_sequence(), + closing_port.outer().to_sequence(), + delim_port.outer().to_sequence(), + items_port, + TerminalStyle::fg_color( + match level { + _ => (255, 255, 255) + } + ), + TerminalStyle::fg_color( + match level { + _ => (255, 255, 255) + } + ), + out_port + ) + } +} + diff --git a/shell/src/main.rs b/shell/src/main.rs index 96f8f50..a324156 100644 --- a/shell/src/main.rs +++ b/shell/src/main.rs @@ -24,6 +24,8 @@ use { } }; +pub mod list; + #[async_std::main] async fn main() { /* todo: @@ -282,7 +284,7 @@ write:: let hex_label = VecBuffer::::with_data("x0".chars().collect(), hex_label_port.inner()); let delim_port = ViewPort::new(); - let delim = VecBuffer::::with_data(" ,".chars().collect(), delim_port.inner()); + let delim = VecBuffer::::with_data(",".chars().collect(), delim_port.inner()); let closing_port = ViewPort::new(); let closing = VecBuffer::::with_data("[".chars().collect(), closing_port.inner()); @@ -337,17 +339,55 @@ write:: ); } - compositor.write().unwrap().push( - arg1_hex_unic_port - .to_index() - .map_key( - |idx| Point2::new(40 - *idx as i16, 3 as i16), - |pt| if pt.y == 3 { Some(40 - pt.x as usize) } else { None } - ) - .map_item( - |_idx, digit| TerminalAtom::from(digit) - ) - ); + { + let items_port = ViewPort::new(); + let items = VecBuffer::with_data( + vec![ + arg1_dec_mint_port + .map(|val| char::from_digit(*val as u32, 16).unwrap()) + .map(|c| TerminalAtom::from(c)), + arg1_hex_unic_port.clone() + .map(|c| TerminalAtom::from(c)), + arg1_hex_unic_port.clone() + .map(|c| TerminalAtom::from(c)), + ], + items_port.inner() + ); + + let liport = ViewPort::new(); + let list_decorator = list::ListDecorator::lisp_style( + 1, + items_port.outer().to_sequence(), + liport.inner() + ); + + let par_items_port = ViewPort::new(); + let par_items = VecBuffer::with_data( + vec![ + liport.outer().flatten(), + arg1_hex_unic_port.clone() + .map(|c| TerminalAtom::from(c)), + ], + par_items_port.inner() + ); + + let par_liport = ViewPort::new(); + let par_list_decorator = list::ListDecorator::lisp_style( + 0, + par_items_port.outer().to_sequence(), + par_liport.inner() + ); + + compositor.write().unwrap().push( + par_liport.outer() + .flatten() + .to_index() + .map_key( + |idx| Point2::new(*idx as i16, 3), + |pt| if pt.y == 3 { Some(pt.x as usize) } else { None } + ) + ); + } let magic_vec_port = ViewPort::new(); let _magic_vec = VecBuffer::with_data("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>".chars().collect::>(), magic_vec_port.inner()); @@ -393,7 +433,7 @@ write:: TerminalEvent::Input(Event::Key(Key::Home)) => ed.goto_end(), TerminalEvent::Input(Event::Key(Key::End)) => ed.goto(0), TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {}, - TerminalEvent::Input(Event::Key(Key::Char(c))) => { ed.insert(c); ed.prev() }, + TerminalEvent::Input(Event::Key(Key::Char(c))) => { ed.insert(c); ed.prev(); }, TerminalEvent::Input(Event::Key(Key::Delete)) => ed.delete_prev(), TerminalEvent::Input(Event::Key(Key::Backspace)) => ed.delete(), TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break,