move list editor module to nested crate

This commit is contained in:
Michael Sippel 2021-08-11 17:49:58 +02:00
parent 2d17254b2c
commit 07ee04bba4
Signed by: senvas
GPG key ID: F96CF119C34B64A6
6 changed files with 963 additions and 347 deletions

View file

@ -10,6 +10,7 @@ pub mod sequence;
pub mod vec;
pub mod terminal;
pub mod integer;
pub mod list;
pub mod string_editor;
pub mod leveled_term_view;

427
nested/src/list/editor.rs Normal file
View file

@ -0,0 +1,427 @@
use {
std::sync::{Arc, RwLock},
termion::event::{Event, Key},
crate::{
core::{
View,
ViewPort,
OuterViewPort,
InnerViewPort,
ObserverBroadcast,
Observer,
ObserverExt,
context::{
ReprTree,
Object,
MorphismType,
MorphismMode,
Context
}
},
projection::ProjectionHelper,
singleton::{SingletonView, SingletonBuffer},
sequence::{SequenceView},
vec::{VecBuffer},
terminal::{
TerminalView,
TerminalStyle,
TerminalEvent,
TerminalEditor,
TerminalEditorResult,
make_label
},
string_editor::StringEditor,
leveled_term_view::LeveledTermView,
list::SExprView
}
};
#[derive(Clone, Copy, PartialEq, Eq)]
enum ListEditorCursor {
None,
Insert(usize),
Select(usize),
Edit(usize)
}
impl Default for ListEditorCursor {
fn default() -> Self {
ListEditorCursor::None
}
}
pub struct ListEditor<SubEditor, FnMakeItemEditor>
where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
{
cursor: SingletonBuffer<ListEditorCursor>,
data: VecBuffer<Arc<RwLock<SubEditor>>>,
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>>>,
}
impl<SubEditor, FnMakeItemEditor> TerminalEditor for ListEditor<SubEditor, FnMakeItemEditor>
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)
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match self.cursor.get() {
ListEditorCursor::None => {
}
ListEditorCursor::Insert(idx) => {
match event {
TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.cursor.set(ListEditorCursor::Select(idx));
}
TerminalEvent::Input(Event::Key(Key::Left)) => {
if idx > 0 {
self.cursor.set(ListEditorCursor::Insert(idx-1));
}
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
if idx < self.data.len() {
self.cursor.set(ListEditorCursor::Insert(idx+1));
}
}
event => {
self.data.insert(idx, (self.make_item_editor)());
self.cursor.set(ListEditorCursor::Edit(idx));
self.data.get_mut(idx).write().unwrap().handle_terminal_event(event);
}
}
}
ListEditorCursor::Select(idx) => {
match event {
TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.cursor.set(ListEditorCursor::Insert(idx));
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.remove(idx);
if self.data.len() == 0 {
self.cursor.set(ListEditorCursor::Insert(0));
} else if idx == self.data.len() && idx > 0 {
self.cursor.set(ListEditorCursor::Select(idx-1))
}
}
TerminalEvent::Input(Event::Key(Key::Home)) => {
if self.data.len() > 0 {
self.cursor.set(ListEditorCursor::Select(0))
} else {
self.cursor.set(ListEditorCursor::Insert(0))
}
}
TerminalEvent::Input(Event::Key(Key::End)) => {
if self.data.len() > 0 {
self.cursor.set(ListEditorCursor::Select(self.data.len() - 1))
} else {
self.cursor.set(ListEditorCursor::Insert(0))
}
}
TerminalEvent::Input(Event::Key(Key::Left)) => {
if idx > 0 {
self.cursor.set(ListEditorCursor::Select(idx - 1));
}
}
TerminalEvent::Input(Event::Key(Key::Right)) => {
if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Select(idx + 1));
}
}
event => {
self.cursor.set(ListEditorCursor::Edit(idx));
self.data.get_mut(idx).write().unwrap().handle_terminal_event(event);
}
}
}
ListEditorCursor::Edit(idx) => {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\t'))) => {
if idx > 0 {
self.cursor.set(ListEditorCursor::Edit(idx-1));
}
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Edit(idx+1));
}
}
TerminalEvent::Input(Event::Key(Key::Char(' '))) => {
// split..
self.data.insert(idx+1, (self.make_item_editor)());
self.data.get_mut(idx).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End)));
self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home)));
self.cursor.set(ListEditorCursor::Edit(idx+1));
}
event => {
let ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap();
match cur_edit.handle_terminal_event(event) {
TerminalEditorResult::Exit => {
match event {
TerminalEvent::Input(Event::Key(Key::Up)) => {
self.cursor.set(ListEditorCursor::Select(idx));
}
TerminalEvent::Input(Event::Key(Key::Home)) => {
if idx > 0 {
self.cursor.set(ListEditorCursor::Edit(idx-1));
self.data.get_mut(idx-1).write().unwrap().handle_terminal_event(event);
} else {
cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home)));
}
}
TerminalEvent::Input(Event::Key(Key::Backspace)) | // -> join
TerminalEvent::Input(Event::Key(Key::Left)) => {
if idx > 0 {
self.cursor.set(ListEditorCursor::Edit(idx-1));
self.data.get_mut(idx-1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End)));
} else {
cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home)));
}
}
TerminalEvent::Input(Event::Key(Key::End)) => {
if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Edit(idx+1));
self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(event);
} else if idx+1 == self.data.len() {
cur_edit.handle_terminal_event(event);
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) |
TerminalEvent::Input(Event::Key(Key::Right)) => {
if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Edit(idx+1));
self.data.get_mut(idx+1).write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Home)));
} else if idx+1 == self.data.len() {
cur_edit.handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::End)));
}
}
_ => {}
}
}
TerminalEditorResult::Continue => {}
}
}
}
}
}
TerminalEditorResult::Continue
}
}
enum ListEditorViewSegment {
InsertCursor,
View(OuterViewPort<dyn TerminalView>),
Select(OuterViewPort<dyn TerminalView>),
Edit(OuterViewPort<dyn TerminalView>)
}
struct ListEditorView {
cursor: Arc<dyn SingletonView<Item = ListEditorCursor>>,
data: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
cur_cursor: ListEditorCursor,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = ListEditorViewSegment>>>>,
proj_helper: ProjectionHelper<Self>
}
impl View for ListEditorView {
type Msg = usize;
}
impl SequenceView for ListEditorView {
type Item = ListEditorViewSegment;
fn len(&self) -> Option<usize> {
match self.cur_cursor {
ListEditorCursor::None => self.data.len(),
ListEditorCursor::Select(_) => self.data.len(),
ListEditorCursor::Edit(_) => self.data.len(),
ListEditorCursor::Insert(_) => Some(self.data.len()? + 1)
}
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
Some(
match self.cur_cursor {
ListEditorCursor::None =>
ListEditorViewSegment::View(self.data.get(idx)?),
ListEditorCursor::Select(c) =>
if *idx == c {
ListEditorViewSegment::Select(self.data.get(idx)?)
} else {
ListEditorViewSegment::View(self.data.get(idx)?)
},
ListEditorCursor::Edit(c) =>
if *idx == c {
ListEditorViewSegment::Edit(self.data.get(idx)?)
} else {
ListEditorViewSegment::View(self.data.get(idx)?)
},
ListEditorCursor::Insert(c) =>
if *idx < c {
ListEditorViewSegment::View(self.data.get(idx)?)
} else if *idx == c {
ListEditorViewSegment::InsertCursor
} else {
ListEditorViewSegment::View(self.data.get(&(idx-1))?)
},
}
)
}
}
impl ListEditorView {
fn new(
cursor_port: OuterViewPort<dyn SingletonView<Item = ListEditorCursor>>,
data_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
out_port: InnerViewPort<dyn SequenceView<Item = ListEditorViewSegment>>
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let proj = Arc::new(RwLock::new(
ListEditorView {
cur_cursor: ListEditorCursor::None,
cursor: proj_helper.new_singleton_arg(
cursor_port,
|s: &mut Self, _msg| {
let old_cursor = s.cur_cursor;
let new_cursor = s.cursor.get();
s.cur_cursor = new_cursor;
let mut begin = std::cmp::min(
match old_cursor {
ListEditorCursor::None => usize::MAX,
ListEditorCursor::Select(c) => c,
ListEditorCursor::Insert(c) => c,
ListEditorCursor::Edit(c) => c
},
match new_cursor {
ListEditorCursor::None => usize::MAX,
ListEditorCursor::Select(c) => c,
ListEditorCursor::Insert(c) => c,
ListEditorCursor::Edit(c) => c
}
);
let mut end =
/*
match (old_cursor, new_cursor) {
(ListEditorCursor::None, ListEditorCursor::None) => usize::MAX,
(ListEditorCursor::Select(old_pos), ListEditorCursor::Select(new_pos)) => max(old_pos, new_pos),
(ListEditorCursor::Edit(old_pos), ListEditorCursor::Edit(new_pos)) => max(old_pos, new_pos),
(ListEditorCursor::Insert(old_pos), ListEditorCursor::Insert(new_pos)) => max(old_pos, new_pos),
(ListEditorCursor::)
};
*/
std::cmp::max(
match old_cursor {
ListEditorCursor::None => 0,
ListEditorCursor::Select(c) => c,
ListEditorCursor::Insert(c) => c+1,
ListEditorCursor::Edit(c) => c
},
match new_cursor {
ListEditorCursor::None => 0,
ListEditorCursor::Select(c) => c,
ListEditorCursor::Insert(c) => c+1,
ListEditorCursor::Edit(c) => c
}
);
s.cast.notify_each(
begin ..= end
);
}),
data: proj_helper.new_sequence_arg(
data_port,
|s: &mut Self, idx| {
match s.cur_cursor {
ListEditorCursor::None => s.cast.notify(idx),
ListEditorCursor::Select(c) => s.cast.notify(idx),
ListEditorCursor::Edit(c) => s.cast.notify(idx),
ListEditorCursor::Insert(c) =>
if *idx < c {
s.cast.notify(idx)
} else {
s.cast.notify(&(*idx + 1))
}
}
}),
cast: out_port.get_broadcast(),
proj_helper
}
));
proj.write().unwrap().proj_helper.set_proj(&proj);
out_port.set_view(Some(proj.clone()));
proj
}
}
impl<SubEditor, FnMakeItemEditor> ListEditor<SubEditor, FnMakeItemEditor>
where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
{
pub fn new(make_item_editor: FnMakeItemEditor) -> Self {
let cursor_port = ViewPort::new();
let data_port = ViewPort::new();
let mut cursor = SingletonBuffer::new(ListEditorCursor::Insert(0), cursor_port.inner());
let mut data = VecBuffer::<Arc<RwLock<SubEditor>>>::new(data_port.inner());
let data_sequence_port = data_port.into_outer().to_sequence();
let segment_view_port = ViewPort::<dyn SequenceView<Item = ListEditorViewSegment>>::new();
let segment_view = ListEditorView::new(
cursor_port.outer(),
data_sequence_port.map(|ed| ed.read().unwrap().get_term_view()),
segment_view_port.inner()
);
ListEditor {
data,
data_sequence_port,
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()
}
)
}
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = Arc<RwLock<SubEditor>>>> {
self.data_sequence_port.clone()
}
}

7
nested/src/list/mod.rs Normal file
View file

@ -0,0 +1,7 @@
pub mod editor;
pub mod sexpr;
pub use editor::ListEditor;
pub use sexpr::SExprView;

283
nested/src/list/sexpr.rs Normal file
View file

@ -0,0 +1,283 @@
use {
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
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ListDecorator {
opening_port: OuterViewPort<dyn TerminalView>,
closing_port: OuterViewPort<dyn TerminalView>,
delim_port: OuterViewPort<dyn TerminalView>,
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>>>,
proj_helper: ProjectionHelper<Self>
}
impl View for ListDecorator {
type Msg = usize;
}
impl SequenceView for ListDecorator {
type Item = OuterViewPort<dyn TerminalView>;
fn len(&self) -> Option<usize> {
let l = self.items.len()?;
Some(if l == 0 { 2 } else { 2*l + 2 })
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let item_idx = idx / 2;
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))
}
)
}
}
impl ListDecorator {
pub fn new(
opening: &str,
closing: &str,
delim: &str,
level: usize,
items_port: OuterViewPort<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)
}
),
cast: out_port.get_broadcast(),
proj_helper
}));
li.write().unwrap().proj_helper.set_proj(&li);
out_port.set_view(Some(li.clone()));
li
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use crate::{index::IndexView, grid::GridView};
pub struct VerticalSexprDecorator {
opening_port: OuterViewPort<dyn TerminalView>,
closing_port: OuterViewPort<dyn TerminalView>,
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = OuterViewPort<dyn TerminalView>>>>>,
proj_helper: ProjectionHelper<Self>
}
impl View for VerticalSexprDecorator {
type Msg = Point2<i16>;
}
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<_>>();
area.push(Point2::new(0, 0));
area.push(Point2::new(2, self.items.len()? as i16 - 1));
Some(area)
}
fn get(&self, pt: &Point2<i16>) -> Option<Self::Item> {
let item_idx = pt.y as usize;
let list_style = self.list_style.clone();
let item_style = self.item_style.clone();
let l = self.items.len().unwrap_or(0);
match pt.x {
0 => {
if pt.y == 0 {
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)))
} 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)))
} else {
None
}
}
_ => None
}
}
}
impl VerticalSexprDecorator {
pub fn new(
opening: &str,
closing: &str,
level: usize,
items_port: OuterViewPort<dyn SequenceView<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)
}
),
cast: out_port.get_broadcast(),
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>;
fn vertical_sexpr_view(&self, level: usize) -> OuterViewPort<dyn TerminalView>;
}
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()
);
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()
);
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()
}
}

View file

@ -1,167 +0,0 @@
use {
std::sync::Arc,
std::sync::RwLock,
nested::{
core::{
View,
ViewPort,
OuterViewPort,
InnerViewPort,
Observer,
ObserverBroadcast
},
sequence::{SequenceView, VecBuffer},
terminal::{Terminal, TerminalAtom, TerminalStyle},
projection::ProjectionHelper
}
};
pub struct ListDecorator {
opening_port: OuterViewPort<dyn SequenceView<Item = char>>,
closing_port: OuterViewPort<dyn SequenceView<Item = char>>,
delim_port: OuterViewPort<dyn SequenceView<Item = char>>,
items: Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>>>,
proj_helper: ProjectionHelper<Self>
}
impl View for ListDecorator {
type Msg = usize;
}
impl SequenceView for ListDecorator {
type Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>;
fn len(&self) -> Option<usize> {
Some(self.items.len()? * 2 + 1)
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let item_idx = idx / 2;
let list_style = self.list_style.clone();
let item_style = self.item_style.clone();
Some(
if idx % 2 == 0 {
if item_idx == 0 {
self.opening_port.clone()
} else if item_idx == self.items.len().unwrap_or(0) {
self.closing_port.clone()
} else {
self.delim_port.clone()
}
.map(move |c| TerminalAtom::new(*c, list_style))
} else {
self.items
.get(&item_idx)?
.map(move |atom| atom.add_style_back(item_style))
}
)
}
}
impl ListDecorator {
pub fn new(
opening_port: OuterViewPort<dyn SequenceView<Item = char>>,
closing_port: OuterViewPort<dyn SequenceView<Item = char>>,
delim_port: OuterViewPort<dyn SequenceView<Item = char>>,
items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>,
list_style: TerminalStyle,
item_style: TerminalStyle,
out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let li = Arc::new(RwLock::new(ListDecorator {
opening_port,
closing_port,
delim_port,
items: proj_helper.new_sequence_arg(
items_port,
|s: &mut Self, item_idx| {
s.cast.notify(&(item_idx * 2));
s.cast.notify(&(item_idx * 2 + 1));
}
),
list_style,
item_style,
cast: out_port.get_broadcast(),
proj_helper
}));
out_port.set_view(Some(li.clone()));
li
}
pub fn lisp_style(
level: usize,
items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>,
out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>
) -> Arc<RwLock<Self>> {
let opening_port = ViewPort::new();
let opening = VecBuffer::<char>::with_data("(".chars().collect(), opening_port.inner());
let closing_port = ViewPort::new();
let closing = VecBuffer::<char>::with_data(")".chars().collect(), closing_port.inner());
let delim_port = ViewPort::new();
let delim = VecBuffer::<char>::with_data(" ".chars().collect(), delim_port.inner());
Self::new(
opening_port.outer().to_sequence(),
closing_port.outer().to_sequence(),
delim_port.outer().to_sequence(),
items_port,
TerminalStyle::fg_color(
match level {
0 => (200, 120, 10),
1 => (120, 200, 10),
_ => (255, 255, 255)
}
),
TerminalStyle::fg_color(
match level {
_ => (255, 255, 255)
}
),
out_port
)
}
pub fn c_style(
level: usize,
items_port: OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>,
out_port: InnerViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = TerminalAtom>>>>
) -> Arc<RwLock<Self>> {
let opening_port = ViewPort::new();
let opening = VecBuffer::<char>::with_data("{".chars().collect(), opening_port.inner());
let closing_port = ViewPort::new();
let closing = VecBuffer::<char>::with_data("}".chars().collect(), closing_port.inner());
let delim_port = ViewPort::new();
let delim = VecBuffer::<char>::with_data(", ".chars().collect(), delim_port.inner());
Self::new(
opening_port.outer().to_sequence(),
closing_port.outer().to_sequence(),
delim_port.outer().to_sequence(),
items_port,
TerminalStyle::fg_color(
match level {
_ => (255, 255, 255)
}
),
TerminalStyle::fg_color(
match level {
_ => (255, 255, 255)
}
),
out_port
)
}
}

View file

@ -1,30 +1,53 @@
use {
std::sync::RwLock,
cgmath::Point2,
//mod monstera;
use{
std::sync::{Arc, RwLock},
cgmath::{Point2, Vector2},
termion::event::{Event, Key},
nested::{
core::{
View,
ViewPort,
OuterViewPort,
context::{
ReprTree,
Object,
MorphismType,
MorphismMode,
Context
},
port::{
UpdateTask
}
},
sequence::{SequenceView, VecBuffer},
Observer,
ObserverExt,
context::{ReprTree, Object, MorphismType, MorphismMode, Context},
port::{UpdateTask}},
index::{IndexView},
sequence::{SequenceView},
vec::{VecBuffer},
integer::{RadixProjection},
terminal::{Terminal, TerminalAtom, TerminalStyle, TerminalCompositor, TerminalEvent},
string_editor::StringEditor
terminal::{
Terminal,
TerminalStyle,
TerminalAtom,
TerminalCompositor,
TerminalEvent,
make_label,
TerminalView,
TerminalEditor},
string_editor::StringEditor,
list::{SExprView, ListEditor}
}
};
pub mod list;
struct GridFill<T: Send + Sync + Clone>(T);
impl<T: Send + Sync + Clone> View for GridFill<T> {
type Msg = Point2<i16>;
}
impl<T: Send + Sync + Clone> IndexView<Point2<i16>> for GridFill<T> {
type Item = T;
fn area(&self) -> Option<Vec<Point2<i16>>> {
None
}
fn get(&self, _: &Point2<i16>) -> Option<T> {
Some(self.0.clone())
}
}
#[async_std::main]
async fn main() {
@ -58,25 +81,27 @@ write::
*/
let mut args = std::env::args();
/*
let arg0_port = ViewPort::new();
let _arg0 = VecBuffer::<char>::with_data(
args.next().expect("Arg $0 missing!")
.chars().collect::<Vec<char>>(),
arg0_port.inner()
);
/*
*/
let arg1_vec_port = ViewPort::new();
let mut arg1 = VecBuffer::<char>::with_data(
vec!['1'],
/*
args.next().expect("Arg $1 missing!")
.chars().collect::<Vec<char>>(),
*/
arg1_vec_port.inner()
);
*/
let arg1_vec = args.next().expect("Arg $1 missing!")
/*
let _arg1_vec = args.next().expect("Arg $1 missing!")
.chars().collect::<Vec<char>>();
*/
let term_port = ViewPort::new();
let compositor = TerminalCompositor::new(term_port.inner());
@ -171,7 +196,7 @@ write::
})
);
*/
let arg1_vec_port = ed.get_data_port();
ctx.add_obj("$1".into(), "( Vec UnicodeChar )");
@ -247,202 +272,242 @@ write::
arg1_hex_unic_port.clone().into()
);
compositor.write().unwrap().push(
ed.insert_view()
.map_key(
|pt| Point2::new(40 as i16 - pt.x, 1 as i16),
|pt| if pt.y == 1 { Some(Point2::new(40 as i16 - pt.x, 0)) } else { None }
)
let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
.map_item(
|_pos, atom|
TerminalAtom::new(
atom.c.unwrap_or(' '),
|pos, atom|
atom.add_style_back(
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)
}
(5,
((80+(pos.x*30)%100) as u8),
(55+(pos.x*15)%180) as u8)
)
)
)
);
let opening_port = ViewPort::new();
let opening = VecBuffer::<char>::with_data("]".chars().collect(), opening_port.inner());
let dec_label_port = ViewPort::new();
let dec_label = VecBuffer::<char>::with_data("d0".chars().collect(), dec_label_port.inner());
let hex_label_port = ViewPort::new();
let hex_label = VecBuffer::<char>::with_data("x0".chars().collect(), hex_label_port.inner());
let delim_port = ViewPort::new();
let delim = VecBuffer::<char>::with_data(",".chars().collect(), delim_port.inner());
let closing_port = ViewPort::new();
let closing = VecBuffer::<char>::with_data("[".chars().collect(), closing_port.inner());
for c in arg1_vec {
ed.insert(c);
ed.prev();
}
);
{
let tree_port = ViewPort::new();
let mut tree = VecBuffer::with_data(
vec![
opening_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))),
arg1_dec_mint_port
.map(|val| char::from_digit(*val as u32, 16).unwrap())
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((255, 255, 255)))),
dec_label_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 170)))),
delim_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))),
arg1_hex_unic_port.clone()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((255, 255, 255)))),
hex_label_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 170)))),
closing_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((170, 170, 30)))),
],
tree_port.inner()
);
compositor.write().unwrap().push(
tree_port.outer()
.to_sequence()
.flatten()
.to_index()
.map_key(
|idx| Point2::new(40 - *idx as i16, 2 as i16),
|pt| if pt.y == 2 { Some(40 - pt.x as usize) } else { None }
)
);
compositor.write().unwrap().push(magic.offset(Vector2::new(40, 4)));
//compositor.write().unwrap().push(magic.offset(Vector2::new(40, 20)));
/*
let monstera_port = monstera::make_monstera();
compositor.write().unwrap().push(monstera_port.clone());
compositor.write().unwrap().push(monstera_port.offset(Vector2::new(83,0)));
*/
}
/*
// list views
{
let items_port = ViewPort::new();
let items = VecBuffer::with_data(
vec![
arg1_dec_mint_port
.map(|val| char::from_digit(*val as u32, 16).unwrap())
.map(|c| TerminalAtom::from(c)),
arg1_hex_unic_port.clone()
.map(|c| TerminalAtom::from(c)),
.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)),
.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 liport = ViewPort::new();
let list_decorator = list::ListDecorator::lisp_style(
1,
items_port.outer().to_sequence(),
liport.inner()
);
let par_items_port = ViewPort::new();
let par_items = VecBuffer::with_data(
vec![
liport.outer().flatten(),
items_port.outer().to_sequence().sexpr_view(1),
arg1_hex_unic_port.clone()
.map(|c| TerminalAtom::from(c)),
.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()
);
let par_liport = ViewPort::new();
let par_list_decorator = list::ListDecorator::lisp_style(
0,
par_items_port.outer().to_sequence(),
par_liport.inner()
);
compositor.write().unwrap().push(
par_liport.outer()
.flatten()
.to_index()
.map_key(
|idx| Point2::new(*idx as i16, 3),
|pt| if pt.y == 3 { Some(pt.x as usize) } else { None }
)
par_items_port.outer()
.to_sequence()
.sexpr_view(0)
.offset(Vector2::new(45, 5))
);
}
let magic_vec_port = ViewPort::new();
let _magic_vec = VecBuffer::with_data("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>".chars().collect::<Vec<char>>(), magic_vec_port.inner());
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());
/*
compositor.write().unwrap().push(
history_port.into_outer()
.to_sequence()
.map(
|
)
.to_grid_vertical()
.flatten()
.offset(Vector2::new(45, 5))
);
*/
};
let mut y = 5;
// TypeEditor
let make_sub_editor = || {
std::sync::Arc::new(std::sync::RwLock::new(StringEditor::new()))
};
let mut te = ListEditor::new(make_sub_editor.clone());
compositor.write().unwrap().push(
magic_vec_port.outer()
.to_sequence()
.to_index()
.map_item(
|idx, c| TerminalAtom::new(
*c,
TerminalStyle::fg_color((5, ((80+(idx*30)%100) as u8), (55+(idx*15)%180) as u8))
)
)
.map_key(
|idx| Point2::new(*idx as i16, 4),
|pt| if pt.y == 4 { Some(pt.x as usize) } else { None }
)
te.segment_seq.horizontal_sexpr_view(0).offset(cgmath::Vector2::new(40,y))
);
y += 1;
compositor.write().unwrap().push(
magic_vec_port.outer()
.to_sequence()
.to_index()
.map_item(
|idx, c| TerminalAtom::new(
*c,
TerminalStyle::fg_color((5, ((80+(idx*30)%100) as u8), (55+(idx*15)%180) as u8))
)
)
.map_key(
|idx| Point2::new(*idx as i16, 0),
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None }
)
);
term_port.update();
let mut p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
loop {
term_port.update();
match term.next_event().await {
TerminalEvent::Input(Event::Key(Key::Left)) => ed.next(),
TerminalEvent::Input(Event::Key(Key::Right)) => ed.prev(),
TerminalEvent::Input(Event::Key(Key::Home)) => ed.goto_end(),
TerminalEvent::Input(Event::Key(Key::End)) => ed.goto(0),
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {},
TerminalEvent::Input(Event::Key(Key::Char(c))) => { ed.insert(c); ed.prev(); },
TerminalEvent::Input(Event::Key(Key::Delete)) => ed.delete_prev(),
TerminalEvent::Input(Event::Key(Key::Backspace)) => ed.delete(),
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break,
TerminalEvent::Resize(new_size) => {
cur_size.set(new_size);
term_port.inner().get_broadcast().notify_each(
nested::grid::GridWindowIterator::from(
Point2::new(0,0) .. Point2::new(new_size.x, new_size.y)
)
);
}
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) |
TerminalEvent::Input(Event::Key(Key::Ctrl('g'))) |
TerminalEvent::Input(Event::Key(Key::Ctrl('d'))) => break,
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
let mut strings = Vec::new();
let v = p.get_view().unwrap();
for i in 0 .. v.len().unwrap_or(0) {
strings.push(
v
.get(&i).unwrap()
.get_view().unwrap()
.read().unwrap()
.iter().collect::<String>()
);
}
if strings.len() == 0 { continue; }
if let Ok(output) =
std::process::Command::new(strings[0].as_str())
.args(&strings[1..])
.output()
{
// take output and update terminal view
let mut line_port = ViewPort::new();
let mut line = VecBuffer::new(line_port.inner());
for byte in output.stdout {
match byte {
b'\n' => {
compositor.write().unwrap().push(
line_port.outer()
.to_sequence()
.map(|c| TerminalAtom::new(*c, TerminalStyle::fg_color((130,90,90))))
.to_grid_horizontal()
.offset(Vector2::new(45, y))
);
y += 1;
line_port = ViewPort::new();
line = VecBuffer::new(line_port.inner());
}
byte => {
line.push(byte as char);
}
}
}
} else {
compositor.write().unwrap().push(
make_label("Command not found")
.map_item(|idx, a| a.add_style_back(TerminalStyle::fg_color((200,0,0))))
.offset(Vector2::new(45, y))
);
y+=1;
}
te.handle_terminal_event(
&TerminalEvent::Input(Event::Key(Key::Up))
);
te.handle_terminal_event(
&TerminalEvent::Input(Event::Key(Key::Home))
);
te = ListEditor::new(make_sub_editor.clone());
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))
);
y += 1;
p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
},
ev => {
te.handle_terminal_event(&ev);
}
_ => {}
}
term_port.update();
}
drop(term);
//drop(term);
}
);