From 86562614cc238fd52275e8c1a9dd54b78811921f Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Wed, 6 Jan 2021 21:35:46 +0100
Subject: [PATCH] refactoring

---
 Cargo.toml                 |   8 +-
 src/{ => core}/channel.rs  |  16 ++-
 src/core/mod.rs            |  30 ++++++
 src/core/observer.rs       | 149 +++++++++++++++++++++++++++
 src/core/port.rs           | 144 ++++++++++++++++++++++++++
 src/core/view.rs           |  24 +++++
 src/main.rs                | 127 +++++++++++++++--------
 src/port.rs                | 186 ---------------------------------
 src/string_editor.rs       |  89 ++++++++--------
 src/terminal/compositor.rs | 186 +++++++++++++++++++++++++++------
 src/terminal/mod.rs        |  20 +++-
 src/terminal/terminal.rs   | 203 ++++++++++++++++++++++++++-----------
 src/view.rs                | 189 ----------------------------------
 src/view/grid.rs           |  78 ++++++++++++++
 src/view/index.rs          |  73 +++++++++++++
 src/view/mod.rs            |  13 +++
 src/view/sequence.rs       |  41 ++++++++
 src/view/singleton.rs      |  53 ++++++++++
 18 files changed, 1071 insertions(+), 558 deletions(-)
 rename src/{ => core}/channel.rs (93%)
 create mode 100644 src/core/mod.rs
 create mode 100644 src/core/observer.rs
 create mode 100644 src/core/port.rs
 create mode 100644 src/core/view.rs
 delete mode 100644 src/port.rs
 delete mode 100644 src/view.rs
 create mode 100644 src/view/grid.rs
 create mode 100644 src/view/index.rs
 create mode 100644 src/view/mod.rs
 create mode 100644 src/view/sequence.rs
 create mode 100644 src/view/singleton.rs

diff --git a/Cargo.toml b/Cargo.toml
index 828e078..c9d0fc0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,10 +6,10 @@ name = "NeStEd"
 version = "0.1.0"
 
 [dependencies]
-cgmath = "*"
-termion = "*"
-signal-hook = "*"
-signal-hook-async-std = "*"
+cgmath = "0.17.0"
+termion = "1.5.5"
+signal-hook = "0.3.1"
+signal-hook-async-std = "0.2.0"
 
 [dependencies.async-std]
 version = "1.7.0"
diff --git a/src/channel.rs b/src/core/channel.rs
similarity index 93%
rename from src/channel.rs
rename to src/core/channel.rs
index 6fe6a46..453f17c 100644
--- a/src/channel.rs
+++ b/src/core/channel.rs
@@ -13,7 +13,7 @@ use {
     },
 
     crate::{
-        view::{Observer}
+        core::{Observer}
     }
 };
 
@@ -83,11 +83,9 @@ pub struct ChannelReceiver<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
 
 //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
 
-impl<Data: ChannelData> Observer for ChannelSender<Data>
+impl<Data: ChannelData> ChannelSender<Data>
 where Data::IntoIter: Send + Sync {
-    type Msg = Data::Item;
-
-    fn notify(&self, msg: Data::Item) {
+    pub fn send(&self, msg: Data::Item) {
         let mut state =  self.0.lock().unwrap();
 
         if state.send_buf.is_none() {
@@ -102,6 +100,14 @@ where Data::IntoIter: Send + Sync {
     }
 }
 
+use crate::core::View;
+impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
+where V::Msg: Clone, Data::IntoIter: Send + Sync {
+    fn notify(&self, msg: &V::Msg) {
+        self.send(msg.clone());
+    }
+}
+
 impl<Data: ChannelData> Clone for ChannelSender<Data> {
     fn clone(&self) -> Self {
         self.0.lock().unwrap().num_senders += 1;
diff --git a/src/core/mod.rs b/src/core/mod.rs
new file mode 100644
index 0000000..30c8d6c
--- /dev/null
+++ b/src/core/mod.rs
@@ -0,0 +1,30 @@
+
+pub mod view;
+pub mod observer;
+pub mod channel;
+pub mod port;
+
+pub use {
+    view::{View},
+    observer::{
+        Observer,
+        ObserverExt,
+        ObserverBroadcast,
+        NotifyFnObserver,
+        ResetFnObserver
+    },
+    channel::{
+        ChannelReceiver,
+        ChannelSender,
+        set_channel,
+        queue_channel,
+        singleton_channel
+    },
+    port::{
+        ViewPort,
+        InnerViewPort,
+        OuterViewPort
+    }
+};
+
+
diff --git a/src/core/observer.rs b/src/core/observer.rs
new file mode 100644
index 0000000..b02f2fe
--- /dev/null
+++ b/src/core/observer.rs
@@ -0,0 +1,149 @@
+use {
+    crate::core::View,
+    std::{
+        ops::Deref,
+        sync::{Arc, Weak, RwLock}
+    }
+};
+
+                    /*\
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                 Observer
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                    \*/
+pub trait Observer<V: View + ?Sized> : Send + Sync {
+    fn reset(&self, view: Option<Arc<V>>) {}
+    fn notify(&self, msg: &V::Msg);
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<V: View + ?Sized, O: Observer<V>> Observer<V> for RwLock<O> {
+    fn notify(&self, msg: &V::Msg) {
+        self.read().unwrap().notify(&msg);
+    }
+}
+
+impl<V: View + ?Sized, O: Observer<V>> Observer<V> for Arc<O> {
+    fn notify(&self, msg: &V::Msg) {
+        self.deref().notify(&msg);
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait ObserverExt<V: View + ?Sized> : Observer<V> {    
+    fn notify_each(&self, it: impl IntoIterator<Item = V::Msg>);
+}
+
+impl<V: View + ?Sized, T: Observer<V>> ObserverExt<V> for T {
+    fn notify_each(&self, it: impl IntoIterator<Item = V::Msg>) {
+        for msg in it {
+            self.notify(&msg);
+        }
+    }
+}
+
+                    /*\
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                 Broadcast
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                    \*/
+
+pub struct ObserverBroadcast<V: View + ?Sized> {
+    observers: Vec<Weak<dyn Observer<V>>>
+}
+
+impl<V: View + ?Sized> ObserverBroadcast<V> {
+    pub fn new() -> Self {
+        ObserverBroadcast {
+            observers: Vec::new()
+        }
+    }
+
+    pub fn add_observer(&mut self, obs: Weak<dyn Observer<V>>) {
+        self.cleanup();
+        self.observers.push(obs);
+    }
+
+    fn cleanup(&mut self) {
+        self.observers.retain(|o| o.strong_count() > 0);
+    }
+
+    fn iter(&self) -> impl Iterator<Item = Arc<dyn Observer<V>>> + '_ {
+        self.observers.iter().filter_map(|o| o.upgrade())
+    }
+}
+
+impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V> {
+    fn reset(&self, view: Option<Arc<V>>) {
+        for o in self.iter() {
+            o.reset(view.clone());
+        }
+    }
+
+    fn notify(&self, msg: &V::Msg) {
+        for o in self.iter() {
+            o.notify(&msg);
+        }
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct NotifyFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(&V::Msg) + Send + Sync {
+    f: F,
+    _phantom: std::marker::PhantomData<V>
+}
+
+impl<V, F> NotifyFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(&V::Msg) + Send + Sync {
+    pub fn new(f: F) -> Self {
+        NotifyFnObserver {
+            f,
+            _phantom: std::marker::PhantomData
+        }
+    }
+}
+
+impl<V, F> Observer<V> for NotifyFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(&V::Msg) + Send + Sync {
+    fn notify(&self, msg: &V::Msg) {
+        (self.f)(msg);
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct ResetFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(Option<Arc<V>>) + Send + Sync {
+    f: F,
+    _phantom: std::marker::PhantomData<V>
+}
+
+impl<V, F> ResetFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(Option<Arc<V>>) + Send + Sync {
+    pub fn new(f: F) -> Self {
+        ResetFnObserver {
+            f,
+            _phantom: std::marker::PhantomData
+        }
+    }
+}
+
+impl<V, F> Observer<V> for ResetFnObserver<V, F>
+where V: View + ?Sized,
+      F: Fn(Option<Arc<V>>) + Send + Sync {
+    fn notify(&self, msg: &V::Msg) {}
+    fn reset(&self, view: Option<Arc<V>>) {
+        (self.f)(view);
+    }
+}
+
+
diff --git a/src/core/port.rs b/src/core/port.rs
new file mode 100644
index 0000000..66078cb
--- /dev/null
+++ b/src/core/port.rs
@@ -0,0 +1,144 @@
+use {
+    std::sync::{Arc, RwLock},
+    crate::core::{
+        View,
+        Observer,
+        ObserverBroadcast,
+        NotifyFnObserver,
+        ResetFnObserver,
+        channel::{
+            ChannelData,
+            ChannelSender,
+            ChannelReceiver
+        }
+    }
+};
+
+                    /*\
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                 View Port
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                    \*/
+#[derive(Clone)]
+pub struct ViewPort<V: View + ?Sized> {
+    view: Arc<RwLock<Option<Arc<V>>>>,
+    observers: Arc<RwLock<ObserverBroadcast<V>>>
+}
+
+impl<V: View + ?Sized> ViewPort<V> {
+    pub fn new() -> Self {
+        ViewPort {
+            view: Arc::new(RwLock::new(None)),
+            observers: Arc::new(RwLock::new(ObserverBroadcast::new()))
+        }
+    }
+
+    pub fn with_view(view: Arc<V>) -> Self {
+        let port = ViewPort::new();
+        port.set_view(Some(view));
+        port
+    }
+
+    pub fn set_view(&self, view: Option<Arc<V>>) {
+        *self.view.write().unwrap() = view.clone();
+        self.observers.read().unwrap().reset(view);
+    }
+
+    pub fn add_observer(&self, observer: Arc<dyn Observer<V>>) {
+        self.observers.write().unwrap().add_observer(Arc::downgrade(&observer));
+        observer.reset(self.view.read().unwrap().clone());
+    }
+
+    pub fn inner(&self) -> InnerViewPort<V> {
+        InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
+    }
+
+    pub fn outer(&self) -> OuterViewPort<V> {
+        OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
+    }
+
+    pub fn into_inner(self) -> InnerViewPort<V> {
+        InnerViewPort(ViewPort{ view: self.view, observers: self.observers })
+    }
+
+    pub fn into_outer(self) -> OuterViewPort<V> {
+        OuterViewPort(ViewPort{ view: self.view, observers: self.observers })
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+#[derive(Clone)]
+pub struct InnerViewPort<V: View + ?Sized>(ViewPort<V>);
+
+#[derive(Clone)]
+pub struct OuterViewPort<V: View + ?Sized>(ViewPort<V>);
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<V: View + ?Sized> InnerViewPort<V> {
+    pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
+        self.0.observers.clone()
+    }
+
+    pub fn set_view(&self, view: Option<Arc<V>>) -> Arc<RwLock<ObserverBroadcast<V>>> {
+        self.0.set_view(view);
+        self.get_broadcast()
+    }
+
+    pub fn get_view(&self) -> Option<Arc<V>> {
+        self.0.view.read().unwrap().clone()
+    }
+
+    pub fn notify(&self, msg: &V::Msg) {
+        self.0.observers.read().unwrap().notify(msg);
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<V: View + ?Sized + 'static> OuterViewPort<V> {
+    pub fn get_view(&self) -> Option<Arc<V>> {
+        self.0.view.read().unwrap().clone()
+    }
+
+    pub fn get_view_arc(&self) -> Arc<RwLock<Option<Arc<V>>>> {
+        self.0.view.clone()
+    }
+
+    pub fn add_observer(&self, observer: Arc<dyn Observer<V>>) -> Arc<RwLock<Option<Arc<V>>>> {
+        self.0.add_observer(observer);
+        self.get_view_arc()
+    }
+
+/*
+    pub fn add_reset_fn(&self, reset: impl Fn(Option<Arc<V>>) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<V>>>> {
+        self.add_observer(Arc::new(ResetFnObserver::new(reset)))
+    }
+
+    pub fn add_notify_fn(&self, notify: impl Fn(&V::Msg) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<V>>>> {
+        self.add_observer(Arc::new(NotifyFnObserver::new(notify)))
+    }
+*/
+}
+
+/*
+impl<V: View + ?Sized + 'static> OuterViewPort<V>
+where V::Msg: Clone {
+    pub fn into_stream<Data>(
+        self,
+        reset: impl Fn(Option<Arc<V>>, ChannelSender<Data>) + Send + Sync + 'static
+    ) -> ChannelReceiver<Data>
+    where Data: ChannelData<Item = V::Msg> + 'static,
+          Data::IntoIter: Send + Sync + 'static
+    {
+        let (s, r) = crate::core::channel::channel::<Data>();
+        self.add_observer(Arc::new(s.clone()));
+        self.add_reset_fn(
+            move |view| { reset(view, s.clone()); }
+        );
+        r
+    }
+}
+*/
+
diff --git a/src/core/view.rs b/src/core/view.rs
new file mode 100644
index 0000000..1f76892
--- /dev/null
+++ b/src/core/view.rs
@@ -0,0 +1,24 @@
+
+                    /*\
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                   View
+<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+                    \*/
+pub trait View : Send + Sync {
+    /// Notification message for the observers
+    type Msg;
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+use std::sync::{Arc, RwLock};
+
+impl<V: View> View for RwLock<V> {
+    type Msg = V::Msg;
+}
+
+impl<V: View> View for Arc<V> {
+    type Msg = V::Msg;
+}
+
+
diff --git a/src/main.rs b/src/main.rs
index dbfb4ba..071ee4f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,51 +1,104 @@
-
 #![feature(trait_alias)]
 #![feature(assoc_char_funcs)]
 
+pub mod core;
 pub mod view;
-pub mod port;
-pub mod channel;
-pub mod singleton_buffer;
-pub mod vec_buffer;
 pub mod terminal;
+
 pub mod string_editor;
 
+//pub mod singleton_buffer;
+//pub mod vec_buffer;
+//pub mod sequence_element_projection;
+
 use {
     async_std::{task},
     std::{
-        sync::{Arc, RwLock}
+        sync::{Arc, RwLock},
+        ops::Range
     },
-    cgmath::{Vector2},
+    cgmath::{Vector2, Point2},
+    termion::event::{Event, Key},
     crate::{
-        view::{View, Observer},
-        port::{ViewPort, InnerViewPort, OuterViewPort},
-        singleton_buffer::SingletonBuffer,
-        vec_buffer::VecBuffer,
+        core::{View, Observer, ObserverExt, ViewPort},
+        view::{*},
         terminal::{
-            Terminal,
+            TerminalView,
             TerminalAtom,
             TerminalStyle,
-            TerminalCompositor,
-            TerminalEvent
-        }
-    },
-    termion::event::{Event, Key}
+            TerminalEvent,
+            Terminal,
+            TerminalCompositor
+        },
+    }
 };
 
-struct Fill(TerminalAtom);
-impl View for Fill {
-    type Key = Vector2<i16>;
-    type Value = TerminalAtom;
+struct VecSequenceView<T: Send + Sync + Clone>(Arc<RwLock<Vec<T>>>);
+impl<T: Send + Sync + Clone> ImplIndexView for VecSequenceView<T> {
+    type Key = usize;
+    type Value = T;
 
-    fn view(&self, _: Vector2<i16>) -> Option<TerminalAtom> {
-        Some(self.0.clone())
+    fn get(&self, idx: &usize) -> T {
+        self.0.read().unwrap()[*idx].clone()
+    }
+
+    fn range(&self) -> Option<Range<usize>> {
+        Some(0 .. self.0.read().unwrap().len())
+    }
+}
+
+struct Checkerboard;
+impl ImplIndexView for Checkerboard {
+    type Key = Point2<i16>;
+    type Value = Option<TerminalAtom>;
+
+    fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
+        if pos.x == 0 || pos.x == 1 || pos.x > 17 || pos.y == 0 || pos.y > 8 {
+            // border
+            Some(TerminalAtom::new_bg((20, 10, 10)))
+        } else {
+            // field
+            if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) {
+                Some(TerminalAtom::new_bg((0, 0, 0)))
+            } else {
+                Some(TerminalAtom::new_bg((200, 200, 200)))
+            }
+        }
+    }
+
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        Some(Point2::new(0,0) .. Point2::new(20,10))
+    }
+}
+
+struct ScrambleBackground;
+impl ImplIndexView for ScrambleBackground {
+    type Key = Point2<i16>;
+    type Value = Option<TerminalAtom>;
+
+    fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
+        if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) {
+            Some(TerminalAtom::new(char::from((35+(5*pos.y+pos.x)%40) as u8), TerminalStyle::fg_color((40, 40, 40))))
+        } else {
+            Some(TerminalAtom::new(char::from((35+(pos.y+9*pos.x)%40) as u8), TerminalStyle::fg_color((90, 90, 90))))
+        }
+    }
+
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        None
+        //Some(Point2::new(0,0) .. Point2::new(50,30))
     }
 }
 
 #[async_std::main]
 async fn main() {
-    let composite_view = port::ViewPort::new();
-    let mut compositor = TerminalCompositor::new(composite_view.inner());
+    let term_port = ViewPort::<dyn TerminalView>::new();
+
+    let mut compositor = TerminalCompositor::new(term_port.inner());
+    compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(ScrambleBackground)).into_outer());
+    
+    let mut term = Terminal::new(term_port.outer());
+    let term_writer = term.get_writer();
 
     task::spawn(async move {
                             /*\
@@ -53,36 +106,30 @@ async fn main() {
                         Setup Views
         <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
                             \*/
-        let fp = port::ViewPort::with_view(Arc::new(Fill(TerminalAtom::new('.', TerminalStyle::fg_color((50,50,50))))));
-        compositor.push(fp.outer());
 
-        let ep = port::ViewPort::new();
-        let mut editor = string_editor::StringEditor::new(ep.inner());
-        compositor.push(ep.outer());
+        compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(Checkerboard)).into_outer());
+        let edit_port = ViewPort::<dyn TerminalView>::new();        
+        let mut editor = string_editor::StringEditor::new(edit_port.inner());
+        compositor.push(edit_port.into_outer());
 
                             /*\
         <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
                         Event Loop
         <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
                             \*/
-        let mut term = Terminal::new();
         loop {
             match term.next_event().await {
-                TerminalEvent::Resize(size) => {
-                    for x in 0 .. size.x {
-                        for y in 0 .. size.y {
-                            fp.inner().notify(Vector2::new(x,y));
-                        }
-                    }
-                },
                 TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(),
                 TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(),
                 TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0),
                 TerminalEvent::Input(Event::Key(Key::End)) => editor.goto_end(),
+                TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {},
                 TerminalEvent::Input(Event::Key(Key::Char(c))) => editor.insert(c),
                 TerminalEvent::Input(Event::Key(Key::Delete)) => editor.delete(),
                 TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); },
-                TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break,
+                TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
+                    break
+                }
                 _ => {}
             }
         }
@@ -93,6 +140,6 @@ async fn main() {
                  Terminal Rendering
     <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
                         \*/
-    Terminal::show(composite_view.into_outer()).await.ok();
+    term_writer.show().await.ok();
 }
 
diff --git a/src/port.rs b/src/port.rs
deleted file mode 100644
index 2980068..0000000
--- a/src/port.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-use {
-    std::{
-        sync::{Arc, RwLock},
-        collections::HashSet,
-        hash::Hash,
-    },
-    crate::{
-        view::{View, Observer, FnView, FnObserver},
-        channel::{ChannelReceiver}
-    }
-};
-
-                    /*\
-<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-                 View Port
-<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-                    \*/
-#[derive(Clone)]
-pub struct ViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static> {
-    view: Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>>,
-    observers: Arc<RwLock<Vec<Arc<dyn Observer<Msg = K>>>>>
-}
-
-impl<K, V> ViewPort<K, V>
-where K: Send + Sync + 'static,
-      V: Send + Sync + 'static {
-    pub fn new() -> Self {
-        ViewPort {
-            view: Arc::new(RwLock::new(None)),
-            observers: Arc::new(RwLock::new(Vec::new()))
-        }
-    }
-
-    pub fn with_view(view: Arc<dyn View<Key = K, Value = V>>) -> Self {
-        ViewPort {
-            view: Arc::new(RwLock::new(Some(view))),
-            observers: Arc::new(RwLock::new(Vec::new()))
-        }
-    }
-
-    pub fn set_view(&self, view: Arc<dyn View<Key = K, Value = V>>) {
-        *self.view.write().unwrap() = Some(view);
-    }
-
-    pub fn add_observer(&self, observer: Arc<dyn Observer<Msg = K>>) {
-        self.observers.write().unwrap().push(observer);
-    }
-
-    pub fn inner(&self) -> InnerViewPort<K, V> {
-        InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
-    }
-
-    pub fn outer(&self) -> OuterViewPort<K, V> {
-        OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
-    }
-
-    pub fn into_inner(self) -> InnerViewPort<K, V> {
-        InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
-    }
-
-    pub fn into_outer(self) -> OuterViewPort<K, V> {
-        OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-#[derive(Clone)]
-pub struct InnerViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static>(ViewPort<K, V>);
-
-#[derive(Clone)]
-pub struct OuterViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static>(ViewPort<K, V>);
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-impl<K: Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
-    pub fn get_view(&self) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
-        self.0.view.clone()
-    }
-
-    pub fn add_observer(self, observer: Arc<dyn Observer<Msg = K>>) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
-        self.0.add_observer(observer);
-        self.0.view
-    }
-
-    pub fn add_observer_fn(self, obs_fn: impl Fn(K) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
-        self.add_observer(Arc::new(FnObserver::new(obs_fn)))
-    }
-}
-
-impl<K: Eq + Hash + Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
-    pub fn stream(self) -> ChannelReceiver<HashSet<K>> {
-        let (s, r) = crate::channel::set_channel();
-        self.0.add_observer(Arc::new(s));
-        r
-    }
-}
-
-impl<K: Clone + Eq + Hash + Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {   
-    pub fn map_value<
-        V2: Clone + Send + Sync + 'static,
-        F: Fn(Option<V>) -> Option<V2> + Send + Sync + 'static
-    >(
-        self,
-        f: F
-    ) -> OuterViewPort<K, V2> {
-        let port = ViewPort::new();
-        let view = self.add_observer_fn({
-            let dst = port.inner();
-            move |key| dst.notify(key)
-        });
-        port.inner().set_view_fn(move |key| f(view.view(key)));
-        port.outer()
-    }
- 
-    pub fn map_key<
-        K2: Clone + Send + Sync + 'static,
-        F1: Fn(K) -> K2 + Send + Sync + 'static,
-        F2: Fn(K2) -> K + Send + Sync + 'static
-    >(
-        self,
-        f1: F1,
-        f2: F2
-    ) -> OuterViewPort<K2, V> {
-        let port = ViewPort::new();
-        let view = self.add_observer_fn({
-            let dst = port.inner();
-            move |key| dst.notify(f1(key))
-        });
-        port.inner().set_view_fn(move |key| view.view(f2(key)));
-        port.outer()
-    }
-}
-
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-impl<K: Send + Sync + 'static, V: Send + Sync + 'static> InnerViewPort<K, V> {
-    pub fn set_view(&self, view: Arc<dyn View<Key = K, Value = V> + Send + Sync>) {
-        *self.0.view.write().unwrap() = Some(view);
-    }
-
-    pub fn set_view_fn(&self, view_fn: impl Fn(K) -> Option<V> + Send + Sync + 'static) {
-        self.set_view(Arc::new(FnView::new(view_fn)))
-    }
-}
-
-impl<K, V> Observer for InnerViewPort<K, V>
-where K: Clone + Send + Sync + 'static,
-      V: Send + Sync + 'static {
-    type Msg = K;
-
-    fn notify(&self, msg: K) {
-        for observer in self.0.observers.read().unwrap().iter() {
-            observer.notify(msg.clone());
-        }
-    }    
-}
-
-                    /*\
-<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-                Stream Port
-<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-                    \*/
-
-/*
-pub struct StreamPort<T> {
-    actions: Vec<Arc<Mutex<dyn FnMut(T)>>>
-}
-
-impl<T> StreamPort<T> {
-    async fn set_stream(&self, stream: impl Stream<T>) -> impl Future<()> {
-        for msg in stream.next().await.unwrap() {
-            for act in self.actions.iter() {
-                (*act.lock().unwrap())(msg);
-            }
-        }
-    }
-
-    fn add_action(&self, action: impl FnMut(T)) {
-        self.actions.push(Arc::new(Mutex::new(action)))
-    }
-}
- */
-
-
diff --git a/src/string_editor.rs b/src/string_editor.rs
index aeb2215..85db477 100644
--- a/src/string_editor.rs
+++ b/src/string_editor.rs
@@ -1,40 +1,54 @@
 use {
-    std::sync::{Arc, RwLock},
-    cgmath::Vector2,
+    std::{
+        ops::Range,
+        sync::{Arc, RwLock},
+    },
+    cgmath::Point2,
     crate::{
-        view::{View, Observer, ObserverExt},
-        port::{ViewPort, InnerViewPort, OuterViewPort},
-        terminal::{TerminalAtom, TerminalStyle},
-        vec_buffer::VecBuffer
+        core::{
+            View,
+            Observer,
+            ObserverExt,
+            ObserverBroadcast,
+            ViewPort,
+            InnerViewPort,
+            OuterViewPort
+        },
+        sequence::SequenceView,
+        index::{ImplIndexView},
+        grid::{GridView},
+        terminal::{TerminalAtom, TerminalStyle, TerminalView},
+        //vec_buffer::VecBuffer
     }
 };
 
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
 pub struct StringEditorState {
     cursor: usize,
     data: Arc<RwLock<Vec<char>>>
 }
 
-impl View for StringEditorState {
-    type Key = Vector2<i16>;
-    type Value = TerminalAtom;
+impl ImplIndexView for StringEditorState {
+    type Key = Point2<i16>;
+    type Value = Option<TerminalAtom>;
+
+    fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
+        let data = self.data.read().unwrap();
 
-    fn view(&self, pos: Vector2<i16>) -> Option<TerminalAtom> {
         if pos.y == 0 {
-            let cur = self.cursor;
-            let data = self.data.read().unwrap();
-
             if pos.x < data.len() as i16 + 3 {
                 let i = pos.x as usize;
                 return Some(
                     if i == 0 {
                         TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
-                    } else if i-1 == cur {
+                    } else if i-1 == self.cursor {
                         TerminalAtom::new('|', TerminalStyle::fg_color((180,200,130)).add(TerminalStyle::bold(true)))
                     } else if i-1 == data.len()+1 {
                         TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
                     } else {
                         TerminalAtom::new(
-                            data.get(i as usize - if i <= cur { 1 } else { 2 }).cloned().unwrap(),
+                            data.get(i as usize - if i <= self.cursor { 1 } else { 2 }).unwrap().clone(),
                             TerminalStyle::fg_color((80,150,80))
                         )
                     }
@@ -43,42 +57,35 @@ impl View for StringEditorState {
         }
 
         None
+    }        
+
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        Some(
+            Point2::new(0, 0)
+                .. Point2::new(self.data.read().unwrap().len() as i16 + 3, 1)
+        )
     }
 }
 
 pub struct StringEditor {
     state: Arc<RwLock<StringEditorState>>,
-    port: InnerViewPort<Vector2<i16>, TerminalAtom>
+    cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
 }
 
 impl StringEditor {
     pub fn new(
-        port: InnerViewPort<Vector2<i16>, TerminalAtom>
+        port: InnerViewPort<dyn TerminalView>
     ) -> Self {
         let state = Arc::new(RwLock::new(StringEditorState{
-            cursor: 0,
-            data: Arc::new(RwLock::new(Vec::new()))
+            cursor: 7,
+            data: Arc::new(RwLock::new("edit me".chars().collect()))
         }));
-/*
-        let buf_port = ViewPort::new();
-        let buf = VecBuffer::with_data(data.clone(), buf_port.inner());
 
-        buf_port.outer().add_observer_fn({
-            let port = port.clone();
-            let cursor = cursor.clone();
+        let cast = port.set_view(Some(state.clone()));
 
-            move |idx|
-            if idx < *cursor.read().unwrap() {
-                port.notify(Vector2::new(1 + idx as i16, 0));
-            } else {
-                port.notify(Vector2::new(2 + idx as i16, 0));
-            }
-        });
-*/
-        port.set_view(state.clone());
         StringEditor {
             state,
-            port
+            cast
         }
     }
 
@@ -109,26 +116,26 @@ impl StringEditor {
             old_idx
         };
 
-        self.port.notify_each(
+        self.cast.notify_each(
             (std::cmp::min(old_idx, new_idx) ..= std::cmp::max(old_idx, new_idx))
-            .map(|idx| Vector2::new(1+idx as i16, 0))
+            .map(|idx| Point2::new(1+idx as i16, 0))
         );
     }
 
     pub fn insert(&mut self, c: char) {
-        self.port.notify_each({
+        self.cast.notify_each({
             let mut state = self.state.write().unwrap();
             let mut data = state.data.write().unwrap();
 
             data.insert(state.cursor, c);
             (state.cursor .. data.len()+2)
-        }.map(|idx| Vector2::new(1+idx as i16, 0)));
+        }.map(|idx| Point2::new(1+idx as i16, 0)));
 
         self.next();
     }
 
     pub fn delete(&mut self) {
-        self.port.notify_each({
+        self.cast.notify_each({
             let mut state = self.state.write().unwrap();
             let mut data = state.data.write().unwrap();
 
@@ -136,7 +143,7 @@ impl StringEditor {
                 data.remove(state.cursor);
             }
             (state.cursor .. data.len()+3)
-        }.map(|idx| Vector2::new(1+idx as i16, 0)));
+        }.map(|idx| Point2::new(1+idx as i16, 0)));
     }
 }
 
diff --git a/src/terminal/compositor.rs b/src/terminal/compositor.rs
index a174823..c66e97d 100644
--- a/src/terminal/compositor.rs
+++ b/src/terminal/compositor.rs
@@ -1,53 +1,175 @@
 use {
-    std::sync::{Arc, RwLock},
-    cgmath::Vector2,
+    std::{
+        sync::{Arc, Weak, RwLock},
+        collections::HashMap,
+        ops::Range,
+        cmp::{min, max}
+    },
+    cgmath::Point2,
     crate::{
-        view::{View},
-        port::{ViewPort, InnerViewPort, OuterViewPort},
-        terminal::{TerminalAtom}
+        core::{View, ViewPort, InnerViewPort, OuterViewPort, Observer, ObserverExt, ObserverBroadcast},
+        view::{ImplIndexView, grid::GridWindowIterator},
+        terminal::{TerminalAtom, TerminalView}
     }
 };
 
-pub struct TerminalCompositor {
-    layers: Arc<RwLock<Vec<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>>>,
-    port: Arc<InnerViewPort<Vector2<i16>, TerminalAtom>>
+struct CompositeLayer {
+    comp: Weak<RwLock<TerminalCompositeView>>,
+    idx: usize,
+    view: RwLock<Option<Arc<dyn TerminalView>>>
 }
 
-impl TerminalCompositor {
-    pub fn new(port: InnerViewPort<Vector2<i16>, TerminalAtom>) -> Self {
-        let layers = Arc::new(RwLock::new(Vec::<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>::new()));
+impl Observer<dyn TerminalView> for CompositeLayer {
+    fn reset(&self, view: Option<Arc<dyn TerminalView>>) {
+        let comp = self.comp.upgrade().unwrap();
+        let mut c = comp.write().unwrap();
 
-        port.set_view_fn({
-            let layers = layers.clone();
-            move |pos| {
-                let mut atom = None;
+        {
+            let mut v = self.view.write().unwrap();
+            let old_view = v.clone();
+            *v = view.clone();
 
-                for l in layers.read().unwrap().iter() {
-                    match (atom, l.view(pos)) {
+            if let Some(old_view) = old_view {
+                if let Some(range) = old_view.range() {
+                    c.cast.notify_each(GridWindowIterator::from(range));
+                }
+            }
+
+            if let Some(view) = v.as_ref() {
+                if let Some(range) = view.range() {
+                    c.cast.notify_each(GridWindowIterator::from(range));
+                }
+            }
+        }
+
+        c.update_range();
+    }
+
+    fn notify(&self, pos: &Point2<i16>) {
+        self.comp
+            .upgrade().unwrap()
+            .read().unwrap()
+            .cast.notify(pos);
+    }
+}
+
+pub struct TerminalCompositeView {
+    idx_count: usize,
+    layers: HashMap<usize, Arc<CompositeLayer>>,
+    range: Option<Range<Point2<i16>>>,
+    cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
+}
+
+impl TerminalCompositeView {
+    fn update_range(&mut self) {
+        if self.layers.len() == 0 {
+            self.range = Some(Point2::new(0, 0) .. Point2::new(0, 0))
+        } else {
+            self.range = None;
+
+            for (idx, layer) in self.layers.iter() {
+                self.range =
+                    if let (
+                        Some(new_range),
+                        Some(old_range)
+                    ) = (
+                        if let Some(view) = layer.view.read().unwrap().clone() {
+                            view.range().clone()
+                        } else {
+                            None
+                        },
+                        self.range.as_ref()
+                    ) {
+                        Some(
+                            Point2::new(
+                                min(old_range.start.x, new_range.start.x),
+                                min(old_range.start.y, new_range.start.y)
+                            ) .. Point2::new(
+                                max(old_range.end.x, new_range.end.x),
+                                max(old_range.end.y, new_range.end.y)
+                            )
+                        )
+                    } else {
+                        None
+                    };
+            }
+        }
+    }
+}
+
+impl ImplIndexView for TerminalCompositeView {
+    type Key = Point2<i16>;
+    type Value = Option<TerminalAtom>;
+
+    fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
+        let mut atom = None;
+
+        for idx in 0 .. self.idx_count {
+            if let Some(l) = self.layers.get(&idx) {
+                if let Some(view) = l.view.read().unwrap().as_ref() {
+                    if let Some(range) = view.range() {
+                        if pos.x < range.start.x ||
+                            pos.x >= range.end.x ||
+                            pos.y < range.start.y ||
+                            pos.y >= range.end.y {
+                                continue;
+                            }
+                    }
+
+                    match (atom, view.get(pos)) {
                         (None, next) => atom = next,
                         (Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)),
                         _ => {}
                     }
                 }
-
-                atom
             }
-        });
-        
-        TerminalCompositor {
-            layers,
-            port: Arc::new(port)
         }
+
+        atom
     }
 
-    pub fn push(&mut self, v: OuterViewPort<Vector2<i16>, TerminalAtom>) {
-        self.layers.write().unwrap().push(v.add_observer(self.port.clone()));
-    }
-    
-    pub fn make_port(&mut self) -> InnerViewPort<Vector2<i16>, TerminalAtom> {
-        let port = ViewPort::new();
-        self.push(port.outer());
-        port.inner()
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        self.range.clone()
+    }
+}
+
+pub struct TerminalCompositor {
+    view: Arc<RwLock<TerminalCompositeView>>,
+    port: InnerViewPort<dyn TerminalView>
+}
+
+impl TerminalCompositor {
+    pub fn new(
+        port: InnerViewPort<dyn TerminalView>
+    ) -> Self {
+        let view = Arc::new(RwLock::new(
+            TerminalCompositeView {
+                idx_count: 0,
+                layers: HashMap::new(),
+                range: Some(Point2::new(0, 0) .. Point2::new(0, 0)),
+                cast: port.get_broadcast()
+            }
+        ));
+
+        port.set_view(Some(view.clone()));
+        TerminalCompositor{ view, port }
+    }
+
+    pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {        
+        let mut comp = self.view.write().unwrap();
+        let idx = comp.idx_count;
+        comp.idx_count += 1;
+
+        let layer = Arc::new(CompositeLayer {
+            comp: Arc::downgrade(&self.view),
+            idx: idx,
+            view: RwLock::new(None)
+        });
+
+        comp.layers.insert(idx, layer.clone());
+        drop(comp);
+
+        v.add_observer(layer);
     }
 }
 
diff --git a/src/terminal/mod.rs b/src/terminal/mod.rs
index 3296bc0..f07e7eb 100644
--- a/src/terminal/mod.rs
+++ b/src/terminal/mod.rs
@@ -7,6 +7,24 @@ pub use {
     style::{TerminalStyle},
     atom::{TerminalAtom},
     terminal::{Terminal, TerminalEvent},
-    compositor::TerminalCompositor
+    compositor::TerminalCompositor,
 };
 
+use {
+    crate::{
+        core::View,
+        view::{
+            IndexView,
+            GridView
+        }
+    },
+    cgmath::Point2,
+    std::ops::Range
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait TerminalView = GridView<Item = Option<TerminalAtom>>;
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
diff --git a/src/terminal/terminal.rs b/src/terminal/terminal.rs
index 1a5c5b2..3123f38 100644
--- a/src/terminal/terminal.rs
+++ b/src/terminal/terminal.rs
@@ -1,23 +1,40 @@
-
 use {
-    std::io::{Write, stdout, stdin},
+    std::{
+        sync::{Arc, RwLock},
+        io::{Write, stdout, stdin},
+        collections::HashSet
+    },
     async_std::{
         stream::StreamExt,
         task
     },
     signal_hook,
     signal_hook_async_std::Signals,
-    cgmath::Vector2,
+    cgmath::{Vector2, Point2},
     termion::{
         raw::IntoRawMode,
         input::{TermRead, MouseTerminal}
     },
-    super::{TerminalAtom, TerminalStyle},
     crate::{
-        view::{View, Observer},
-        port::{OuterViewPort},
-        channel::ChannelReceiver
-    }
+        core::{
+            OuterViewPort,
+            Observer,
+            channel::{
+                ChannelReceiver,
+                ChannelSender,
+                queue_channel,
+                set_channel
+            }
+        },
+        view::{
+            IndexView,
+            grid::GridWindowIterator
+        }
+    },
+    super::{
+        TerminalStyle,
+        TerminalView
+    },
 };
 
 pub enum TerminalEvent {
@@ -26,36 +43,56 @@ pub enum TerminalEvent {
 }
 
 pub struct Terminal {
+    writer: Arc<TermOutWriter>,
+    observer: Arc<TermOutObserver>,
+
     events: ChannelReceiver<Vec<TerminalEvent>>,
-    signal_handle: signal_hook_async_std::Handle
+    _signal_handle: signal_hook_async_std::Handle
 }
 
 impl Terminal {
-    pub fn new() -> Self {
-        let (event_tx, event_rx) = crate::channel::queue_channel();
+    pub fn new(
+        port: OuterViewPort<dyn TerminalView>
+    ) -> Self {
+        let (dirty_pos_tx, dirty_pos_rx) = set_channel();
+
+        let writer = Arc::new(TermOutWriter {
+            out: RwLock::new(MouseTerminal::from(stdout().into_raw_mode().unwrap())),
+            dirty_pos_rx,
+            view: port.get_view_arc()
+        });
+
+        let observer = Arc::new(TermOutObserver {
+            dirty_pos_tx,
+            writer: writer.clone()
+        });
+
+        port.add_observer(observer.clone());
+
+        let (event_tx, event_rx) = queue_channel();
 
         let input_tx = event_tx.clone();
         std::thread::spawn(move || {
             for event in stdin().events() {
-                input_tx.notify(TerminalEvent::Input(event.unwrap()));
+                input_tx.send(TerminalEvent::Input(event.unwrap()));
             }
         });
 
         // send initial teriminal size
-        let (w,h) = termion::terminal_size().unwrap();
-        event_tx.notify(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
+        let (w, h) = termion::terminal_size().unwrap();
+        event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
 
         // and again on SIGWINCH
-        let signals = Signals::new(&[ signal_hook::SIGWINCH ]).unwrap();
+        let signals = Signals::new(&[ signal_hook::consts::signal::SIGWINCH ]).unwrap();
         let handle = signals.handle();
 
         task::spawn(async move {
             let mut signals = signals.fuse();
             while let Some(signal) = signals.next().await {
                 match signal {
-                    signal_hook::SIGWINCH => {
+                    signal_hook::consts::signal::SIGWINCH => {
                         let (w,h) = termion::terminal_size().unwrap();
-                        event_tx.notify(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
+                        event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
                     },
                     _ => unreachable!(),
                 }
@@ -63,61 +100,107 @@ impl Terminal {
         });
 
         Terminal {
+            writer,
+            observer,
             events: event_rx,
-            signal_handle: handle
+            _signal_handle: handle
         }
     }
 
+    pub fn get_writer(&self) -> Arc<TermOutWriter> {
+        self.writer.clone()
+    }
+
     pub async fn next_event(&mut self) -> TerminalEvent {
         self.events.next().await.unwrap()
     }
+}
 
-    pub async fn show(view_port: OuterViewPort<Vector2<i16>, TerminalAtom>) -> std::io::Result<()> {
-        let (atom_tx, atom_rx) = crate::channel::queue_channel();
+struct TermOutObserver {
+    dirty_pos_tx: ChannelSender<HashSet<Point2<i16>>>,
+    writer: Arc<TermOutWriter>
+}
 
-        let view = view_port.get_view();
-        view_port.add_observer_fn(move |pos| atom_tx.notify((pos, view.view(pos))));
+impl Observer<dyn TerminalView> for TermOutObserver {
+    fn reset(&self, view: Option<Arc<dyn TerminalView>>) {
+        self.writer.reset();
 
-        Self::show_stream(atom_rx).await
+        let (w, h) = termion::terminal_size().unwrap();
+        if let Some(view) = view {
+            for pos in GridWindowIterator::from(
+                view.range().unwrap_or(
+                    Point2::new(0, 0) .. Point2::new(w as i16, h as i16)
+                )
+            ) {
+                self.dirty_pos_tx.send(pos);
+            }
+        }
     }
 
-    pub async fn show_stream(recv: ChannelReceiver<Vec<(Vector2<i16>, Option<TerminalAtom>)>>) -> std::io::Result<()> {
-        let mut out = MouseTerminal::from(stdout().into_raw_mode().unwrap());
-        let mut cur_pos = Vector2::<i16>::new(0, 0);
-        let mut cur_style = TerminalStyle::default();
-            write!(out, "{}{}{}{}",
-                   termion::clear::All,
-                   termion::cursor::Goto(1, 1),
-                   termion::cursor::Hide,
-                   termion::style::Reset)?;
-
-        while let Some(atoms) = recv.recv().await {
-            for (pos, atom) in atoms.into_iter() {
-                if pos != cur_pos+Vector2::new(1,0) {
-                    write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?;
-                }
-                cur_pos = pos;
-
-                if let Some(atom) = atom {
-                    if cur_style != atom.style {
-                        cur_style = atom.style;
-                        write!(out, "{}", atom.style)?;
-                    }
-
-                    write!(out, "{}", atom.c.unwrap_or(' '))?;
-                } else {
-                    write!(out, "{} ", termion::style::Reset)?;
-                    cur_style = TerminalStyle::default();
-                }
-            }
-
-            out.flush()?;
-        }
-
-        write!(out, "{}", termion::cursor::Show)?;
-        out.flush()?;
-
-        std::io::Result::Ok(())        
+    fn notify(&self, pos: &Point2<i16>) {
+        self.dirty_pos_tx.send(*pos);
+    }
+}
+
+pub struct TermOutWriter {
+    out: RwLock<MouseTerminal<termion::raw::RawTerminal<std::io::Stdout>>>,
+    dirty_pos_rx: ChannelReceiver<HashSet<Point2<i16>>>,
+    view: Arc<RwLock<Option<Arc<dyn TerminalView>>>>
+}
+
+impl TermOutWriter {
+    fn reset(&self) {
+        let mut out = self.out.write().unwrap();
+        write!(out, "{}", termion::clear::All).ok();        
+    }
+}
+
+impl TermOutWriter {
+    pub async fn show(&self) -> std::io::Result<()> {
+        // init
+        write!(self.out.write().unwrap(), "{}{}{}",
+               termion::cursor::Hide,
+               termion::cursor::Goto(1, 1),
+               termion::style::Reset)?;
+
+        let mut cur_pos = Point2::<i16>::new(0, 0);
+        let mut cur_style = TerminalStyle::default();
+
+        // draw atoms until view port is destroyed
+        while let Some(dirty_pos) = self.dirty_pos_rx.recv().await {
+            if let Some(view) = self.view.read().unwrap().as_ref() {
+                let mut out = self.out.write().unwrap();
+
+                for pos in dirty_pos.into_iter() {
+                    if pos != cur_pos {
+                        write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?;
+                    }
+
+                    if let Some(atom) = view.get(&pos) {
+                        if cur_style != atom.style {
+                            cur_style = atom.style;
+                            write!(out, "{}", atom.style)?;
+                        }
+
+                        write!(out, "{}", atom.c.unwrap_or(' '))?;
+                    } else {
+                        write!(out, "{} ", termion::style::Reset)?;
+                        cur_style = TerminalStyle::default();
+                    }
+
+                    cur_pos = pos + Vector2::new(1, 0);
+                }
+
+                out.flush()?;
+            }
+        }
+
+        // restore conventional terminal settings
+        let mut out = self.out.write().unwrap();
+        write!(out, "{}", termion::cursor::Show)?;
+        out.flush()?;
+
+        std::io::Result::Ok(())
     }
 }
 
diff --git a/src/view.rs b/src/view.rs
deleted file mode 100644
index 8c0c915..0000000
--- a/src/view.rs
+++ /dev/null
@@ -1,189 +0,0 @@
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-pub trait View : Send + Sync {
-    type Key;
-    type Value;
-
-    fn view(&self, key: Self::Key) -> Option<Self::Value>;
-}
-
-pub trait Observer : Send + Sync {
-    type Msg;
-
-    fn notify(&self, key: Self::Msg);
-}
-
-pub trait ObserverExt : Observer {
-    fn notify_each(&self, it: impl IntoIterator<Item = Self::Msg>);
-}
-
-impl<T: Observer> ObserverExt for T {
-    fn notify_each(&self, it: impl IntoIterator<Item = Self::Msg>) {
-        for msg in it {
-            self.notify(msg);
-        }
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-use cgmath::Vector2;
-
-pub trait SingletonView = View<Key = ()>;
-pub trait SingletonObserver = Observer<Msg = ()>;
-
-pub trait SequenceView = View<Key = usize>;
-pub trait SequenceObserver = Observer<Msg = usize>;
-
-pub trait GridView = View<Key = Vector2<i16>>;
-pub trait GridObserver = Observer<Msg = Vector2<i16>>;
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-pub struct FnView<K, V, F>
-where K: Send + Sync,
-      V: Send + Sync,
-      F: Fn(K) -> Option<V> + Send + Sync {
-    f: F,
-    _phantom0: std::marker::PhantomData<K>,
-    _phantom1: std::marker::PhantomData<V>
-}
-
-impl<K, V, F> FnView<K, V, F>
-where K: Send + Sync,
-      V: Send + Sync,
-      F: Fn(K) -> Option<V> + Send + Sync {
-    pub fn new(f: F) -> Self {
-        FnView {
-            f,
-            _phantom0: std::marker::PhantomData,
-            _phantom1: std::marker::PhantomData
-        }
-    }
-}
-
-impl<K, V, F> View for FnView<K, V, F>
-where K: Send + Sync,
-      V: Send + Sync,
-      F: Fn(K) -> Option<V> + Send + Sync {
-    type Key = K;
-    type Value = V;
-
-    fn view(&self, key: K) -> Option<V> {
-        (self.f)(key)
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-pub struct FnObserver<T, F>
-where T: Send + Sync,
-      F: Fn(T) + Send + Sync {
-    f: F,
-    _phantom: std::marker::PhantomData<T>
-}
-
-impl<T, F> FnObserver<T, F>
-where T: Send + Sync,
-      F: Fn(T) + Send + Sync {
-    pub fn new(f: F) -> Self {
-        FnObserver {
-            f,
-            _phantom: std::marker::PhantomData
-        }
-    }
-}
-
-impl<T, F> Observer for FnObserver<T, F>
-where T: Send + Sync,
-      F: Fn(T) + Send + Sync {
-    type Msg = T;
-
-    fn notify(&self, msg: T) {
-        (self.f)(msg);
-    }
-}
-
-//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
-
-use std::ops::Deref;
-use std::sync::{Arc, RwLock};
-
-impl<T: View> View for RwLock<T> {
-    type Key = T::Key;
-    type Value = T::Value;
-
-    fn view(&self, key: T::Key) -> Option<T::Value> {
-        self.read().unwrap().view(key)
-    }
-}
-
-impl<T: Observer> Observer for RwLock<T> {
-    type Msg = T::Msg;
-
-    fn notify(&self, msg: T::Msg) {
-        self.read().unwrap().notify(msg)
-    }
-}
-
-impl<T: View> View for Arc<T> {
-    type Key = T::Key;
-    type Value = T::Value;
-
-    fn view(&self, key: T::Key) -> Option<T::Value> {
-        self.deref().view(key)
-    }
-}
-
-impl<T: Observer> Observer for Arc<T> {
-    type Msg = T::Msg;
-
-    fn notify(&self, msg: T::Msg) {
-        self.deref().notify(msg)
-    }
-}
-
-impl<K, V> View for Arc<dyn View<Key = K, Value = V>>
-where K: Send + Sync,
-      V: Send + Sync {
-    type Key = K;
-    type Value = V;
-
-    fn view(&self, key: K) -> Option<V> {
-        self.deref().view(key)
-    }
-}
-
-impl<T> Observer for Arc<dyn Observer<Msg = T>>
-where T:  Send + Sync {
-    type Msg = T;
-
-    fn notify(&self, msg: T) {
-        self.deref().notify(msg)
-    }
-}
-
-impl<T: View> View for Option<T> {
-    type Key = T::Key;
-    type Value = T::Value;
-
-    fn view(&self, key: T::Key) -> Option<T::Value> {
-        if let Some(view) = self.as_ref() {
-            view.view(key)
-        } else {
-            None
-        }
-    }
-}
-
-impl<T: Observer> Observer for Option<T> {
-    type Msg = T::Msg;
-
-    fn notify(&self, msg: T::Msg) {
-        if let Some(obs) = self.as_ref() {
-            obs.notify(msg);
-        }
-    }
-}
-
diff --git a/src/view/grid.rs b/src/view/grid.rs
new file mode 100644
index 0000000..81bddf8
--- /dev/null
+++ b/src/view/grid.rs
@@ -0,0 +1,78 @@
+use {
+    std::{
+        sync::{Arc, RwLock},
+        ops::{Deref, Range}
+    },
+    cgmath::{Point2, Vector2},
+    crate::{
+        core::View,
+        view::{IndexView, ImplIndexView}
+    }
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait GridView = IndexView<Point2<i16>>;
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+/*
+pub trait ImplGridView : Send + Sync {
+    type Item;
+
+    fn get(&self, pos: &Point2<i16>) -> Self::Item;
+
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        None
+    }
+}
+
+impl<V: ImplGridView> ImplIndexView for V {
+    type Key = Point2<i16>;
+    type Value = V::Item;
+
+    fn get(&self, pos: &Point2<i16>) -> V::Item {
+        (self as &V).get(pos)
+    }
+
+    fn range(&self) -> Option<Range<Point2<i16>>> {
+        (self as &V).range()
+    }
+}
+*/
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct GridWindowIterator {
+    next: Point2<i16>,
+    range: Range<Point2<i16>>
+}
+
+impl From<Range<Point2<i16>>> for GridWindowIterator {
+    fn from(range: Range<Point2<i16>>) -> Self {
+        GridWindowIterator {
+            next: range.start,
+            range
+        }
+    }
+}
+
+impl Iterator for GridWindowIterator {
+    type Item = Point2<i16>;
+
+    fn next(&mut self) -> Option<Point2<i16>> {
+        if self.next.y < self.range.end.y {
+            let next = self.next;
+
+            if self.next.x+1 < self.range.end.x {
+                self.next.x += 1;
+            } else {
+                self.next.x = self.range.start.x;
+                self.next.y += 1;
+            }
+
+            Some(next)
+        } else {
+            None
+        }
+    }
+}
+
diff --git a/src/view/index.rs b/src/view/index.rs
new file mode 100644
index 0000000..bed5dac
--- /dev/null
+++ b/src/view/index.rs
@@ -0,0 +1,73 @@
+use {
+    std::{
+        sync::{Arc, RwLock},
+        ops::{Deref, Range}
+    },
+    crate::core::View
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait IndexView<Key> : View<Msg = Key> {
+    type Item;
+
+    fn get(&self, key: &Key) -> Self::Item;
+
+    fn range(&self) -> Option<Range<Key>> {
+        None
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<Key, V: IndexView<Key>> IndexView<Key> for RwLock<V> {
+    type Item = V::Item;
+
+    fn get(&self, key: &Key) -> Self::Item {
+        self.read().unwrap().get(key)
+    }
+
+    fn range(&self) -> Option<Range<Key>> {
+        self.read().unwrap().range()
+    }
+}
+
+impl<Key, V: IndexView<Key>> IndexView<Key> for Arc<V> {
+    type Item = V::Item;
+
+    fn get(&self, key: &Key) -> Self::Item {
+        self.deref().get(key)
+    }
+    
+    fn range(&self) -> Option<Range<Key>> {
+        self.deref().range()
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait ImplIndexView : Send + Sync {
+    type Key;
+    type Value;
+
+    fn get(&self, key: &Self::Key) -> Self::Value;
+    fn range(&self) -> Option<Range<Self::Key>> {
+        None
+    }    
+}
+
+impl<V: ImplIndexView> View for V {
+    type Msg = V::Key;
+}
+
+impl<V: ImplIndexView> IndexView<V::Key> for V {
+    type Item = V::Value;
+
+    fn get(&self, key: &V::Key) -> Self::Item {
+        (self as &V).get(key)
+    }
+
+    fn range(&self) -> Option<Range<V::Key>> {
+        (self as &V).range()
+    }
+}
diff --git a/src/view/mod.rs b/src/view/mod.rs
new file mode 100644
index 0000000..de3db23
--- /dev/null
+++ b/src/view/mod.rs
@@ -0,0 +1,13 @@
+pub mod singleton;
+pub mod index;
+pub mod sequence;
+pub mod grid;
+
+pub use {
+    singleton::SingletonView,
+    index::{IndexView, ImplIndexView},
+    sequence::SequenceView,
+    grid::GridView,
+    crate::core::View
+};
+
diff --git a/src/view/sequence.rs b/src/view/sequence.rs
new file mode 100644
index 0000000..0c00374
--- /dev/null
+++ b/src/view/sequence.rs
@@ -0,0 +1,41 @@
+use {
+    std::{
+        sync::{Arc, RwLock},
+        ops::{Range, Deref}
+    },
+    super::{IndexView, ImplIndexView},
+    crate::core::View
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub trait SequenceView = IndexView<usize>;
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+/*
+pub trait ImplSequenceView : Send + Sync {
+    type Item;
+
+    fn get(&self, idx: usize) -> Self::Item;
+    fn len(&self) -> Option<usize> {
+        None
+    }
+}
+
+impl<V: ImplSequenceView> ImplIndexView for V {
+    type Key = usize;
+    type Value = V::Item;
+
+    fn get(&self, idx: &usize) -> V::Item {
+        (self as V).get(*idx)
+    }
+
+    fn range(&self) -> Option<Range<usize>> {
+        if let Some(len) = (self as V).len() {
+            Some(0 .. len)
+        } else {
+            None
+        }
+    }
+}
+*/
diff --git a/src/view/singleton.rs b/src/view/singleton.rs
new file mode 100644
index 0000000..ca0b6ca
--- /dev/null
+++ b/src/view/singleton.rs
@@ -0,0 +1,53 @@
+use {
+    std::{
+        sync::{Arc, RwLock},
+        ops::Deref
+    },
+    crate::core::{View}
+};
+
+// TODO: #[ImplForArc, ImplForRwLock]
+pub trait SingletonView : View<Msg = ()> {
+    type Item;
+
+    fn get(&self) -> Self::Item;
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<V: SingletonView> SingletonView for RwLock<V> {
+    type Item = V::Item;
+
+    fn get(&self) -> Self::Item {
+        self.read().unwrap().get()
+    }
+}
+
+impl<V: SingletonView> SingletonView for Arc<V> {
+    type Item = V::Item;
+
+    fn get(&self) -> Self::Item {
+        self.deref().get()
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+/*
+pub trait ImplSingletonView : Send + Sync {
+    type Item;
+
+    fn get(&self) -> Self::Item;
+}
+
+impl<V: ImplSingletonView> View for V {
+    type Msg = ();
+}
+
+impl<V: ImplSingletonView> SingletonView for V {
+    type Item = V::Item;
+
+    fn get(&self) -> Self::Item {
+        (self as &V).get()
+    }
+}
+*/