From 127c43bca0ea63fc26ab927917d3f548ed37f52a Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sun, 15 Aug 2021 02:05:33 +0200
Subject: [PATCH] list editor: add path view

add decorate() on OuterViewPort to create a ListDecorator
---
 nested/src/list/editor.rs |  76 +++++++-----
 nested/src/list/mod.rs    |   2 +-
 nested/src/list/sexpr.rs  | 238 ++++++++++++++++++--------------------
 shell/src/main.rs         |  95 +--------------
 4 files changed, 165 insertions(+), 246 deletions(-)

diff --git a/nested/src/list/editor.rs b/nested/src/list/editor.rs
index ea0c6ae..c4af949 100644
--- a/nested/src/list/editor.rs
+++ b/nested/src/list/editor.rs
@@ -32,7 +32,7 @@ use {
         },
         string_editor::StringEditor,
         leveled_term_view::LeveledTermView,
-        list::SExprView
+        list::{SExprView, ListDecoration}
     }
 };
 
@@ -59,7 +59,7 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
     data_sequence_port: OuterViewPort<dyn SequenceView<Item = Arc<RwLock<SubEditor>>>>,
     make_item_editor: FnMakeItemEditor,
     level: usize,
-    pub segment_seq: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
+    segment_seq: OuterViewPort<dyn SequenceView<Item = ListEditorViewSegment>>,
 }
 
 impl<SubEditor, FnMakeItemEditor> TerminalEditor for ListEditor<SubEditor, FnMakeItemEditor>
@@ -67,7 +67,7 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
       FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
 {
     fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
-        self.segment_seq.horizontal_sexpr_view(0)
+        self.horizontal_sexpr_view()
     }
 
     fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
@@ -369,6 +369,49 @@ impl<SubEditor, FnMakeItemEditor> ListEditor<SubEditor, FnMakeItemEditor>
 where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
       FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
 {
+
+    pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
+        self.segment_seq
+            .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 horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
+        self.get_seg_seq_view().horizontal_sexpr_view(0)
+    }
+    pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
+        self.get_seg_seq_view().vertical_sexpr_view(0)
+    }
+
+    pub fn path_view(&self) -> OuterViewPort<dyn TerminalView> {
+        self.get_seg_seq_view()
+            .decorate("<", ">", "/", 1)
+            .to_grid_horizontal()
+            .flatten()
+    }
+
     pub fn new(make_item_editor: FnMakeItemEditor) -> Self {
         let cursor_port = ViewPort::new();
         let data_port = ViewPort::new();
@@ -391,32 +434,7 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
             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()
-                    }
-                )
+            segment_seq: segment_view_port.outer()
         }
     }
 
diff --git a/nested/src/list/mod.rs b/nested/src/list/mod.rs
index 0888a48..eaed748 100644
--- a/nested/src/list/mod.rs
+++ b/nested/src/list/mod.rs
@@ -3,5 +3,5 @@ pub mod editor;
 pub mod sexpr;
 
 pub use editor::ListEditor;
-pub use sexpr::SExprView;
+pub use sexpr::{SExprView, ListDecoration};
 
diff --git a/nested/src/list/sexpr.rs b/nested/src/list/sexpr.rs
index 9496d5b..810a576 100644
--- a/nested/src/list/sexpr.rs
+++ b/nested/src/list/sexpr.rs
@@ -1,20 +1,13 @@
 use {
+    crate::{
+        core::{InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
+        projection::ProjectionHelper,
+        sequence::SequenceView,
+        terminal::{make_label, TerminalStyle, TerminalView},
+    },
+    cgmath::Point2,
     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
-    }
 };
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
@@ -29,7 +22,7 @@ pub struct ListDecorator {
     item_style: TerminalStyle,
 
     cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>>>,
-    proj_helper: ProjectionHelper<Self>
+    proj_helper: ProjectionHelper<Self>,
 }
 
 impl View for ListDecorator {
@@ -41,7 +34,7 @@ impl SequenceView for ListDecorator {
 
     fn len(&self) -> Option<usize> {
         let l = self.items.len()?;
-        Some(if l == 0 { 2 } else { 2*l + 2 })
+        Some(if l == 0 { 2 } else { 2 * l + 2 })
     }
 
     fn get(&self, idx: &usize) -> Option<Self::Item> {
@@ -49,22 +42,23 @@ impl SequenceView for ListDecorator {
         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))
-            }
-        )
+        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))
+        })
     }
 }
 
@@ -75,51 +69,64 @@ impl ListDecorator {
         delim: &str,
         level: usize,
         items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
-        out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>
+        out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
     ) -> Arc<RwLock<Self>> {
         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)
-                }
-            ),
+            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
+            proj_helper,
         }));
 
         li.write().unwrap().proj_helper.set_proj(&li);
-        
+
         out_port.set_view(Some(li.clone()));
         li
     }
 }
 
+pub trait ListDecoration {
+    fn decorate(
+        &self,
+        opening: &str,
+        closing: &str,
+        delim: &str,
+        level: usize,
+    ) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>;
+}
+
+impl ListDecoration for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
+    fn decorate(
+        &self,
+        opening: &str,
+        closing: &str,
+        delim: &str,
+        level: usize,
+    ) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
+        let port = ViewPort::new();
+        ListDecorator::new(opening, closing, delim, level, self.clone(), port.inner());
+        port.into_outer()
+    }    
+}
+
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
 
-use crate::{index::IndexView, grid::GridView};
+use crate::{grid::GridView, index::IndexView};
 
 pub struct VerticalSexprDecorator {
     opening_port: OuterViewPort<dyn TerminalView>,
@@ -130,7 +137,7 @@ pub struct VerticalSexprDecorator {
     item_style: TerminalStyle,
 
     cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>>>,
-    proj_helper: ProjectionHelper<Self>
+    proj_helper: ProjectionHelper<Self>,
 }
 
 impl View for VerticalSexprDecorator {
@@ -141,7 +148,9 @@ impl IndexView<Point2<i16>> for VerticalSexprDecorator {
     type Item = OuterViewPort<dyn TerminalView>;
 
     fn area(&self) -> Option<Vec<Point2<i16>>> {
-        let mut area = (0 .. self.items.len()?).map(|i| Point2::new(1 as i16, i as i16)).collect::<Vec<_>>();
+        let mut area = (0..self.items.len()?)
+            .map(|i| Point2::new(1 as i16, i as i16))
+            .collect::<Vec<_>>();
         area.push(Point2::new(0, 0));
         area.push(Point2::new(2, self.items.len()? as i16 - 1));
         Some(area)
@@ -156,28 +165,38 @@ impl IndexView<Point2<i16>> for VerticalSexprDecorator {
         match pt.x {
             0 => {
                 if pt.y == 0 {
-                    Some(self.opening_port.clone()
-                         .map_item(move |_, atom| atom.add_style_back(list_style)))
+                    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)))
+                    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)))
+                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
+            _ => None,
         }
     }
 }
@@ -188,51 +207,37 @@ impl VerticalSexprDecorator {
         closing: &str,
         level: usize,
         items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
-        out_port: InnerViewPort<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>
+        out_port: InnerViewPort<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>,
     ) -> Arc<RwLock<Self>> {
         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)
-                }
-            ),
+            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
+            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<dyn TerminalView>;
     fn vertical_bar_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
@@ -242,42 +247,21 @@ pub trait SExprView {
 impl SExprView for OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
     fn horizontal_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
         let port = ViewPort::new();
-        ListDecorator::new(
-            "(", ")", " ",
-            level,
-            self.clone(),
-            port.inner()
-        );
+        ListDecorator::new("(", ")", " ", level, self.clone(), port.inner());
 
-        port.into_outer()
-            .to_grid_horizontal()
-            .flatten()
+        port.into_outer().to_grid_horizontal().flatten()
     }
 
     fn vertical_bar_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
         let port = ViewPort::new();
-        ListDecorator::new(
-            "Λ", "V", "|",
-            level,
-            self.clone(),
-            port.inner()
-        );
+        ListDecorator::new("Λ", "V", "|", level, self.clone(), port.inner());
 
-        port.into_outer()
-            .to_grid_vertical()
-            .flatten()
+        port.into_outer().to_grid_vertical().flatten()
     }
 
     fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView> {
         let port = ViewPort::new();
-        VerticalSexprDecorator::new(
-            "(", ")",
-            level,
-            self.clone(),
-            port.inner()
-        );
-        port.into_outer()
-            .flatten()        
+        VerticalSexprDecorator::new("(", ")", level, self.clone(), port.inner());
+        port.into_outer().flatten()
     }
 }
-
diff --git a/shell/src/main.rs b/shell/src/main.rs
index 544c290..b75a377 100644
--- a/shell/src/main.rs
+++ b/shell/src/main.rs
@@ -294,95 +294,9 @@ write::
 
             }
 
-/*
-
-            // list views
-            {
-                let items_port = ViewPort::new();
-                let items = VecBuffer::with_data(
-                    vec![
-                        arg1_hex_unic_port.clone()
-                            .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))
-                            .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 par_items_port = ViewPort::new();
-                let par_items = VecBuffer::with_data(
-                    vec![
-                        items_port.outer().to_sequence().sexpr_view(1),
-                        arg1_hex_unic_port.clone()
-                            .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()
-                );
-
-                compositor.write().unwrap().push(
-                    par_items_port.outer()
-                        .to_sequence()
-                        .sexpr_view(0)
-                        .offset(Vector2::new(45, 5))
-                );
-            }
-
-            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());
@@ -411,11 +325,12 @@ write::
             let mut te = ListEditor::new(make_sub_editor.clone());
 
             compositor.write().unwrap().push(
-                te.segment_seq.horizontal_sexpr_view(0).offset(cgmath::Vector2::new(40,y))
+                te.path_view()
+                    .offset(cgmath::Vector2::new(40,y))
             );
             y += 1;
 
-            let mut p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());            
+            let mut p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
 
             loop {
                 term_port.update();
@@ -494,7 +409,9 @@ write::
                         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))
+                            te
+                                .horizontal_sexpr_view()
+                                .offset(Vector2::new(40, y))
                         );
                         y += 1;