From 4b8b857134fc6f9894fe59b44d311b2c3ac4463d Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 28 Oct 2022 10:24:07 +0200
Subject: [PATCH] commander: display error on invalid symbol

---
 nested/src/make_editor.rs |  31 ++++++++++
 shell/src/command.rs      |  44 +++++++++++---
 shell/src/main.rs         | 123 +++++++++++++-------------------------
 3 files changed, 109 insertions(+), 89 deletions(-)

diff --git a/nested/src/make_editor.rs b/nested/src/make_editor.rs
index 027832e..929b7d8 100644
--- a/nested/src/make_editor.rs
+++ b/nested/src/make_editor.rs
@@ -34,6 +34,18 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
             )
         ))
 
+    } else if t[0] == c.type_term_from_str("( Symbol )").unwrap() {
+        Arc::new(RwLock::new(
+            PTYListEditor::new(
+                Box::new(|| {
+                    Arc::new(RwLock::new(CharEditor::new()))
+                }),
+                SeqDecorStyle::Plain,
+                ' ',
+                depth
+            )
+        ))
+
     } else if t[0] == c.type_term_from_str("( List String )").unwrap() {
         Arc::new(RwLock::new(
             PTYListEditor::new(
@@ -53,6 +65,25 @@ pub fn make_editor(ctx: Arc<RwLock<Context>>, t: &TypeLadder, depth: usize) -> A
                 depth
             )
         )) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
+    } else if t[0] == c.type_term_from_str("( List Symbol )").unwrap() {
+        Arc::new(RwLock::new(
+            PTYListEditor::new(
+                Box::new({
+                    let d = depth + 1;
+                    let ctx = ctx.clone();
+                    move || {
+                        make_editor(
+                            ctx.clone(),
+                            &vec![ctx.read().unwrap().type_term_from_str("( Symbol )").unwrap()],
+                            d
+                        )
+                    }
+                }),
+                SeqDecorStyle::EnumSet,
+                ' ',
+                depth
+            )
+        )) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
 
     } else if t[0] == c.type_term_from_str("( List Char )").unwrap() {
         Arc::new(RwLock::new(
diff --git a/shell/src/command.rs b/shell/src/command.rs
index 5ac9e66..2076770 100644
--- a/shell/src/command.rs
+++ b/shell/src/command.rs
@@ -72,7 +72,7 @@ impl Action for ActCp {
                              .with_t(Point2::new(1, 2), " Destination")
                              .with_n(Point2::new(0, 2), vec![ ctx.read().unwrap().type_term_from_str("( Path )").unwrap() ] )
                              .with_t(Point2::new(1, 3), " Options")
-                             .with_n(Point2::new(0, 3), vec![ ctx.read().unwrap().type_term_from_str("( List String )").unwrap() ] )
+                             .with_n(Point2::new(0, 3), vec![ ctx.read().unwrap().type_term_from_str("( List Symbol )").unwrap() ] )
         )) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
     }
 }
@@ -108,6 +108,18 @@ impl Action for ActColor {
     }
 }
 
+pub struct ActLet {}
+impl Action for ActLet {
+    fn make_editor(&self, ctx: Arc<RwLock<Context>>) -> Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>> {
+        let depth = 1;
+        Arc::new(RwLock::new(ProductEditor::new(depth, ctx.clone())
+                             .with_n(Point2::new(0, 0), vec![ ctx.read().unwrap().type_term_from_str("( Symbol )").unwrap() ] )
+                             .with_t(Point2::new(1, 0), " := ")
+                             .with_n(Point2::new(2, 0), vec![ ctx.read().unwrap().type_term_from_str("( PosInt 10 BigEndian )").unwrap() ] )
+        )) as Arc<RwLock<dyn TerminalTreeEditor + Send + Sync>>
+    }
+}
+
 pub struct Commander {
     ctx: Arc<RwLock<Context>>,
     cmds: HashMap<String, Arc<dyn Action + Send + Sync>>,
@@ -146,15 +158,16 @@ impl Commander {
                                move
                                |pos, mut a| {
                                    if *valid.read().unwrap() {
-                                       a.add_style_front(TerminalStyle::fg_color((0,255,0)))
+                                       a.add_style_back(TerminalStyle::fg_color((0,255,0)))
                                    } else {
-                                       a.add_style_front(TerminalStyle::fg_color((255,0,0)))
+                                       a.add_style_back(TerminalStyle::fg_color((255,0,0)))
                                    }
                                }
                            }));
 
         let mut cmds = HashMap::new();
 
+        cmds.insert("let".into(), Arc::new(ActLet{}) as Arc<dyn Action + Send + Sync>);
         cmds.insert("cd".into(), Arc::new(ActCd{}) as Arc<dyn Action + Send + Sync>);
         cmds.insert("echo".into(), Arc::new(ActEcho{}) as Arc<dyn Action + Send + Sync>);
         cmds.insert("ls".into(), Arc::new(ActLs{}) as Arc<dyn Action + Send + Sync>);
@@ -196,11 +209,14 @@ impl TerminalEditor for Commander {
         if let (Some(cmd_editor), true) = (self.cmd_editor.as_ref(), self.confirmed) {
             match event {
                 TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
-                    // run
-                    cmd_editor.write().unwrap().goto(TreeCursor::none());
-                    
+                    if cmd_editor.write().unwrap().nexd() == TreeNavResult::Exit {
+                        // run
+                        cmd_editor.write().unwrap().goto(TreeCursor::none());
 
-                    TerminalEditorResult::Exit
+                        TerminalEditorResult::Exit
+                    } else {
+                        TerminalEditorResult::Continue
+                    }
                 }
                 event => {
                     cmd_editor.write().unwrap().handle_terminal_event(event)
@@ -224,16 +240,20 @@ impl TerminalEditor for Commander {
                         }
                     } else {
                         // undefined command
+                        let mut b = VecBuffer::new();
+                        b.push(nested::diagnostics::make_error(nested::terminal::make_label(&format!("invalid symbol {}", self.symbol_editor.get_string()))));
+                        self.m_buf.clear();
+                        self.m_buf.push(b.get_port().to_sequence());
                     }
 
                     TerminalEditorResult::Continue
                 }
 
                 event => {
+                    self.m_buf.clear();
                     let res = self.symbol_editor.handle_terminal_event(event);
-
                     let symbol = self.symbol_editor.get_string();
-                    
+
                     if let Some(action) = self.cmds.get(&symbol) {
                         let editor = action.make_editor(self.ctx.clone());
 
@@ -242,9 +262,15 @@ impl TerminalEditor for Commander {
                         } else {
                             *self.view_elements.get_mut(1) = editor.read().unwrap().get_term_view().map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((80,80,80))));
                         }
+
                         self.cmd_editor = Some(editor);
                         *self.valid.write().unwrap() = true;
                     } else {
+                        /*
+                        let mut b = VecBuffer::new();
+                        b.push(nested::diagnostics::make_error(nested::terminal::make_label(&format!("invalid symbol {}", self.symbol_editor.get_string()))));
+                        self.m_buf.push(b.get_port().to_sequence());
+*/
                         self.cmd_editor = None;
                         *self.valid.write().unwrap() = false;
 
diff --git a/shell/src/main.rs b/shell/src/main.rs
index e98c47b..75dc2a1 100644
--- a/shell/src/main.rs
+++ b/shell/src/main.rs
@@ -14,10 +14,10 @@ use {
     },
     cgmath::{Point2, Vector2},
     nested::{
-        core::{port::UpdateTask, Observer, OuterViewPort, ViewPort, Context, TypeTerm},
+        core::{port::UpdateTask, Observer, OuterViewPort, View, ViewPort, Context, TypeTerm},
         index::IndexArea,
         list::{ListCursorMode, PTYListEditor},
-        sequence::{decorator::{SeqDecorStyle, Separate}},
+        sequence::{SequenceView, decorator::{SeqDecorStyle, Separate}},
         terminal::{
             make_label, Terminal, TerminalAtom, TerminalCompositor, TerminalEditor,
             TerminalEditorResult, TerminalEvent, TerminalStyle, TerminalView,
@@ -53,42 +53,27 @@ async fn main() {
     for tn in vec![
         "MachineWord", "MachineInt", "MachineSyllab", "Bits",
         "Vec", "Stream", "Json",
-        "Sequence", "AsciiString", "UTF-8-String", "Char", "String",
+        "Sequence", "AsciiString", "UTF-8-String", "Char", "String", "Symbol",
         "PosInt", "Digit", "LittleEndian", "BigEndian",
         "DiffStream", "ℕ", "List", "Path", "Term", "RGB", "Vec3i"
     ] { ctx.write().unwrap().add_typename(tn.into()); }
-/*
-    let mut process_list_editor = PTYListEditor::new(
-        Box::new(
-            move || {
-                Arc::new(RwLock::new(PosIntEditor::new(16)))
-            }
-        ),
-        SeqDecorStyle::VerticalSexpr,
-        0
-    );
-*/
-    let mut process_list_editor = PTYListEditor::new(
-            Box::new({let ctx = ctx.clone(); move || Arc::new(RwLock::new(Commander::new(ctx.clone())))}),
-/*
-        Box::new({
-            let ctx = ctx.clone();
-            move || nested::make_editor::make_editor(
-                ctx.clone(),
-                &vec![ctx.read().unwrap().type_term_from_str("( List String )").unwrap()],
-                1
-            )}),
-*/
-        SeqDecorStyle::VerticalSexpr,
-        '\n',
-        0
-    );
+
+    let mut process_list_editor =
+        PTYListEditor::new(
+            Box::new( move || {
+                Arc::new(RwLock::new(Commander::new(ctx.clone())))
+            }),
+            SeqDecorStyle::Plain,
+            '\0',
+            0
+        );
 
     async_std::task::spawn(async move {
         let mut table = nested::index::buffer::IndexBuffer::new();
         
         let magic =
-            make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>").map_item(|pos, atom| {
+            make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
+            .map_item(|pos, atom| {
                 atom.add_style_back(TerminalStyle::fg_color((
                     5,
                     ((80 + (pos.x * 30) % 100) as u8),
@@ -99,31 +84,6 @@ async fn main() {
         let mut cur_size = nested::singleton::SingletonBuffer::new(Vector2::new(10, 10));
         let mut status_chars = VecBuffer::new();
 
-        let mut plist = VecBuffer::new(); let mut plist_port =
-        plist.get_port(); async_std::task::spawn(async move { let (w,
-        _h) = termion::terminal_size().unwrap(); let mut x: usize = 0;
-        loop { let val = (5.0 + (x as f32 / 3.0).sin() * 5.0 + 2.0 +
-        ((7 + x) as f32 / 5.0).sin() * 2.0 + 2.0 + ((9 + x) as f32 /
-        10.0).cos() * 3.0) as usize;
-
-                if x < w as usize {
-                    plist.push(val);
-                } else {
-                    *plist.get_mut(x % (w as usize)) = val;
-                }
-
-                x += 1;
-                async_std::task::sleep(std::time::Duration::from_millis(10)).await;
-
-                if x % (w as usize) == 0 {
-                    async_std::task::sleep(std::time::Duration::from_secs(3)).await;
-                }
-            }
-        });
-
-        let plot_port = ViewPort::new();
-        let _plot = crate::plot::Plot::new(plist_port.to_sequence(), plot_port.inner());
-        
         table.insert_iter(vec![
             (Point2::new(0, 0), magic.clone()),
             (
@@ -133,22 +93,26 @@ async fn main() {
             (Point2::new(0, 2), magic.clone()),
             (Point2::new(0, 3), make_label(" ")),
             (Point2::new(0, 4),
-             process_list_editor
-             .editor
+             process_list_editor.editor
              .get_seg_seq_view()
-             .separate(make_label(" ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~").map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((40,40,40)))))
+             .separate(
+                 make_label(" ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~  ~~")
+                     .map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((40,40,40))))
+             )
              .to_grid_vertical()
              .flatten()),
-            (Point2::new(0, 5),  make_label(" ")),
-            (Point2::new(0, 6),  make_label("-~~--~~--~~--~~--~~--~~--~~--~~--~~--~~").map_item(|p,a| a.add_style_front(TerminalStyle::fg_color((200,200,200))))),
-            (Point2::new(0, 7),  process_list_editor.get_msg_port().map(
+
+            (Point2::new(0, 5), make_label(" ")),
+            (Point2::new(0, 6), magic.clone()),
+
+            (Point2::new(0, 7), process_list_editor.get_msg_port().map(
                 |entry| {
                     let mut b = VecBuffer::new();
                     b.push(
                          make_label("@")
                          .map_item(|p,a| a
                                    .add_style_back(TerminalStyle::bold(true))
-                                   .add_style_back(TerminalStyle::fg_color((180,180,0))))
+                                   .add_style_back(TerminalStyle::fg_color((120,120,0))))
                     );
 
                     for x in entry.addr.iter() {
@@ -161,13 +125,23 @@ async fn main() {
                             make_label(".")
                                 .map_item(|p,a| a
                                    .add_style_back(TerminalStyle::bold(true))
-                                   .add_style_back(TerminalStyle::fg_color((180,180,0))))                            
+                                   .add_style_back(TerminalStyle::fg_color((120,120,0))))
                         );
                     }
 
                     b.push(entry.port.clone());
-
-                    b.get_port().to_sequence().to_grid_horizontal().flatten()
+                    b.get_port()
+                        .to_sequence()
+                        .to_grid_horizontal()
+                        .flatten()
+                        .map_item(move |p,a| {
+                            let select = false;
+                            if select {
+                                a.add_style_back(TerminalStyle::fg_color((60,60,60)))
+                            } else {
+                                *a
+                            }
+                        })
                 }
             ).to_grid_vertical().flatten())
 
@@ -175,22 +149,10 @@ async fn main() {
 
         let (w, h) = termion::terminal_size().unwrap();
 /*
-        compositor.write().unwrap().push(
-            plot_port.outer()
-                .map_item(|pt, a| {
-                    a.add_style_back(TerminalStyle::fg_color((
-                        255 - pt.y as u8 * 8,
-                        100,
-                        pt.y as u8 * 15,
-                    )))
-                })
-                .offset(Vector2::new(0, h as i16 - 20)),
-        );
-
         compositor
             .write()
             .unwrap()
-            .push(monstera::make_monstera().offset(Vector2::new(w as i16 - 38, 0)));
+        .push(monstera::make_monstera().offset(Vector2::new(w as i16 - 38, 0)));
 */
         compositor
             .write()
@@ -201,7 +163,7 @@ async fn main() {
             leaf_mode: ListCursorMode::Insert,
             tree_addr: vec![0],
         });
-        
+
         loop {
             status_chars.clear();
             let cur = process_list_editor.get_cursor();
@@ -240,6 +202,7 @@ async fn main() {
                 status_chars.push(TerminalAtom::new(
                     ':',
                     TerminalStyle::fg_color((150, 80,230)).add(TerminalStyle::bold(true)),
+
                 ));
             } else {
                 for c in "Press <DN> to enter".chars() {
@@ -271,7 +234,7 @@ async fn main() {
             }
                 */
             }
-*/
+*/            
             match ev {
                 TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
                 TerminalEvent::Input(Event::Key(Key::Ctrl('l'))) => {