From a3d966df115acba02233e428e48f629295cd9416 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sat, 28 Aug 2021 17:01:31 +0200
Subject: [PATCH] fix some bugs and add help to demo

---
 nested/src/grid/flatten.rs  |  19 +++---
 nested/src/list/editor.rs   |  84 +++++++++++++++++++--------
 nested/src/string_editor.rs |  32 ++++++++++-
 shell/src/main.rs           | 111 +++++++++++++++++++++++-------------
 4 files changed, 173 insertions(+), 73 deletions(-)

diff --git a/nested/src/grid/flatten.rs b/nested/src/grid/flatten.rs
index 9792f7c..92c2dc2 100644
--- a/nested/src/grid/flatten.rs
+++ b/nested/src/grid/flatten.rs
@@ -115,11 +115,10 @@ where Item: 'static
                     }
                 }
             );
-/*
+
             if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
                 chunk.view = view;
             } else {
-*/
                 self.chunks.insert(
                     chunk_idx,
                     Chunk {
@@ -128,9 +127,7 @@ where Item: 'static
                         view
                     }
                 );
-                /*
             }
-             */
 
             chunk_port.0.update();
             self.update_all_offsets();
@@ -162,20 +159,24 @@ where Item: 'static
         let mut col_widths = vec![0 as i16; (top_range.end.x) as usize];
         let mut row_heights = vec![0 as i16; (top_range.end.y) as usize];
 
+        for chunk_idx in GridWindowIterator::from(self.top.range()) {
+            if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
+                let lim = chunk.view.range().end;
+                col_widths[chunk_idx.x as usize] = std::cmp::max(col_widths[chunk_idx.x as usize], lim.x);
+                row_heights[chunk_idx.y as usize] = std::cmp::max(row_heights[chunk_idx.y as usize], lim.y);
+            }
+        }
+
         for chunk_idx in GridWindowIterator::from(self.top.range()) {
             if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
                 let old_offset = chunk.offset;
                 let old_limit = chunk.limit;
 
+                chunk.limit = chunk.view.range().end;
                 chunk.offset = Vector2::new(
                     (0 .. chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
                     (0 .. chunk_idx.y as usize).map(|y| row_heights[y]).sum()
                 );
-                chunk.limit = chunk.view.range().end;
-
-                col_widths[chunk_idx.x as usize] = std::cmp::max(col_widths[chunk_idx.x as usize], chunk.limit.x);
-                row_heights[chunk_idx.y as usize] = std::cmp::max(row_heights[chunk_idx.y as usize], chunk.limit.y);
-
                 if old_offset != chunk.offset {
                     dirty_idx.extend(
                         GridWindowIterator::from(
diff --git a/nested/src/list/editor.rs b/nested/src/list/editor.rs
index 9723b77..d04b754 100644
--- a/nested/src/list/editor.rs
+++ b/nested/src/list/editor.rs
@@ -137,6 +137,17 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
     fn goto_end(&mut self) -> TreeNavResult {
         let mut cur = self.cursor.get();
         let i = cur.idx.unwrap_or(0);
+
+        if self.data.len() == 0 && cur.idx.is_none() {
+            self.cursor.set(
+                ListCursor {
+                    mode: ListCursorMode::Insert,
+                    idx: Some(0)
+                }
+            );
+            return TreeNavResult::Continue;
+        }
+        
         if i < self.data.len() {
             match cur.mode {
                 ListCursorMode::Insert => {
@@ -150,6 +161,16 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                     }
                 }
                 ListCursorMode::Select => {
+                    if self.data.len() == 0 && cur.idx.is_none() {
+                        self.cursor.set(
+                            ListCursor {
+                                mode: ListCursorMode::Insert,
+                                idx: Some(0)
+                            }
+                        );
+                        return TreeNavResult::Continue;
+                    }
+
                     if i+1 < self.data.len() || cur.idx.is_none() {
                         cur.idx = Some(self.data.len()-1);
                         self.cursor.set(cur);
@@ -170,24 +191,25 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                         }
                         TreeNavResult::Exit => {
                             drop(cur_edit);
+
                             self.up();
 
-                            if let Some(i) = cur.idx {
-                                if i+1 < self.data.len() {
-                                    self.nexd();
-                                    self.set_leaf_mode(cur_mode);
-
-                                    for x in 1 .. depth {
-                                        self.dn();
-                                        self.goto_home();
-                                    }
+                            if i+1 < self.data.len() {
+                                self.set_mode(ListCursorMode::Select);
+                                self.nexd();
 
+                                for x in 1 .. depth {
                                     self.dn();
-                                    self.goto_end();
-
-                                    return TreeNavResult::Continue;
+                                    self.goto_home();
                                 }
+
+                                self.set_leaf_mode(cur_mode);
+                                self.dn();
+                                self.goto_end();
+
+                                return TreeNavResult::Continue;
                             }
+
                             TreeNavResult::Exit
                         }
                     }
@@ -201,13 +223,23 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
 
     fn goto_home(&mut self) -> TreeNavResult {
         let cur = self.cursor.get();
+        if self.data.len() == 0 && cur.idx.is_none() {
+            self.cursor.set(
+                ListCursor {
+                    mode: ListCursorMode::Insert,
+                    idx: Some(0)
+                }
+            );
+            return TreeNavResult::Continue;
+        }
+
         match cur.mode {
             ListCursorMode::Insert |
             ListCursorMode::Select => {
                 if cur.idx != Some(0) {
                     self.cursor.set(
                         ListCursor {
-                            mode: cur.mode,
+                            mode: if self.data.len() == 0 { ListCursorMode::Insert } else { cur.mode },
                             idx: Some(0)
                         }
                     );
@@ -226,9 +258,10 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                 match cur_edit.goto_home() {
                     TreeNavResult::Exit => {
                         drop(cur_edit);
-                        self.up();
 
                         if let Some(i) = cur.idx {
+                            self.up();
+
                             if i > 0 {
                                 self.set_mode(ListCursorMode::Select);
                                 self.pxev();
@@ -331,6 +364,7 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                             self.up();
 
                             if i > 0 {
+                                self.set_mode(ListCursorMode::Select);
                                 self.pxev();
 
                                 for x in 1 .. depth {
@@ -341,7 +375,6 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                                 self.set_leaf_mode(cur_mode);
                                 self.dn();
                                 self.goto_end();
-
                                 TreeNavResult::Continue
                             } else {
                                 TreeNavResult::Exit
@@ -391,17 +424,21 @@ where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
                         TreeNavResult::Exit => {
                             drop(cur_edit);
                             drop(ce);
-                            self.up();
+                                self.up();
 
                             if i+1 < self.data.len() {
+
+                                self.set_mode(ListCursorMode::Select);
                                 self.nexd();
 
-                                for x in 0 .. depth {
+                                for x in 1 .. depth {
                                     self.dn();
                                     self.goto_home();
                                 }
 
                                 self.set_leaf_mode(cur_mode);
+                                self.dn();
+                                self.goto_home();
                                 TreeNavResult::Continue
                             } else {
                                 TreeNavResult::Exit
@@ -565,7 +602,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
                         .map_item(
                             |_pt, atom|
                             atom.add_style_back(TerminalStyle::fg_color((90,60,200)))
-                                .add_style_back(TerminalStyle::bg_color((0,0,0)))
+                                //.add_style_back(TerminalStyle::bg_color((0,0,0)))
                                 .add_style_back(TerminalStyle::bold(true))
                         ),
                     ListEditorViewSegment::Select(sub_view) =>
@@ -574,11 +611,11 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
                             atom.add_style_front(TerminalStyle::bg_color((90,60,200)))
                         ),
                     ListEditorViewSegment::Modify(sub_view) => {
-                        sub_view.map_item(
+                        sub_view.clone()/*.map_item(
                             |_pt, atom|
-                            atom.add_style_back(TerminalStyle::bg_color((0,0,0)))
-                                .add_style_back(TerminalStyle::bold(true))
-                        )
+                            atom//.add_style_back(TerminalStyle::bg_color((0,0,0)))
+                                //.add_style_back(TerminalStyle::bold(true))
+                        )*/
                     },
                     ListEditorViewSegment::View(sub_view) =>
                         sub_view.clone()
@@ -684,7 +721,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
             });
         }
     }
-    
+
     fn set_mode(&mut self, mode: ListCursorMode) {
         let mut cur = self.cursor.get();
 
@@ -699,6 +736,7 @@ where ItemEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
         }
 
         cur.mode = mode;
+
         self.cursor.set(cur);
     }
 }
diff --git a/nested/src/string_editor.rs b/nested/src/string_editor.rs
index db7a44d..477e375 100644
--- a/nested/src/string_editor.rs
+++ b/nested/src/string_editor.rs
@@ -5,7 +5,7 @@ use {
         core::{ViewPort, OuterViewPort},
         singleton::{SingletonView, SingletonBuffer},
         vec::VecBuffer,
-        terminal::{TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
+        terminal::{TerminalView, TerminalStyle, TerminalEvent, TerminalEditor, TerminalEditorResult},
         tree_nav::{TreeNav, TreeNavResult}
     }
 };
@@ -40,6 +40,10 @@ impl TerminalEditor for CharEditor {
             } else {
                 "".to_string()
             })
+            .map_item(
+                |_idx, atom|
+                atom.add_style_back(TerminalStyle::fg_color((120, 200, 10)))
+        )
     }
 
     fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
@@ -60,4 +64,30 @@ impl TerminalEditor for CharEditor {
     }
 }
 
+/*
+pub struct ArgListEditor {
+    
+}
 
+impl TreeNav for ArgListEditor {
+    
+}
+
+impl TerminalEditor for ArgListEditor {
+    fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
+        
+    }
+
+    fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
+        match event {
+            TerminalEvent::Input(Event::Key(Key::Char(' '))) => {
+                // list.get_arg()
+                // split
+            }
+            _ => {
+                
+            }
+        }
+    }
+}
+*/
diff --git a/shell/src/main.rs b/shell/src/main.rs
index b775078..e595bd8 100644
--- a/shell/src/main.rs
+++ b/shell/src/main.rs
@@ -89,45 +89,36 @@ write::
 
     async_std::task::spawn(
         async move {
+            let table_port = ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
+            let mut table_buf = nested::index::buffer::IndexBuffer::new(table_port.inner());
 
-                let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
-                    .map_item(
-                        |pos, atom|
-                        atom.add_style_back(
-                            TerminalStyle::fg_color(
-                                (5,
-                                 ((80+(pos.x*30)%100) as u8),
-                                 (55+(pos.x*15)%180) as u8)
-                            )
+            let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
+                .map_item(
+                    |pos, atom|
+                    atom.add_style_back(
+                        TerminalStyle::fg_color(
+                            (5,
+                             ((80+(pos.x*30)%100) as u8),
+                             (55+(pos.x*15)%180) as u8)
                         )
-                    );
-
-            {
-                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)));
-
-            }
+                    )
+                );
 
             let cur_size_port = ViewPort::new();
             let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10), cur_size_port.inner());
 
-            let mut y = 5;
-
             // TypeEditor
-
             let make_char_editor = || {
-                std::sync::Arc::new(std::sync::RwLock::new(DigitEditor::new(16)))
+                std::sync::Arc::new(std::sync::RwLock::new(CharEditor::new()))
+            };
+            let make_subsub_editor = move || {
+                std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_char_editor.clone(), ListEditorStyle::String)))
             };
-
             let make_sub_editor = move || {
-                std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_char_editor.clone(), ListEditorStyle::Hex)))
+                std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_subsub_editor.clone(), ListEditorStyle::HorizontalSexpr)))
             };
 
-            let mut te = ListEditor::new(make_sub_editor.clone(), ListEditorStyle::Clist);
+            let mut te = ListEditor::new(make_sub_editor.clone(), ListEditorStyle::VerticalSexpr);
 
             te.goto(
                 TreeCursor {
@@ -136,24 +127,63 @@ write::
                 }
             );
 
-            compositor.write().unwrap().push(
-                te.get_term_view()
-                    .offset(cgmath::Vector2::new(40,y))
-            );
-            y += 1;
-
             let mut p = te.get_data_port().map(|sub_editor| sub_editor.read().unwrap().get_data_port());
 
             let status_chars_port = ViewPort::new();
             let mut status_chars = VecBuffer::new(status_chars_port.inner());
 
-            compositor.write().unwrap().push(
-                status_chars_port.outer()
-                    .to_sequence()
-                    .to_grid_horizontal()
-                    .offset(cgmath::Vector2::new(40, 2))
-            );
+            let help_port = ViewPort::<dyn nested::grid::GridView<Item = OuterViewPort<dyn TerminalView>>>::new();
+            let mut help_buf = nested::index::buffer::IndexBuffer::<Point2<i16>, OuterViewPort<dyn TerminalView>>::new(help_port.inner());
 
+            let table_style = TerminalStyle::fg_color((120, 100, 80));
+            let desc_style = TerminalStyle::italic(true);
+            help_buf.insert_iter(vec![
+                (Point2::new(0, 0), make_label("CTRL+{c,d,g}").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 0), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 0), make_label("quit").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+
+                (Point2::new(0, 1), make_label("↞ ← ↑ ↓ → ↠").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 1), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 1), make_label("move cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+
+                (Point2::new(0, 3), make_label("<DEL> (Select)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 3), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 3), make_label("delete item at cursor position").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+
+                (Point2::new(0, 4), make_label("<DEL> (Insert)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 4), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 4), make_label("delete item right to cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+
+                (Point2::new(0, 5), make_label("<BACKSPACE> (Insert)").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 5), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 5), make_label("delete item left to cursor").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+
+                (Point2::new(0, 6), make_label("<TAB>").map_item(|_idx, atom| atom.add_style_back(TerminalStyle::bold(true)))),
+                (Point2::new(1, 6), make_label(" | ").map_item(move |_idx, atom| atom.add_style_back(table_style))),
+                (Point2::new(2, 6), make_label("toggle cursor mode (insert / select)").map_item(move |_idx, atom| atom.add_style_back(desc_style))),
+            ]);
+
+            let help_head = make_label("─────────────────────┬─────────────────────").map_item(move |_idx, atom| atom.add_style_back(table_style));
+
+            table_buf.insert_iter(vec![
+                (Point2::new(0, 0), magic.clone()),
+                (Point2::new(0, 2), status_chars_port.outer().to_sequence().to_grid_horizontal()),
+                (Point2::new(0, 3), te.get_term_view()),
+                (Point2::new(0, 4), make_label(" ")),
+                (Point2::new(0, 5), help_head),
+                (Point2::new(0, 6), help_port.outer().flatten()),
+                (Point2::new(0, 7), magic.clone()),
+            ]);
+
+            compositor.write().unwrap().push(monstera::make_monstera());
+            compositor.write().unwrap().push(table_port.outer().flatten().offset(Vector2::new(40, 2)));
+
+/*
+            te.get_data_port()
+                .map(
+                    |item_editor| item_editor.read().unwrap().get_data_port()
+                )
+*/
             loop {
                 term_port.update();
                 match term.next_event().await {
@@ -180,9 +210,10 @@ write::
                         }
                     }
                     TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); }
-                    TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); }
+                    TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); te.goto_home(); }
                     TerminalEvent::Input(Event::Key(Key::Home)) => {
                         if te.goto_home() == TreeNavResult::Exit {
+
                             te.goto_home();
                         }
                     }