build StringEditor and PosIntEditor ontop of ListEditor

add DigitEditor and CharEditor
This commit is contained in:
Michael Sippel 2021-08-16 01:27:35 +02:00
parent fef4b930ae
commit 9905a2376f
Signed by: senvas
GPG key ID: F96CF119C34B64A6
7 changed files with 301 additions and 483 deletions

View file

@ -0,0 +1,76 @@
use {
std::sync::RwLock,
termion::event::{Key, Event},
crate::{
core::{ViewPort, OuterViewPort},
singleton::{SingletonView, SingletonBuffer},
vec::VecBuffer,
terminal::{TerminalAtom, TerminalStyle, TerminalView, TerminalEvent, TerminalEditor, TerminalEditorResult},
tree_nav::{TreeNav, TreeNavResult}
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct DigitEditor {
radix: u32,
data: SingletonBuffer<Option<char>>,
data_port: ViewPort<dyn SingletonView<Item = Option<char>>>
}
impl DigitEditor {
pub fn new(radix: u32) -> Self {
let mut data_port = ViewPort::new();
DigitEditor {
radix,
data: SingletonBuffer::new(None, data_port.inner()),
data_port
}
}
pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<u32>>> {
let radix = self.radix;
self.data_port.outer().map(
move |c| c.unwrap_or('?').to_digit(radix)
)
}
}
impl TreeNav for DigitEditor {}
impl TerminalEditor for DigitEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
let radix = self.radix;
self.data_port.outer().map(
move |c| TerminalAtom::new(
c.unwrap_or('?'),
if c.unwrap_or('?').to_digit(radix).is_some() {
TerminalStyle::fg_color((100, 140, 100))
} else {
TerminalStyle::fg_color((200, 0, 0))
}
)
).to_grid()
}
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) =>
TerminalEditorResult::Continue,
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
self.data.set(Some(*c));
TerminalEditorResult::Exit
}
TerminalEvent::Input(Event::Key(Key::Backspace)) |
TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.set(None);
TerminalEditorResult::Exit
}
_ => TerminalEditorResult::Continue
}
}
}
struct PosIntEditor {
}

View file

@ -1,9 +1,11 @@
pub mod radix; pub mod radix;
pub mod add; pub mod add;
pub mod digit;
pub use { pub use {
radix::RadixProjection, radix::RadixProjection,
add::Add add::Add,
digit::DigitEditor
}; };

View file

@ -31,7 +31,6 @@ use {
TerminalEditorResult, TerminalEditorResult,
make_label make_label
}, },
string_editor::StringEditor,
leveled_term_view::LeveledTermView, leveled_term_view::LeveledTermView,
list::{SExprView, ListDecoration} list::{SExprView, ListDecoration}
} }
@ -145,10 +144,29 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
fn goto_end(&mut self) -> TreeNavResult { fn goto_end(&mut self) -> TreeNavResult {
match self.cursor.get() { match self.cursor.get() {
ListEditorCursor::None | ListEditorCursor::None => { self.goto(vec![ self.data.len() - 1 ])}
ListEditorCursor::Insert(_) | ListEditorCursor::Insert(idx) => {
ListEditorCursor::Select(_) => if idx < self.data.len() {
self.goto(vec![ self.data.len()-1 ]), self.goto(vec![ self.data.len() ])
} else {
self.up();
self.nexd();
self.dn();
self.goto_end();
TreeNavResult::Continue
}
}
ListEditorCursor::Select(idx) => {
if idx < self.data.len()-1 {
self.goto(vec![ self.data.len()-1 ])
} else {
self.up();
self.nexd();
self.dn();
self.goto_end();
TreeNavResult::Continue
}
}
ListEditorCursor::Edit(idx) => { ListEditorCursor::Edit(idx) => {
let ce = self.data.get_mut(idx); let ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap(); let mut cur_edit = ce.write().unwrap();
@ -157,8 +175,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
TreeNavResult::Continue => TreeNavResult::Continue, TreeNavResult::Continue => TreeNavResult::Continue,
TreeNavResult::Exit => { TreeNavResult::Exit => {
if idx+1 < self.data.len() { if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Edit(idx+1)); drop(cur_edit);
self.data.get_mut(idx+1).write().unwrap().goto_end(); self.up();
self.nexd();
self.dn();
self.goto_end();
TreeNavResult::Continue TreeNavResult::Continue
} else { } else {
self.cursor.set(ListEditorCursor::None); self.cursor.set(ListEditorCursor::None);
@ -183,8 +204,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
TreeNavResult::Continue => TreeNavResult::Continue, TreeNavResult::Continue => TreeNavResult::Continue,
TreeNavResult::Exit => { TreeNavResult::Exit => {
if idx > 0 { if idx > 0 {
self.cursor.set(ListEditorCursor::Edit(idx-1)); drop(cur_edit);
self.data.get_mut(idx-1).write().unwrap().goto_home(); self.up();
self.pxev();
self.dn();
self.goto_home();
TreeNavResult::Continue TreeNavResult::Continue
} else { } else {
self.cursor.set(ListEditorCursor::None); self.cursor.set(ListEditorCursor::None);
@ -206,6 +230,12 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
self.data.get_mut(idx).write().unwrap().goto_home(); self.data.get_mut(idx).write().unwrap().goto_home();
self.cursor.set(ListEditorCursor::Edit(idx)); self.cursor.set(ListEditorCursor::Edit(idx));
} }
ListEditorCursor::Edit(idx) => {
let ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap();
cur_edit.dn();
}
_ => {} _ => {}
} }
TreeNavResult::Continue TreeNavResult::Continue
@ -239,8 +269,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
match cur_edit.pxev() { match cur_edit.pxev() {
TreeNavResult::Exit => { TreeNavResult::Exit => {
if idx > 0 { if idx > 0 {
self.cursor.set(ListEditorCursor::Edit(idx-1)); drop(cur_edit);
self.data.get_mut(idx-1).write().unwrap().goto_end(); self.up();
self.pxev();
self.dn();
self.goto_end();
TreeNavResult::Continue TreeNavResult::Continue
} else { } else {
TreeNavResult::Exit TreeNavResult::Exit
@ -268,6 +301,7 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
self.cursor.set(ListEditorCursor::Select(idx + 1)); self.cursor.set(ListEditorCursor::Select(idx + 1));
TreeNavResult::Continue TreeNavResult::Continue
} else { } else {
self.cursor.set(ListEditorCursor::None);
TreeNavResult::Exit TreeNavResult::Exit
} }
} }
@ -278,8 +312,10 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
match cur_edit.nexd() { match cur_edit.nexd() {
TreeNavResult::Exit => { TreeNavResult::Exit => {
if idx+1 < self.data.len() { if idx+1 < self.data.len() {
self.cursor.set(ListEditorCursor::Edit(idx+1)); drop(cur_edit);
self.data.get_mut(idx+1).write().unwrap().goto_home(); self.up();
self.nexd();
self.dn();
TreeNavResult::Continue TreeNavResult::Continue
} else {//if idx+1 == self.data.len() { } else {//if idx+1 == self.data.len() {
TreeNavResult::Exit TreeNavResult::Exit
@ -297,42 +333,74 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>> FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
{ {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> { fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.horizontal_sexpr_view() self.terminal_view.clone()
} }
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match self.cursor.get() { match self.cursor.get() {
ListEditorCursor::Insert(idx) => { ListEditorCursor::Insert(idx) => {
self.data.insert(idx, (self.make_item_editor)()); match event {
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
if idx > 0 {
self.data.remove(idx-1);
self.cursor.set(ListEditorCursor::Insert(idx-1));
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Delete)) => {
if idx < self.data.len() {
self.data.remove(idx);
self.cursor.set(ListEditorCursor::Insert(idx));
TerminalEditorResult::Continue
} else {
TerminalEditorResult::Exit
}
}
TerminalEvent::Input(Event::Key(Key::Insert)) => {
let l = self.data.len();
if idx < l {
self.cursor.set(ListEditorCursor::Select(idx));
} else {
self.cursor.set(ListEditorCursor::Select(l-1))
}
TerminalEditorResult::Continue
}
_ => {
let mut ce = self.data.get_mut(idx); let new_edit = (self.make_item_editor)();
let mut cur_edit = ce.write().unwrap(); self.data.insert(idx, new_edit.clone());
cur_edit.goto_home(); new_edit.write().unwrap().goto_home();
self.cursor.set(ListEditorCursor::Edit(idx)); self.cursor.set(ListEditorCursor::Edit(idx));
cur_edit.handle_terminal_event(event); match new_edit.write().unwrap().handle_terminal_event(event) {
TerminalEditorResult::Exit => {
self.cursor.set(ListEditorCursor::Insert(idx+1));
}
_ => {}
}
TerminalEditorResult::Continue
}
}
} }
ListEditorCursor::Edit(idx) => { ListEditorCursor::Edit(idx) => {
let mut ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap();
match event { match event {
TerminalEvent::Input(Event::Key(Key::Char(' '))) => { TerminalEvent::Input(Event::Key(Key::Char(' '))) => {
// split.. // split..
self.data.insert(idx+1, (self.make_item_editor)()); cur_edit.up();
self.data.get_mut(idx).write().unwrap().goto_end(); self.cursor.set(ListEditorCursor::Insert(idx+1));
self.data.get_mut(idx+1).write().unwrap().goto_home(); TerminalEditorResult::Continue
self.cursor.set(ListEditorCursor::Edit(idx+1));
}
event => {
let mut ce = self.data.get_mut(idx);
let mut cur_edit = ce.write().unwrap();
cur_edit.handle_terminal_event(event);
} }
_ => cur_edit.handle_terminal_event(event)
} }
} }
ListEditorCursor::Select(idx) => { ListEditorCursor::Select(idx) => {
match event { match event {
TerminalEvent::Input(Event::Key(Key::Insert)) => { TerminalEvent::Input(Event::Key(Key::Insert)) => {
self.cursor.set(ListEditorCursor::Insert(idx));
} }
TerminalEvent::Input(Event::Key(Key::Delete)) => { TerminalEvent::Input(Event::Key(Key::Delete)) => {
self.data.remove(idx); self.data.remove(idx);
@ -345,12 +413,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
} }
_=>{} _=>{}
} }
}
_ => {}
}
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
_ => TerminalEditorResult::Continue
}
}
} }
enum ListEditorViewSegment { enum ListEditorViewSegment {
@ -472,7 +539,7 @@ impl ListEditorView {
); );
s.cast.notify_each( s.cast.notify_each(
begin ..= end 0 ..= s.data.len().unwrap_or(0)+1
); );
}), }),
data: proj_helper.new_sequence_arg( data: proj_helper.new_sequence_arg(
@ -502,11 +569,19 @@ impl ListEditorView {
} }
} }
pub enum ListEditorStyle {
HorizontalSexpr,
VerticalSexpr,
Path,
String,
Clist,
Hex
}
impl<SubEditor, FnMakeItemEditor> ListEditor<SubEditor, FnMakeItemEditor> impl<SubEditor, FnMakeItemEditor> ListEditor<SubEditor, FnMakeItemEditor>
where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static, where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>> FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
{ {
pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> { pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
self.segment_seq self.segment_seq
.map( .map(
@ -538,9 +613,11 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> { pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view().horizontal_sexpr_view(0) self.get_seg_seq_view().horizontal_sexpr_view(0)
} }
pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> { pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view().vertical_sexpr_view(0) self.get_seg_seq_view().vertical_sexpr_view(0)
} }
pub fn path_view(&self) -> OuterViewPort<dyn TerminalView> { pub fn path_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view() self.get_seg_seq_view()
.decorate("<", ">", "/", 0) .decorate("<", ">", "/", 0)
@ -553,8 +630,21 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
.to_grid_horizontal() .to_grid_horizontal()
.flatten() .flatten()
} }
pub fn clist_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("{", "}", ", ", 1)
.to_grid_horizontal()
.flatten()
}
pub fn new(make_item_editor: FnMakeItemEditor) -> Self { pub fn hex_view(&self) -> OuterViewPort<dyn TerminalView> {
self.get_seg_seq_view()
.decorate("0x", "", "", 0)
.to_grid_horizontal()
.flatten()
}
pub fn new(make_item_editor: FnMakeItemEditor, style: ListEditorStyle) -> Self {
let cursor_port = ViewPort::new(); let cursor_port = ViewPort::new();
let data_port = ViewPort::new(); let data_port = ViewPort::new();
@ -570,13 +660,27 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
segment_view_port.inner() segment_view_port.inner()
); );
ListEditor { let mut le = ListEditor {
data, data,
data_sequence_port, data_sequence_port,
cursor, cursor,
make_item_editor, make_item_editor,
level: 0, level: 0,
segment_seq: segment_view_port.outer() segment_seq: segment_view_port.outer(),
terminal_view: make_label("lol"),
};
le.set_style(style);
le
}
pub fn set_style(&mut self, style: ListEditorStyle) {
self.terminal_view = match style {
ListEditorStyle::HorizontalSexpr => self.horizontal_sexpr_view(),
ListEditorStyle::VerticalSexpr => self.vertical_sexpr_view(),
ListEditorStyle::Path => self.path_view(),
ListEditorStyle::String => self.string_view(),
ListEditorStyle::Clist => self.clist_view(),
ListEditorStyle::Hex => self.hex_view()
} }
} }

View file

@ -2,6 +2,6 @@
pub mod editor; pub mod editor;
pub mod sexpr; pub mod sexpr;
pub use editor::ListEditor; pub use editor::{ListEditor, ListEditorStyle};
pub use sexpr::{SExprView, ListDecoration}; pub use sexpr::{SExprView, ListDecoration};

View file

@ -34,7 +34,7 @@ impl SequenceView for ListDecorator {
fn len(&self) -> Option<usize> { fn len(&self) -> Option<usize> {
let l = self.items.len()?; let l = self.items.len()?;
Some(if l == 0 { 2 } else { 2 * l + 2 }) Some(if l == 0 { 2 } else { 2 * l + 1 })
} }
fn get(&self, idx: &usize) -> Option<Self::Item> { fn get(&self, idx: &usize) -> Option<Self::Item> {

View file

@ -12,271 +12,52 @@ use {
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)] pub struct CharEditor {
pub struct StringEditor { data: SingletonBuffer<Option<char>>,
data: VecBuffer<char>, data_port: ViewPort<dyn SingletonView<Item = Option<char>>>
cursor: SingletonBuffer<Option<usize>>,
data_port: ViewPort<RwLock<Vec<char>>>,
cursor_port: ViewPort<dyn SingletonView<Item = Option<usize>>>
} }
impl StringEditor { impl CharEditor {
pub fn new() -> Self { pub fn new() -> Self {
let data_port = ViewPort::new(); let mut data_port = ViewPort::new();
let cursor_port = ViewPort::new(); CharEditor {
data: SingletonBuffer::new(None, data_port.inner()),
StringEditor { data_port
data: VecBuffer::new(data_port.inner()),
cursor: SingletonBuffer::new(None, cursor_port.inner()),
data_port,
cursor_port
} }
} }
pub fn insert_view(&self) -> OuterViewPort<dyn TerminalView> { pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<char>>> {
let port = ViewPort::new();
insert_view::StringInsertView::new(
self.get_cursor_port(),
self.get_data_port().to_sequence(),
port.inner()
);
port.into_outer()
}
pub fn get_data_port(&self) -> OuterViewPort<RwLock<Vec<char>>> {
self.data_port.outer() self.data_port.outer()
} }
pub fn get_cursor_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<usize>>> {
self.cursor_port.outer()
} }
pub fn insert(&mut self, c: char) -> TreeNavResult { impl TreeNav for CharEditor {}
self.data.insert(self.cursor.get().unwrap_or(0), c); impl TerminalEditor for CharEditor {
self.nexd()
}
pub fn delete_prev(&mut self) -> TreeNavResult {
let cur = self.cursor.get().unwrap_or(0);
if cur <= self.data.len() && cur > 0 {
self.data.remove(cur-1);
}
self.pxev()
}
pub fn delete(&mut self) -> TreeNavResult {
let cur = self.cursor.get().unwrap_or(0);
if cur < self.data.len() {
self.data.remove(cur);
TreeNavResult::Continue
} else {
self.cursor.set(None);
TreeNavResult::Exit
}
}
}
impl TreeNav for StringEditor {
fn goto(&mut self, tree_pos: Vec<usize>) -> TreeNavResult {
if tree_pos.len() == 1 {
let new_pos = tree_pos[0];
if new_pos <= self.data.len() {
self.cursor.set(Some(new_pos));
TreeNavResult::Continue
} else {
self.cursor.set(None);
TreeNavResult::Exit
}
} else {
self.cursor.set(None);
TreeNavResult::Exit
}
}
fn pxev(&mut self) -> TreeNavResult {
let cur = self.cursor.get().unwrap_or(usize::MAX);
if cur > 0 {
self.cursor.set(Some(cur - 1));
TreeNavResult::Continue
} else {
self.cursor.set(None);
TreeNavResult::Exit
}
}
fn nexd(&mut self) -> TreeNavResult {
self.goto(vec![ self.cursor.get().unwrap_or(0) + 1 ])
}
fn goto_end(&mut self) -> TreeNavResult {
if self.cursor.get() == Some(self.data.len()) {
self.up()
} else {
self.goto(vec![ self.data.len() ])
}
}
fn goto_home(&mut self) -> TreeNavResult {
if self.cursor.get() == Some(0) {
self.up()
} else {
self.goto(vec![ 0 ])
}
}
fn up(&mut self) -> TreeNavResult {
self.cursor.set(None);
TreeNavResult::Exit
}
fn dn(&mut self) -> TreeNavResult {
if self.cursor.get() == Some(0) {
self.up()
} else {
self.goto(vec![0])
}
}
}
impl TerminalEditor for StringEditor {
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> { fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
self.insert_view() crate::terminal::make_label(
&if let Some(c) = self.data.get() {
c.to_string()
} else {
"".to_string()
})
} }
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event { match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Continue, TerminalEvent::Input(Event::Key(Key::Char('\n'))) =>
TerminalEvent::Input(Event::Key(Key::Char(c))) => match self.insert(*c) { TerminalEditorResult::Continue,
TreeNavResult::Exit => TerminalEditorResult::Exit, TerminalEvent::Input(Event::Key(Key::Char(c))) => {
TreeNavResult::Continue => TerminalEditorResult::Continue self.data.set(Some(*c));
TerminalEditorResult::Exit
} }
TerminalEvent::Input(Event::Key(Key::Delete)) => match self.delete() { TerminalEvent::Input(Event::Key(Key::Backspace)) |
TreeNavResult::Exit => TerminalEditorResult::Exit, TerminalEvent::Input(Event::Key(Key::Delete)) => {
TreeNavResult::Continue => TerminalEditorResult::Continue self.data.set(None);
} TerminalEditorResult::Exit
TerminalEvent::Input(Event::Key(Key::Backspace)) => match self.delete_prev() {
TreeNavResult::Exit => TerminalEditorResult::Exit,
TreeNavResult::Continue => TerminalEditorResult::Continue
} }
_ => TerminalEditorResult::Continue _ => TerminalEditorResult::Continue
} }
} }
} }
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub mod insert_view {
use {
std::{
sync::Arc,
cmp::{min, max}
},
cgmath::Point2,
std::sync::RwLock,
crate::{
core::{View, Observer, ObserverExt, ObserverBroadcast, OuterViewPort, InnerViewPort},
terminal::{TerminalAtom, TerminalStyle, TerminalView},
grid::{GridWindowIterator},
singleton::{SingletonView},
sequence::{SequenceView},
index::{IndexView},
projection::{ProjectionHelper},
}
};
pub struct StringInsertView {
cursor: Arc<dyn SingletonView<Item = Option<usize>>>,
data: Arc<RwLock<dyn SequenceView<Item = char>>>,
cur_pos: Option<usize>,
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>,
proj_helper: ProjectionHelper<Self>
}
impl View for StringInsertView {
type Msg = Point2<i16>;
}
impl IndexView<Point2<i16>> for StringInsertView {
type Item = TerminalAtom;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
if pos.y == 0 && pos.x >= 0 {
let i = pos.x as usize;
let data = self.data.read().unwrap();
let len = data.len().unwrap_or(0);
if i < len+1 {
return Some(
if i < self.cur_pos.unwrap_or(usize::MAX) {
TerminalAtom::from(data.get(&i)?)
} else if i == self.cur_pos.unwrap_or(usize::MAX) {
TerminalAtom::new('|', TerminalStyle::fg_color((90, 60, 200)))
} else {
TerminalAtom::from(data.get(&(i - 1))?)
}
);
}
}
None
}
fn area(&self) -> Option<Vec<Point2<i16>>> {
Some(GridWindowIterator::from(
Point2::new(0, 0) .. Point2::new(self.data.len()? as i16 + if self.cursor.get().is_some() { 1 } else { 0 }, 1)
).collect())
}
}
impl StringInsertView {
pub fn new(
cursor_port: OuterViewPort<dyn SingletonView<Item = Option<usize>>>,
data_port: OuterViewPort<dyn SequenceView<Item = char>>,
out_port: InnerViewPort<dyn TerminalView>
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let proj = Arc::new(RwLock::new(
StringInsertView {
cursor: proj_helper.new_singleton_arg(
cursor_port,
|s: &mut Self, _msg| {
let old_pos = s.cur_pos.unwrap_or(0);
s.cur_pos = s.cursor.get();
let new_pos = s.cur_pos.unwrap_or(0);
s.cast.notify_each(GridWindowIterator::from(Point2::new(min(old_pos, new_pos) as i16,0) ..= Point2::new(max(old_pos, new_pos) as i16, 0)))
}),
data: proj_helper.new_sequence_arg(
data_port,
|s: &mut Self, idx| {
s.cast.notify(&Point2::new(
if *idx < s.cur_pos.unwrap_or(0) {
*idx as i16
} else {
*idx as i16 + 1
},
0
));
}),
cur_pos: None,
cast: out_port.get_broadcast(),
proj_helper
}
));
proj.write().unwrap().proj_helper.set_proj(&proj);
out_port.set_view(Some(proj.clone()));
proj
}
}
}

View file

@ -17,7 +17,7 @@ use{
index::{IndexView}, index::{IndexView},
sequence::{SequenceView}, sequence::{SequenceView},
vec::{VecBuffer}, vec::{VecBuffer},
integer::{RadixProjection}, integer::{RadixProjection, DigitEditor},
terminal::{ terminal::{
Terminal, Terminal,
TerminalStyle, TerminalStyle,
@ -27,9 +27,9 @@ use{
make_label, make_label,
TerminalView, TerminalView,
TerminalEditor}, TerminalEditor},
string_editor::StringEditor, string_editor::{CharEditor},
tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor}, tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor},
list::{SExprView, ListEditor} list::{SExprView, ListEditor, ListEditorStyle}
} }
}; };
@ -81,197 +81,14 @@ 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!")
.chars().collect::<Vec<char>>();
*/
let term_port = ViewPort::new(); let term_port = ViewPort::new();
let compositor = TerminalCompositor::new(term_port.inner()); let compositor = TerminalCompositor::new(term_port.inner());
let mut ed = StringEditor::new();
let mut term = Terminal::new(term_port.outer()); let mut term = Terminal::new(term_port.outer());
let term_writer = term.get_writer(); let term_writer = term.get_writer();
async_std::task::spawn( async_std::task::spawn(
async move { async move {
let mut ctx = Context::new();
for tn in vec![
"MachineWord", "MachineInt", "MachineSyllab", "Bits",
"Vec", "Stream", "Json",
"Sequence", "UTF-8-String", "UnicodeChar",
"PositionalInt", "Digit", "LittleEndian", "BigEndian",
"DiffStream", ""
] { ctx.add_typename(tn.into()); }
let src_type =
ctx.type_term_from_str("( Vec UnicodeChar )").unwrap();
let dst_type =
ctx.type_term_from_str("( Sequence UnicodeChar )").unwrap();
ctx.add_morphism(
MorphismType {
mode: MorphismMode::Epi,
src_type: src_type.clone(),
dst_type: dst_type.clone()
},
Box::new(move |src| {
assert!(src.type_tag == src_type);
Object {
type_tag: dst_type.clone(),
repr: ReprTree::new_leaf(
src.get_port::<RwLock<Vec<char>>>().unwrap()
.to_sequence()
.into()
)
}
})
);
let src_type = ctx.type_term_from_str("( Sequence UnicodeChar )").unwrap();
let dst_type = ctx.type_term_from_str("( Sequence ( Bits 32 ) )").unwrap();
ctx.add_morphism(
MorphismType {
mode: MorphismMode::Mono,
src_type: src_type.clone(),
dst_type: dst_type.clone()
},
Box::new({
move |src| {
assert!(src.type_tag == src_type);
Object {
type_tag: dst_type.clone(),
repr: ReprTree::new_leaf(
src.get_port::<dyn SequenceView<Item = char>>().unwrap()
.map(
|c| *c as u32
)
.into()
)
}
}
})
);
/*
let src_type = vec![
ctx.type_term_from_str("( PositionalInteger )").unwrap(),
];
let dst_type = ctx.type_term_from_str("( Sequence MachineInt )").unwrap();
ctx.add_morphism(
MorphismType {
mode: MorphismMode::Epi,
src_type: src_type.clone(),
dst_type: dst_type.clone()
},
Box::new({
move |src| {
assert!(src.type_tag == src_type);
Object {
type_tag: dst_type.clone(),
repr: ReprTree::new_leaf(
vec![ dst_type.clone() ].into_iter(),
src.get_port::<RwLock<Vec<usize>>>().unwrap().to_sequence().into()
)
}
}
})
);
*/
let arg1_vec_port = ed.get_data_port();
ctx.add_obj("$1".into(), "( Vec UnicodeChar )");
ctx.insert_repr(
"$1",
vec![].into_iter(),
arg1_vec_port.clone().into()
);
ctx.epi_cast("$1", "( Sequence UnicodeChar )");
ctx.epi_cast("$1", "( Sequence ( Digit 10 ) )");
ctx.epi_cast("$1", "( PositionalInt 10 LittleEndian )");
ctx.epi_cast("$1", "( )");
let arg1_dec_unic_port: OuterViewPort<dyn SequenceView<Item = char>> =
ctx.mono_view(
"$1",
vec![
"( PositionalInt 10 LittleEndian )",
"( Sequence ( Digit 10 ) )",
"( Sequence UnicodeChar )"
].into_iter()
).unwrap();
let arg1_dec_mint_port: OuterViewPort<dyn SequenceView<Item = usize>> =
arg1_dec_unic_port
.map(|c| c.to_digit(10).map(|x| x as usize))
.filter(|d| d.is_some())
.map(|d| d.unwrap());
ctx.insert_repr(
"$1",
vec![
"( PositionalInt 10 LittleEndian )",
"( Sequence ( Digit 10 ) )",
"( Sequence MachineInt )"
].into_iter(),
arg1_dec_mint_port.clone().into()
);
let arg1_hex_mint_port: ViewPort<RwLock<Vec<usize>>>
= ViewPort::new();
let _radix_proj = RadixProjection::new(
10,
16,
arg1_dec_mint_port.clone(),
arg1_hex_mint_port.inner()
);
ctx.insert_repr(
"$1",
vec![
"( PositionalInt 16 LittleEndian )",
"( Sequence ( Digit 16 ) )",
"( Sequence MachineInt )"
].into_iter(),
arg1_hex_mint_port.outer().to_sequence().into()
);
let arg1_hex_unic_port: OuterViewPort<dyn SequenceView<Item = char>> =
arg1_hex_mint_port.outer().to_sequence()
.map(
|d| char::from_digit(*d as u32, 16).unwrap()
);
ctx.insert_repr(
"$1",
vec![
"( PositionalInt 16 LittleEndian )",
"( Sequence ( Digit 16 ) )",
"( Sequence UnicodeChar )"
].into_iter(),
arg1_hex_unic_port.clone().into()
);
let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>") let magic = make_label("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
.map_item( .map_item(
@ -302,19 +119,33 @@ write::
// TypeEditor // TypeEditor
let make_sub_editor = || { let make_char_editor = || {
std::sync::Arc::new(std::sync::RwLock::new(StringEditor::new())) std::sync::Arc::new(std::sync::RwLock::new(DigitEditor::new(16)))
}; };
let mut te = ListEditor::new(make_sub_editor.clone()); let make_sub_editor = move || {
std::sync::Arc::new(std::sync::RwLock::new(ListEditor::new(make_char_editor.clone(), ListEditorStyle::Hex)))
};
let mut te = ListEditor::new(make_sub_editor.clone(), ListEditorStyle::Clist);
compositor.write().unwrap().push( compositor.write().unwrap().push(
te.path_view() te.get_term_view()
.offset(cgmath::Vector2::new(40,y)) .offset(cgmath::Vector2::new(40,y))
); );
y += 1; y += 1;
let mut p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port()); let mut p = te.get_data_port().map(|sub_editor| sub_editor.read().unwrap().get_data_port());
let status_chars_port = ViewPort::new();
let mut status_chars = VecBuffer::new(status_chars_port.inner());
compositor.write().unwrap().push(
status_chars_port.outer()
.to_sequence()
.to_grid_horizontal()
.offset(cgmath::Vector2::new(40, 2))
);
loop { loop {
term_port.update(); term_port.update();
@ -343,10 +174,19 @@ write::
} }
TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); } TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); }
TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); } TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); }
TerminalEvent::Input(Event::Key(Key::Home)) => { te.goto_home(); } TerminalEvent::Input(Event::Key(Key::Home)) => {
TerminalEvent::Input(Event::Key(Key::End)) => { te.goto_end(); } if te.goto_home() == TreeNavResult::Exit {
te.goto_home();
}
}
TerminalEvent::Input(Event::Key(Key::End)) => {
if te.goto_end() == TreeNavResult::Exit {
te.goto_end();
}
}
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
/*
let mut strings = Vec::new(); let mut strings = Vec::new();
let v = p.get_view().unwrap(); let v = p.get_view().unwrap();
@ -412,12 +252,27 @@ write::
y += 1; y += 1;
p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port()); p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
*/
}, },
ev => { ev => {
te.handle_terminal_event(&ev); te.handle_terminal_event(&ev);
} }
_ => {} _ => {}
} }
status_chars.clear();
match te.get_cursor() {
Some(addr) => {
status_chars.push(TerminalAtom::new('@', TerminalStyle::fg_color((120, 80, 80)).add(TerminalStyle::bold(true))));
for x in addr {
for c in format!("{}", x).chars() {
status_chars.push(TerminalAtom::new(c, TerminalStyle::fg_color((0, 100, 20))));
}
status_chars.push(TerminalAtom::new('.', TerminalStyle::fg_color((120, 80, 80))));
}
}
None => {}
}
} }
//drop(term); //drop(term);