diff --git a/nested/src/lib.rs b/nested/src/lib.rs index 64f83b1..67d33e4 100644 --- a/nested/src/lib.rs +++ b/nested/src/lib.rs @@ -10,6 +10,7 @@ pub mod sequence; pub mod vec; pub mod terminal; pub mod integer; +pub mod list; pub mod string_editor; pub mod leveled_term_view; diff --git a/nested/src/list/editor.rs b/nested/src/list/editor.rs new file mode 100644 index 0000000..ea0c6ae --- /dev/null +++ b/nested/src/list/editor.rs @@ -0,0 +1,427 @@ +use { + std::sync::{Arc, RwLock}, + termion::event::{Event, Key}, + crate::{ + core::{ + View, + ViewPort, + OuterViewPort, + InnerViewPort, + ObserverBroadcast, + Observer, + ObserverExt, + context::{ + ReprTree, + Object, + MorphismType, + MorphismMode, + Context + } + }, + projection::ProjectionHelper, + singleton::{SingletonView, SingletonBuffer}, + sequence::{SequenceView}, + vec::{VecBuffer}, + terminal::{ + TerminalView, + TerminalStyle, + TerminalEvent, + TerminalEditor, + TerminalEditorResult, + make_label + }, + string_editor::StringEditor, + leveled_term_view::LeveledTermView, + list::SExprView + } +}; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum ListEditorCursor { + None, + Insert(usize), + Select(usize), + Edit(usize) +} + +impl Default for ListEditorCursor { + fn default() -> Self { + ListEditorCursor::None + } +} + +pub struct ListEditor +where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static, + FnMakeItemEditor: Fn() -> Arc> +{ + cursor: SingletonBuffer, + data: VecBuffer>>, + data_sequence_port: OuterViewPort>>>, + make_item_editor: FnMakeItemEditor, + level: usize, + pub segment_seq: OuterViewPort>>, +} + +impl TerminalEditor for ListEditor +where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static, + FnMakeItemEditor: Fn() -> Arc> +{ + fn get_term_view(&self) -> OuterViewPort { + self.segment_seq.horizontal_sexpr_view(0) + } + + fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { + match self.cursor.get() { + ListEditorCursor::None => { + + } + ListEditorCursor::Insert(idx) => { + match event { + TerminalEvent::Input(Event::Key(Key::Insert)) => { + self.cursor.set(ListEditorCursor::Select(idx)); + } + TerminalEvent::Input(Event::Key(Key::Left)) => { + if idx > 0 { + self.cursor.set(ListEditorCursor::Insert(idx-1)); + } + } + TerminalEvent::Input(Event::Key(Key::Right)) => { + if idx < self.data.len() { + self.cursor.set(ListEditorCursor::Insert(idx+1)); + } + } + event => { + self.data.insert(idx, (self.make_item_editor)()); + self.cursor.set(ListEditorCursor::Edit(idx)); + self.data.get_mut(idx).write().unwrap().handle_terminal_event(event); + } + } + } + ListEditorCursor::Select(idx) => { + match event { + TerminalEvent::Input(Event::Key(Key::Insert)) => { + self.cursor.set(ListEditorCursor::Insert(idx)); + } + TerminalEvent::Input(Event::Key(Key::Delete)) => { + self.data.remove(idx); + if self.data.len() == 0 { + self.cursor.set(ListEditorCursor::Insert(0)); + } else if idx == self.data.len() && idx > 0 { + self.cursor.set(ListEditorCursor::Select(idx-1)) + } + } + TerminalEvent::Input(Event::Key(Key::Home)) => { + if self.data.len() > 0 { + self.cursor.set(ListEditorCursor::Select(0)) + } else { + self.cursor.set(ListEditorCursor::Insert(0)) + } + } + TerminalEvent::Input(Event::Key(Key::End)) => { + if self.data.len() > 0 { + self.cursor.set(ListEditorCursor::Select(self.data.len() - 1)) + } else { + self.cursor.set(ListEditorCursor::Insert(0)) + } + } + TerminalEvent::Input(Event::Key(Key::Left)) => { + if idx > 0 { + self.cursor.set(ListEditorCursor::Select(idx - 1)); + } + } + TerminalEvent::Input(Event::Key(Key::Right)) => { + if idx+1 < self.data.len() { + self.cursor.set(ListEditorCursor::Select(idx + 1)); + } + } + event => { + self.cursor.set(ListEditorCursor::Edit(idx)); + self.data.get_mut(idx).write().unwrap().handle_terminal_event(event); + } + } + } + ListEditorCursor::Edit(idx) => { + match event { + TerminalEvent::Input(Event::Key(Key::Char('\t'))) => { + if idx > 0 { + self.cursor.set(ListEditorCursor::Edit(idx-1)); + } + } + TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { + if idx+1 < self.data.len() { + self.cursor.set(ListEditorCursor::Edit(idx+1)); + } + } + TerminalEvent::Input(Event::Key(Key::Char(' '))) => { + // split.. + self.data.insert(idx+1, (self.make_item_editor)()); + self.data.get_mut(idx).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End))); + self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home))); + self.cursor.set(ListEditorCursor::Edit(idx+1)); + } + event => { + let ce = self.data.get_mut(idx); + let mut cur_edit = ce.write().unwrap(); + match cur_edit.handle_terminal_event(event) { + TerminalEditorResult::Exit => { + match event { + TerminalEvent::Input(Event::Key(Key::Up)) => { + self.cursor.set(ListEditorCursor::Select(idx)); + } + TerminalEvent::Input(Event::Key(Key::Home)) => { + if idx > 0 { + self.cursor.set(ListEditorCursor::Edit(idx-1)); + self.data.get_mut(idx-1).write().unwrap().handle_terminal_event(event); + } else { + cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home))); + } + } + TerminalEvent::Input(Event::Key(Key::Backspace)) | // -> join + TerminalEvent::Input(Event::Key(Key::Left)) => { + if idx > 0 { + self.cursor.set(ListEditorCursor::Edit(idx-1)); + self.data.get_mut(idx-1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End))); + } else { + cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home))); + } + } + TerminalEvent::Input(Event::Key(Key::End)) => { + if idx+1 < self.data.len() { + self.cursor.set(ListEditorCursor::Edit(idx+1)); + self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(event); + } else if idx+1 == self.data.len() { + cur_edit.handle_terminal_event(event); + } + } + TerminalEvent::Input(Event::Key(Key::Delete)) | + TerminalEvent::Input(Event::Key(Key::Right)) => { + if idx+1 < self.data.len() { + self.cursor.set(ListEditorCursor::Edit(idx+1)); + self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home))); + } else if idx+1 == self.data.len() { + cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End))); + } + } + _ => {} + } + } + TerminalEditorResult::Continue => {} + } + } + } + } + } + + TerminalEditorResult::Continue + } +} + +enum ListEditorViewSegment { + InsertCursor, + View(OuterViewPort), + Select(OuterViewPort), + Edit(OuterViewPort) +} + +struct ListEditorView { + cursor: Arc>, + data: Arc>>, + cur_cursor: ListEditorCursor, + + cast: Arc>>>, + proj_helper: ProjectionHelper +} + +impl View for ListEditorView { + type Msg = usize; +} + +impl SequenceView for ListEditorView { + type Item = ListEditorViewSegment; + + fn len(&self) -> Option { + match self.cur_cursor { + ListEditorCursor::None => self.data.len(), + ListEditorCursor::Select(_) => self.data.len(), + ListEditorCursor::Edit(_) => self.data.len(), + ListEditorCursor::Insert(_) => Some(self.data.len()? + 1) + } + } + + fn get(&self, idx: &usize) -> Option { + Some( + match self.cur_cursor { + ListEditorCursor::None => + ListEditorViewSegment::View(self.data.get(idx)?), + ListEditorCursor::Select(c) => + if *idx == c { + ListEditorViewSegment::Select(self.data.get(idx)?) + } else { + ListEditorViewSegment::View(self.data.get(idx)?) + }, + ListEditorCursor::Edit(c) => + if *idx == c { + ListEditorViewSegment::Edit(self.data.get(idx)?) + } else { + ListEditorViewSegment::View(self.data.get(idx)?) + }, + ListEditorCursor::Insert(c) => + if *idx < c { + ListEditorViewSegment::View(self.data.get(idx)?) + } else if *idx == c { + ListEditorViewSegment::InsertCursor + } else { + ListEditorViewSegment::View(self.data.get(&(idx-1))?) + }, + } + ) + } +} + +impl ListEditorView { + fn new( + cursor_port: OuterViewPort>, + data_port: OuterViewPort>>, + out_port: InnerViewPort> + ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); + let proj = Arc::new(RwLock::new( + ListEditorView { + cur_cursor: ListEditorCursor::None, + cursor: proj_helper.new_singleton_arg( + cursor_port, + |s: &mut Self, _msg| { + let old_cursor = s.cur_cursor; + let new_cursor = s.cursor.get(); + s.cur_cursor = new_cursor; + + let mut begin = std::cmp::min( + match old_cursor { + ListEditorCursor::None => usize::MAX, + ListEditorCursor::Select(c) => c, + ListEditorCursor::Insert(c) => c, + ListEditorCursor::Edit(c) => c + }, + match new_cursor { + ListEditorCursor::None => usize::MAX, + ListEditorCursor::Select(c) => c, + ListEditorCursor::Insert(c) => c, + ListEditorCursor::Edit(c) => c + } + ); + let mut end = + /* + match (old_cursor, new_cursor) { + (ListEditorCursor::None, ListEditorCursor::None) => usize::MAX, + (ListEditorCursor::Select(old_pos), ListEditorCursor::Select(new_pos)) => max(old_pos, new_pos), + (ListEditorCursor::Edit(old_pos), ListEditorCursor::Edit(new_pos)) => max(old_pos, new_pos), + (ListEditorCursor::Insert(old_pos), ListEditorCursor::Insert(new_pos)) => max(old_pos, new_pos), + (ListEditorCursor::) + }; +*/ + std::cmp::max( + match old_cursor { + ListEditorCursor::None => 0, + ListEditorCursor::Select(c) => c, + ListEditorCursor::Insert(c) => c+1, + ListEditorCursor::Edit(c) => c + }, + match new_cursor { + ListEditorCursor::None => 0, + ListEditorCursor::Select(c) => c, + ListEditorCursor::Insert(c) => c+1, + ListEditorCursor::Edit(c) => c + } + ); + + s.cast.notify_each( + begin ..= end + ); + }), + data: proj_helper.new_sequence_arg( + data_port, + |s: &mut Self, idx| { + match s.cur_cursor { + ListEditorCursor::None => s.cast.notify(idx), + ListEditorCursor::Select(c) => s.cast.notify(idx), + ListEditorCursor::Edit(c) => s.cast.notify(idx), + ListEditorCursor::Insert(c) => + if *idx < c { + s.cast.notify(idx) + } else { + s.cast.notify(&(*idx + 1)) + } + } + }), + cast: out_port.get_broadcast(), + proj_helper + } + )); + + proj.write().unwrap().proj_helper.set_proj(&proj); + out_port.set_view(Some(proj.clone())); + + proj + } +} + +impl ListEditor +where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static, + FnMakeItemEditor: Fn() -> Arc> +{ + pub fn new(make_item_editor: FnMakeItemEditor) -> Self { + let cursor_port = ViewPort::new(); + let data_port = ViewPort::new(); + + let mut cursor = SingletonBuffer::new(ListEditorCursor::Insert(0), cursor_port.inner()); + let mut data = VecBuffer::>>::new(data_port.inner()); + + let data_sequence_port = data_port.into_outer().to_sequence(); + + let segment_view_port = ViewPort::>::new(); + let segment_view = ListEditorView::new( + cursor_port.outer(), + data_sequence_port.map(|ed| ed.read().unwrap().get_term_view()), + segment_view_port.inner() + ); + + ListEditor { + data, + data_sequence_port, + cursor, + make_item_editor, + level: 0, + segment_seq: segment_view_port + .outer() + .map( + |segment| match segment { + ListEditorViewSegment::InsertCursor => + make_label("|") + .map_item( + |_pt, atom| + atom.add_style_back(TerminalStyle::fg_color((90,60,200))) + .add_style_back(TerminalStyle::bold(true)) + ), + ListEditorViewSegment::Select(sub_view) => + sub_view.map_item( + |_pt, atom| + atom.add_style_back(TerminalStyle::bg_color((90,60,200))) + ), + ListEditorViewSegment::Edit(sub_view) => + sub_view.map_item( + |_pt, atom| + atom.add_style_back(TerminalStyle::bg_color((0,0,0))) + .add_style_back(TerminalStyle::bold(true)) + ), + ListEditorViewSegment::View(sub_view) => + sub_view.clone() + } + ) + } + } + + pub fn get_data_port(&self) -> OuterViewPort>>> { + self.data_sequence_port.clone() + } +} + diff --git a/nested/src/list/mod.rs b/nested/src/list/mod.rs new file mode 100644 index 0000000..0888a48 --- /dev/null +++ b/nested/src/list/mod.rs @@ -0,0 +1,7 @@ + +pub mod editor; +pub mod sexpr; + +pub use editor::ListEditor; +pub use sexpr::SExprView; + diff --git a/nested/src/list/sexpr.rs b/nested/src/list/sexpr.rs new file mode 100644 index 0000000..9496d5b --- /dev/null +++ b/nested/src/list/sexpr.rs @@ -0,0 +1,283 @@ +use { + std::sync::Arc, + std::sync::RwLock, + cgmath::{Point2}, + crate::{ + core::{ + View, + ViewPort, + OuterViewPort, + InnerViewPort, + Observer, + ObserverBroadcast + }, + sequence::{SequenceView}, + terminal::{TerminalStyle, TerminalView, make_label}, + 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 { + let l = self.items.len()?; + Some(if l == 0 { 2 } else { 2*l + 2 }) + } + + 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(); + let l = self.items.len().unwrap_or(0); + Some( + if *idx == 0 { + self.opening_port.clone() + .map_item(move |_, atom| atom.add_style_back(list_style)) + } else if (l == 0 && *idx == 1) || *idx == 2*l { + self.closing_port.clone() + .map_item(move |_, atom| atom.add_style_back(list_style)) + } else if idx % 2 == 0 { + self.delim_port.clone() + .map_item(move |_, atom| atom.add_style_back(list_style)) + } else { + self.items + .get(&item_idx)? + .map_item(move |_, atom| atom.add_style_back(item_style)) + } + ) + } +} + +impl ListDecorator { + pub fn new( + opening: &str, + closing: &str, + delim: &str, + level: usize, + items_port: OuterViewPort>>, + 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: make_label(opening), + closing_port: make_label(closing), + delim_port: make_label(delim), + items: proj_helper.new_sequence_arg( + items_port, + |s: &mut Self, item_idx| { + s.cast.notify( + &(*item_idx * 2 + 1) + ); + s.cast.notify( + &(*item_idx * 2 + 2) + ); + } + ), + list_style: TerminalStyle::fg_color( + match level { + 0 => (200, 120, 10), + 1 => (120, 200, 10), + _ => (255, 255, 255) + } + ), + item_style: TerminalStyle::fg_color( + match level { + _ => (255, 255, 255) + } + ), + cast: out_port.get_broadcast(), + proj_helper + })); + + li.write().unwrap().proj_helper.set_proj(&li); + + out_port.set_view(Some(li.clone())); + li + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +use crate::{index::IndexView, grid::GridView}; + +pub struct VerticalSexprDecorator { + opening_port: OuterViewPort, + closing_port: OuterViewPort, + items: Arc>>, + + list_style: TerminalStyle, + item_style: TerminalStyle, + + cast: Arc>>>>, + proj_helper: ProjectionHelper +} + +impl View for VerticalSexprDecorator { + type Msg = Point2; +} + +impl IndexView> for VerticalSexprDecorator { + type Item = OuterViewPort; + + fn area(&self) -> Option>> { + let mut area = (0 .. self.items.len()?).map(|i| Point2::new(1 as i16, i as i16)).collect::>(); + area.push(Point2::new(0, 0)); + area.push(Point2::new(2, self.items.len()? as i16 - 1)); + Some(area) + } + + fn get(&self, pt: &Point2) -> Option { + let item_idx = pt.y as usize; + let list_style = self.list_style.clone(); + let item_style = self.item_style.clone(); + let l = self.items.len().unwrap_or(0); + + match pt.x { + 0 => { + if pt.y == 0 { + Some(self.opening_port.clone() + .map_item(move |_, atom| atom.add_style_back(list_style))) + } else { + None + } + } + 1 => { + if item_idx < l { + Some(self.items.get(&item_idx)?.map_item(move |_, atom| atom.add_style_back(item_style))) + } else { + None + } + } + 2 => { + if (l == 0 && pt.y == 0) || (item_idx+1 == l) { + Some(self.closing_port.clone() + .map_item(move |_, atom| atom.add_style_back(list_style))) + } else { + None + } + } + _ => None + } + } +} + +impl VerticalSexprDecorator { + pub fn new( + opening: &str, + closing: &str, + level: usize, + items_port: OuterViewPort>>, + out_port: InnerViewPort>> + ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone()); + + let li = Arc::new(RwLock::new(VerticalSexprDecorator { + opening_port: make_label(opening), + closing_port: make_label(closing), + items: proj_helper.new_sequence_arg( + items_port, + |s: &mut Self, item_idx| { + s.cast.notify( + &Point2::new(1, *item_idx as i16) + ); + s.cast.notify( + &Point2::new(2, *item_idx as i16 - 1) + ); + s.cast.notify( + &Point2::new(2, *item_idx as i16) + ); + } + ), + list_style: TerminalStyle::fg_color( + match level { + 0 => (200, 120, 10), + 1 => (120, 200, 10), + _ => (255, 255, 255) + } + ), + item_style: TerminalStyle::fg_color( + match level { + _ => (255, 255, 255) + } + ), + cast: out_port.get_broadcast(), + proj_helper + })); + + li.write().unwrap().proj_helper.set_proj(&li); + + out_port.set_view(Some(li.clone())); + li + } +} + + +pub trait SExprView { + fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort; + fn vertical_bar_view(&self, level: usize) -> OuterViewPort; + fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort; +} + +impl SExprView for OuterViewPort>> { + fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort { + let port = ViewPort::new(); + ListDecorator::new( + "(", ")", " ", + level, + self.clone(), + port.inner() + ); + + port.into_outer() + .to_grid_horizontal() + .flatten() + } + + fn vertical_bar_view(&self, level: usize) -> OuterViewPort { + let port = ViewPort::new(); + ListDecorator::new( + "Λ", "V", "|", + level, + self.clone(), + port.inner() + ); + + port.into_outer() + .to_grid_vertical() + .flatten() + } + + fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort { + let port = ViewPort::new(); + VerticalSexprDecorator::new( + "(", ")", + level, + self.clone(), + port.inner() + ); + port.into_outer() + .flatten() + } +} + diff --git a/shell/src/list.rs b/shell/src/list.rs deleted file mode 100644 index da29c73..0000000 --- a/shell/src/list.rs +++ /dev/null @@ -1,167 +0,0 @@ - -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 a324156..c12b2fc 100644 --- a/shell/src/main.rs +++ b/shell/src/main.rs @@ -1,30 +1,53 @@ -use { - std::sync::RwLock, - cgmath::Point2, + +//mod monstera; + +use{ + std::sync::{Arc, RwLock}, + cgmath::{Point2, Vector2}, termion::event::{Event, Key}, nested::{ core::{ + View, ViewPort, OuterViewPort, - context::{ - ReprTree, - Object, - MorphismType, - MorphismMode, - Context - }, - port::{ - UpdateTask - } - }, - sequence::{SequenceView, VecBuffer}, + Observer, + ObserverExt, + context::{ReprTree, Object, MorphismType, MorphismMode, Context}, + port::{UpdateTask}}, + index::{IndexView}, + sequence::{SequenceView}, + vec::{VecBuffer}, integer::{RadixProjection}, - terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalCompositor, TerminalEvent}, - string_editor::StringEditor + terminal::{ + Terminal, + TerminalStyle, + TerminalAtom, + TerminalCompositor, + TerminalEvent, + make_label, + TerminalView, + TerminalEditor}, + string_editor::StringEditor, + list::{SExprView, ListEditor} } }; -pub mod list; +struct GridFill(T); +impl View for GridFill { + type Msg = Point2; +} + +impl IndexView> for GridFill { + type Item = T; + + fn area(&self) -> Option>> { + None + } + + fn get(&self, _: &Point2) -> Option { + Some(self.0.clone()) + } +} #[async_std::main] async fn main() { @@ -58,25 +81,27 @@ write:: */ let mut args = std::env::args(); - +/* let arg0_port = ViewPort::new(); let _arg0 = VecBuffer::::with_data( args.next().expect("Arg $0 missing!") .chars().collect::>(), arg0_port.inner() ); -/* +*/ let arg1_vec_port = ViewPort::new(); let mut arg1 = VecBuffer::::with_data( + vec!['1'], +/* args.next().expect("Arg $1 missing!") .chars().collect::>(), +*/ arg1_vec_port.inner() ); -*/ - - let arg1_vec = args.next().expect("Arg $1 missing!") +/* + let _arg1_vec = args.next().expect("Arg $1 missing!") .chars().collect::>(); - +*/ let term_port = ViewPort::new(); let compositor = TerminalCompositor::new(term_port.inner()); @@ -171,7 +196,7 @@ write:: }) ); */ - + let arg1_vec_port = ed.get_data_port(); ctx.add_obj("$1".into(), "( Vec UnicodeChar )"); @@ -247,202 +272,242 @@ write:: arg1_hex_unic_port.clone().into() ); - compositor.write().unwrap().push( - ed.insert_view() - .map_key( - |pt| Point2::new(40 as i16 - pt.x, 1 as i16), - |pt| if pt.y == 1 { Some(Point2::new(40 as i16 - pt.x, 0)) } else { None } - ) + let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>") .map_item( - |_pos, atom| - TerminalAtom::new( - atom.c.unwrap_or(' '), + |pos, atom| + atom.add_style_back( TerminalStyle::fg_color( - if let Some(c) = atom.c { - if c == '|' { - (200, 200, 90) - } else if c.is_digit(10) { - (0, 200, 0) - } else { - (255, 0, 0) - } - } else { - (0, 0, 0) - } + (5, + ((80+(pos.x*30)%100) as u8), + (55+(pos.x*15)%180) as u8) ) ) - ) - ); - - let opening_port = ViewPort::new(); - let opening = VecBuffer::::with_data("]".chars().collect(), opening_port.inner()); - - let dec_label_port = ViewPort::new(); - let dec_label = VecBuffer::::with_data("d0".chars().collect(), dec_label_port.inner()); - - let hex_label_port = ViewPort::new(); - 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 closing_port = ViewPort::new(); - let closing = VecBuffer::::with_data("[".chars().collect(), closing_port.inner()); - for c in arg1_vec { - ed.insert(c); - ed.prev(); - } + ); { - let tree_port = ViewPort::new(); - let mut tree = VecBuffer::with_data( - vec![ - opening_port.outer() - .to_sequence() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))), - - arg1_dec_mint_port - .map(|val| char::from_digit(*val as u32, 16).unwrap()) - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((255, 255, 255)))), - - dec_label_port.outer() - .to_sequence() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 170)))), - - delim_port.outer() - .to_sequence() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))), - - arg1_hex_unic_port.clone() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((255, 255, 255)))), - - hex_label_port.outer() - .to_sequence() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 170)))), - - closing_port.outer() - .to_sequence() - .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))), - ], - tree_port.inner() - ); - - compositor.write().unwrap().push( - tree_port.outer() - .to_sequence() - .flatten() - .to_index() - .map_key( - |idx| Point2::new(40 - *idx as i16, 2 as i16), - |pt| if pt.y == 2 { Some(40 - pt.x as usize) } else { None } - ) - ); + compositor.write().unwrap().push(magic.offset(Vector2::new(40, 4))); + //compositor.write().unwrap().push(magic.offset(Vector2::new(40, 20))); +/* + let monstera_port = monstera::make_monstera(); + compositor.write().unwrap().push(monstera_port.clone()); + compositor.write().unwrap().push(monstera_port.offset(Vector2::new(83,0))); +*/ } +/* + + // list views { 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)), + .map(|c| TerminalAtom::from(c)) + .to_index() + .map_key( + |idx| Point2::new(*idx as i16, 0 as i16), + |pt| if pt.y == 0 { Some(pt.x as usize) } else { None } + ), + ed.insert_view() + .map_item( + |_pos, atom| + TerminalAtom::new( + atom.c.unwrap_or(' '), + TerminalStyle::fg_color( + if let Some(c) = atom.c { + if c == '|' { + (200, 200, 90) + } else if c.is_digit(10) { + (0, 200, 0) + } else { + (255, 0, 0) + } + } else { + (0, 0, 0) + } + ).add( + TerminalStyle::bg_color((0,0,0)) + ) + ) + ), arg1_hex_unic_port.clone() - .map(|c| TerminalAtom::from(c)), + .map(|c| TerminalAtom::from(c)) + .to_index() + .map_key( + |idx| Point2::new(*idx as i16, 0 as i16), + |pt| if pt.y == 0 { Some(pt.x as usize) } else { None } + ), ], 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(), + items_port.outer().to_sequence().sexpr_view(1), arg1_hex_unic_port.clone() - .map(|c| TerminalAtom::from(c)), + .map(|c| TerminalAtom::from(c)) + .to_index() + .map_key( + |idx| Point2::new(*idx as i16, 0 as i16), + |pt| if pt.y == 0 { Some(pt.x as usize) } else { None } + ), ], 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 } - ) + par_items_port.outer() + .to_sequence() + .sexpr_view(0) + .offset(Vector2::new(45, 5)) ); } - let magic_vec_port = ViewPort::new(); - let _magic_vec = VecBuffer::with_data("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>".chars().collect::>(), magic_vec_port.inner()); + for c in _arg1_vec { + ed.insert(c); + } +*/ + + let cur_size_port = ViewPort::new(); + let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner()); + +// compositor.write().unwrap() +// .push( + let label_port = cur_size_port.outer() + .map( + |size| make_label(format!("Current Size: {:?}", size).as_str()) + ); +// ); + + //term_port.update(); + //eprintln!("start loop:"); + + { +// let history_port = ViewPort::new(); +// let mut history = VecBuffer::new(history_port.inner()); +/* + compositor.write().unwrap().push( + history_port.into_outer() + .to_sequence() + .map( + | + ) + .to_grid_vertical() + .flatten() + .offset(Vector2::new(45, 5)) + ); +*/ + }; + let mut y = 5; + + + // TypeEditor + + let make_sub_editor = || { + std::sync::Arc::new(std::sync::RwLock::new(StringEditor::new())) + }; + + let mut te = ListEditor::new(make_sub_editor.clone()); compositor.write().unwrap().push( - magic_vec_port.outer() - .to_sequence() - .to_index() - .map_item( - |idx, c| TerminalAtom::new( - *c, - TerminalStyle::fg_color((5, ((80+(idx*30)%100) as u8), (55+(idx*15)%180) as u8)) - ) - ) - .map_key( - |idx| Point2::new(*idx as i16, 4), - |pt| if pt.y == 4 { Some(pt.x as usize) } else { None } - ) + te.segment_seq.horizontal_sexpr_view(0).offset(cgmath::Vector2::new(40,y)) ); + y += 1; - compositor.write().unwrap().push( - magic_vec_port.outer() - .to_sequence() - .to_index() - .map_item( - |idx, c| TerminalAtom::new( - *c, - TerminalStyle::fg_color((5, ((80+(idx*30)%100) as u8), (55+(idx*15)%180) as u8)) - ) - ) - .map_key( - |idx| Point2::new(*idx as i16, 0), - |pt| if pt.y == 0 { Some(pt.x as usize) } else { None } - ) - ); - - term_port.update(); + let mut p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port()); loop { + term_port.update(); match term.next_event().await { - TerminalEvent::Input(Event::Key(Key::Left)) => ed.next(), - TerminalEvent::Input(Event::Key(Key::Right)) => ed.prev(), - 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::Delete)) => ed.delete_prev(), - TerminalEvent::Input(Event::Key(Key::Backspace)) => ed.delete(), - TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break, + TerminalEvent::Resize(new_size) => { + cur_size.set(new_size); + term_port.inner().get_broadcast().notify_each( + nested::grid::GridWindowIterator::from( + Point2::new(0,0) .. Point2::new(new_size.x, new_size.y) + ) + ); + } + TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) | + TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) | + TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break, + TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { + let mut strings = Vec::new(); + + let v = p.get_view().unwrap(); + for i in 0 .. v.len().unwrap_or(0) { + strings.push( + v + .get(&i).unwrap() + .get_view().unwrap() + .read().unwrap() + .iter().collect::() + ); + } + + if strings.len() == 0 { continue; } + + if let Ok(output) = + std::process::Command::new(strings[0].as_str()) + .args(&strings[1..]) + .output() + { + // take output and update terminal view + let mut line_port = ViewPort::new(); + let mut line = VecBuffer::new(line_port.inner()); + for byte in output.stdout { + match byte { + b'\n' => { + compositor.write().unwrap().push( + line_port.outer() + .to_sequence() + .map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((130,90,90)))) + .to_grid_horizontal() + .offset(Vector2::new(45, y)) + ); + y += 1; + line_port = ViewPort::new(); + line = VecBuffer::new(line_port.inner()); + } + byte => { + line.push(byte as char); + } + } + } + } else { + compositor.write().unwrap().push( + make_label("Command not found") + .map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0)))) + .offset(Vector2::new(45, y)) + ); + y+=1; + } + + te.handle_terminal_event( + &TerminalEvent::Input(Event::Key(Key::Up)) + ); + te.handle_terminal_event( + &TerminalEvent::Input(Event::Key(Key::Home)) + ); + te = ListEditor::new(make_sub_editor.clone()); + + compositor.write().unwrap().push(magic.offset(Vector2::new(40, y))); + y += 1; + compositor.write().unwrap().push( + te.segment_seq.horizontal_sexpr_view(0).offset(cgmath::Vector2::new(40,y)) + ); + y += 1; + + p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port()); + }, + ev => { + te.handle_terminal_event(&ev); + } _ => {} } - term_port.update(); } - drop(term); + //drop(term); } );