From f88f4971afe07a58ae3500a606d5ebcda8cb513c Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Tue, 21 Jan 2025 20:03:49 +0100
Subject: [PATCH] list segments: cache length of segment-list in cur_len

---
 lib-nested-core/src/editors/list/segment.rs | 88 +++++++++++++++------
 1 file changed, 63 insertions(+), 25 deletions(-)

diff --git a/lib-nested-core/src/editors/list/segment.rs b/lib-nested-core/src/editors/list/segment.rs
index 0245daf..3de3cc4 100644
--- a/lib-nested-core/src/editors/list/segment.rs
+++ b/lib-nested-core/src/editors/list/segment.rs
@@ -26,12 +26,11 @@ pub enum ListSegment {
     }
 }
 
-/* todo: switch to ListView instead of SequenceView
- */
 pub struct ListSegments {
     data: Arc<dyn ListView<EditTree>>,
     cursor: Arc<dyn SingletonView<Item = ListCursor>>,
 
+    cur_len: usize,
     cur_cursor: ListCursor,
 
     port: ViewPort<dyn ListView<ListSegment>>,
@@ -45,13 +44,7 @@ impl View for ListSegments {
 
 impl ListView<ListSegment> for ListSegments {
     fn len(&self) -> Option<usize> {
-        let l = self.data.len()?;
-        match self.cur_cursor.mode {
-            ListCursorMode::Insert => {
-                Some(l + if self.cur_cursor.idx.is_some() { 1 } else { 0 })
-            }
-            _ => Some(l),
-        }
+        Some(self.cur_len)
     }
 
     fn get(&self, idx: &usize) -> Option<ListSegment> {
@@ -96,23 +89,61 @@ impl ListSegments {
     ) -> Arc<RwLock<Self>> {
         let out_port = ViewPort::new();
         let mut proj_helper = ProjectionHelper::new(out_port.update_hooks.clone());
-        let proj = Arc::new(RwLock::new(ListSegments {
-            cur_cursor: cursor_port.get_view().get(),
-            port: out_port.clone(),
 
+        let cur_cursor = cursor_port.get_view().get();
+        let mut cur_len = data_port.get_view().unwrap().len().unwrap();
+
+        if cur_cursor.mode == ListCursorMode::Insert {
+            cur_len += 1;
+        }
+
+        let proj = Arc::new(RwLock::new(ListSegments {
+            cur_cursor,
+            cur_len,
+
+            port: out_port.clone(),
             cursor: proj_helper.new_singleton_arg(0, cursor_port, |s: &mut Self, _msg| {
                 let old_cursor = s.cur_cursor;
                 let new_cursor = s.cursor.get();
                 s.cur_cursor = new_cursor;
 
-                if old_cursor.mode == ListCursorMode::Insert {
-                    if let Some(idx) = old_cursor.idx {
-                        s.cast.notify(&ListDiff::Remove(idx as usize));
+                if let Some(cur_idx) = old_cursor.idx {
+                    match old_cursor.mode {
+                    ListCursorMode::Insert => {
+                        eprintln!("segments: notify cursor cur len = {}", s.cur_len);
+                        s.cur_len -= 1;
+                        s.cast.notify(&ListDiff::Remove(cur_idx as usize));
                     }
-                }
-                if new_cursor.mode == ListCursorMode::Insert {
-                    if let Some(idx) = new_cursor.idx {
-                        s.cast.notify(&ListDiff::Insert { idx: idx as usize, val: ListSegment::InsertCursor });
+                    ListCursorMode::Select => {
+                        s.cast.notify(&ListDiff::Update{
+                            idx: cur_idx as usize,
+                            val: ListSegment::Item {
+                                editor: s.data.get(&(cur_idx as usize)).unwrap(),
+                                cur_dist: 0,
+                            }
+                        })
+                    }
+                    }
+                };
+
+                if let Some(cur_idx) = new_cursor.idx {
+                    match new_cursor.mode {
+                        ListCursorMode::Insert => {
+                           s.cur_len += 1;
+                           s.cast.notify(&ListDiff::Insert {
+                               idx: cur_idx as usize,
+                               val: ListSegment::InsertCursor
+                           });
+                        }
+                        ListCursorMode::Select => {
+                            s.cast.notify(&ListDiff::Update{
+                                idx: cur_idx as usize,
+                                val: ListSegment::Item {
+                                    editor: s.data.get(&(cur_idx as usize)).unwrap(),
+                                    cur_dist: 0,
+                                }
+                            })
+                        }
                     }
                 }
             }),
@@ -121,8 +152,8 @@ impl ListSegments {
                 let mut target_idx = match diff {
                     ListDiff::Clear => 0,
                     ListDiff::Remove(idx) => *idx,
-                    ListDiff::Insert { idx, val } => *idx,
-                    ListDiff::Update { idx, val } => *idx
+                    ListDiff::Insert { idx, val:_ } => *idx,
+                    ListDiff::Update { idx, val:_ } => *idx
                 };
                 let mut cur_dist = 0;
 
@@ -138,16 +169,23 @@ impl ListSegments {
 
                 match diff {
                     ListDiff::Clear => {
+                        s.cur_len = 0;
                         s.cast.notify(&ListDiff::Clear);
 
-                        if s.cur_cursor.mode == ListCursorMode::Insert {
+                        if s.cur_cursor.mode == ListCursorMode::Insert
+                        && s.cur_cursor.idx.is_some()
+                        {
+                            s.cur_cursor.idx = Some(0);
+                            s.cur_len += 1;
                             s.cast.notify(&ListDiff::Insert { idx: 0, val: ListSegment::InsertCursor });
                         }
                     }
-                    ListDiff::Remove(idx) => {
+                    ListDiff::Remove(_) => {
+                        s.cur_len -= 1;
                         s.cast.notify(&ListDiff::Remove(target_idx));
                     }
-                    ListDiff::Insert { idx, val } => {
+                    ListDiff::Insert { idx:_, val } => {
+                        s.cur_len += 1;
                         s.cast.notify(&ListDiff::Insert {
                             idx: target_idx,
                             val: ListSegment::Item {
@@ -156,7 +194,7 @@ impl ListSegments {
                             }
                         });
                     }
-                    ListDiff::Update { idx, val } => {
+                    ListDiff::Update { idx:_, val } => {
                         s.cast.notify(&ListDiff::Update {
                             idx: target_idx,
                             val: ListSegment::Item {