build StringEditor and PosIntEditor ontop of ListEditor
add DigitEditor and CharEditor
This commit is contained in:
parent
fef4b930ae
commit
9905a2376f
7 changed files with 301 additions and 483 deletions
76
nested/src/integer/digit.rs
Normal file
76
nested/src/integer/digit.rs
Normal 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 {
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
|
||||
pub mod radix;
|
||||
pub mod add;
|
||||
pub mod digit;
|
||||
|
||||
pub use {
|
||||
radix::RadixProjection,
|
||||
add::Add
|
||||
add::Add,
|
||||
digit::DigitEditor
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ use {
|
|||
TerminalEditorResult,
|
||||
make_label
|
||||
},
|
||||
string_editor::StringEditor,
|
||||
leveled_term_view::LeveledTermView,
|
||||
list::{SExprView, ListDecoration}
|
||||
}
|
||||
|
@ -145,10 +144,29 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
|
||||
fn goto_end(&mut self) -> TreeNavResult {
|
||||
match self.cursor.get() {
|
||||
ListEditorCursor::None |
|
||||
ListEditorCursor::Insert(_) |
|
||||
ListEditorCursor::Select(_) =>
|
||||
self.goto(vec![ self.data.len()-1 ]),
|
||||
ListEditorCursor::None => { self.goto(vec![ self.data.len() - 1 ])}
|
||||
ListEditorCursor::Insert(idx) => {
|
||||
if idx < self.data.len() {
|
||||
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) => {
|
||||
let ce = self.data.get_mut(idx);
|
||||
let mut cur_edit = ce.write().unwrap();
|
||||
|
@ -157,8 +175,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||
TreeNavResult::Exit => {
|
||||
if idx+1 < self.data.len() {
|
||||
self.cursor.set(ListEditorCursor::Edit(idx+1));
|
||||
self.data.get_mut(idx+1).write().unwrap().goto_end();
|
||||
drop(cur_edit);
|
||||
self.up();
|
||||
self.nexd();
|
||||
self.dn();
|
||||
self.goto_end();
|
||||
TreeNavResult::Continue
|
||||
} else {
|
||||
self.cursor.set(ListEditorCursor::None);
|
||||
|
@ -183,8 +204,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
TreeNavResult::Continue => TreeNavResult::Continue,
|
||||
TreeNavResult::Exit => {
|
||||
if idx > 0 {
|
||||
self.cursor.set(ListEditorCursor::Edit(idx-1));
|
||||
self.data.get_mut(idx-1).write().unwrap().goto_home();
|
||||
drop(cur_edit);
|
||||
self.up();
|
||||
self.pxev();
|
||||
self.dn();
|
||||
self.goto_home();
|
||||
TreeNavResult::Continue
|
||||
} else {
|
||||
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.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
|
||||
|
@ -239,8 +269,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
match cur_edit.pxev() {
|
||||
TreeNavResult::Exit => {
|
||||
if idx > 0 {
|
||||
self.cursor.set(ListEditorCursor::Edit(idx-1));
|
||||
self.data.get_mut(idx-1).write().unwrap().goto_end();
|
||||
drop(cur_edit);
|
||||
self.up();
|
||||
self.pxev();
|
||||
self.dn();
|
||||
self.goto_end();
|
||||
TreeNavResult::Continue
|
||||
} else {
|
||||
TreeNavResult::Exit
|
||||
|
@ -268,6 +301,7 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
self.cursor.set(ListEditorCursor::Select(idx + 1));
|
||||
TreeNavResult::Continue
|
||||
} else {
|
||||
self.cursor.set(ListEditorCursor::None);
|
||||
TreeNavResult::Exit
|
||||
}
|
||||
}
|
||||
|
@ -278,8 +312,10 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
match cur_edit.nexd() {
|
||||
TreeNavResult::Exit => {
|
||||
if idx+1 < self.data.len() {
|
||||
self.cursor.set(ListEditorCursor::Edit(idx+1));
|
||||
self.data.get_mut(idx+1).write().unwrap().goto_home();
|
||||
drop(cur_edit);
|
||||
self.up();
|
||||
self.nexd();
|
||||
self.dn();
|
||||
TreeNavResult::Continue
|
||||
} else {//if idx+1 == self.data.len() {
|
||||
TreeNavResult::Exit
|
||||
|
@ -297,42 +333,74 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
|
||||
{
|
||||
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 {
|
||||
match self.cursor.get() {
|
||||
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 mut cur_edit = ce.write().unwrap();
|
||||
let new_edit = (self.make_item_editor)();
|
||||
self.data.insert(idx, new_edit.clone());
|
||||
|
||||
cur_edit.goto_home();
|
||||
new_edit.write().unwrap().goto_home();
|
||||
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) => {
|
||||
let mut ce = self.data.get_mut(idx);
|
||||
let mut cur_edit = ce.write().unwrap();
|
||||
match event {
|
||||
TerminalEvent::Input(Event::Key(Key::Char(' '))) => {
|
||||
// split..
|
||||
self.data.insert(idx+1, (self.make_item_editor)());
|
||||
self.data.get_mut(idx).write().unwrap().goto_end();
|
||||
self.data.get_mut(idx+1).write().unwrap().goto_home();
|
||||
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.up();
|
||||
self.cursor.set(ListEditorCursor::Insert(idx+1));
|
||||
TerminalEditorResult::Continue
|
||||
}
|
||||
_ => cur_edit.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);
|
||||
|
@ -345,12 +413,11 @@ where SubEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static,
|
|||
}
|
||||
_=>{}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
TerminalEditorResult::Continue
|
||||
}
|
||||
_ => TerminalEditorResult::Continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ListEditorViewSegment {
|
||||
|
@ -472,7 +539,7 @@ impl ListEditorView {
|
|||
);
|
||||
|
||||
s.cast.notify_each(
|
||||
begin ..= end
|
||||
0 ..= s.data.len().unwrap_or(0)+1
|
||||
);
|
||||
}),
|
||||
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>
|
||||
where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
||||
FnMakeItemEditor: Fn() -> Arc<RwLock<SubEditor>>
|
||||
{
|
||||
|
||||
pub fn get_seg_seq_view(&self) -> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn TerminalView>>> {
|
||||
self.segment_seq
|
||||
.map(
|
||||
|
@ -538,9 +613,11 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
|||
pub fn horizontal_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||
self.get_seg_seq_view().horizontal_sexpr_view(0)
|
||||
}
|
||||
|
||||
pub fn vertical_sexpr_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||
self.get_seg_seq_view().vertical_sexpr_view(0)
|
||||
}
|
||||
|
||||
pub fn path_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||
self.get_seg_seq_view()
|
||||
.decorate("<", ">", "/", 0)
|
||||
|
@ -553,8 +630,21 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
|||
.to_grid_horizontal()
|
||||
.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 data_port = ViewPort::new();
|
||||
|
||||
|
@ -570,13 +660,27 @@ where SubEditor: TerminalEditor + ?Sized + Send + Sync + 'static,
|
|||
segment_view_port.inner()
|
||||
);
|
||||
|
||||
ListEditor {
|
||||
let mut le = ListEditor {
|
||||
data,
|
||||
data_sequence_port,
|
||||
cursor,
|
||||
make_item_editor,
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
pub mod editor;
|
||||
pub mod sexpr;
|
||||
|
||||
pub use editor::ListEditor;
|
||||
pub use editor::{ListEditor, ListEditorStyle};
|
||||
pub use sexpr::{SExprView, ListDecoration};
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ impl SequenceView for ListDecorator {
|
|||
|
||||
fn len(&self) -> Option<usize> {
|
||||
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> {
|
||||
|
|
|
@ -12,271 +12,52 @@ use {
|
|||
|
||||
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StringEditor {
|
||||
data: VecBuffer<char>,
|
||||
cursor: SingletonBuffer<Option<usize>>,
|
||||
|
||||
data_port: ViewPort<RwLock<Vec<char>>>,
|
||||
cursor_port: ViewPort<dyn SingletonView<Item = Option<usize>>>
|
||||
pub struct CharEditor {
|
||||
data: SingletonBuffer<Option<char>>,
|
||||
data_port: ViewPort<dyn SingletonView<Item = Option<char>>>
|
||||
}
|
||||
|
||||
impl StringEditor {
|
||||
impl CharEditor {
|
||||
pub fn new() -> Self {
|
||||
let data_port = ViewPort::new();
|
||||
let cursor_port = ViewPort::new();
|
||||
|
||||
StringEditor {
|
||||
data: VecBuffer::new(data_port.inner()),
|
||||
cursor: SingletonBuffer::new(None, cursor_port.inner()),
|
||||
|
||||
data_port,
|
||||
cursor_port
|
||||
let mut data_port = ViewPort::new();
|
||||
CharEditor {
|
||||
data: SingletonBuffer::new(None, data_port.inner()),
|
||||
data_port
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_view(&self) -> OuterViewPort<dyn TerminalView> {
|
||||
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>>> {
|
||||
pub fn get_data_port(&self) -> OuterViewPort<dyn SingletonView<Item = Option<char>>> {
|
||||
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 {
|
||||
self.data.insert(self.cursor.get().unwrap_or(0), c);
|
||||
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 {
|
||||
impl TreeNav for CharEditor {}
|
||||
impl TerminalEditor for CharEditor {
|
||||
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 {
|
||||
match event {
|
||||
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => TerminalEditorResult::Continue,
|
||||
TerminalEvent::Input(Event::Key(Key::Char(c))) => match self.insert(*c) {
|
||||
TreeNavResult::Exit => TerminalEditorResult::Exit,
|
||||
TreeNavResult::Continue => TerminalEditorResult::Continue
|
||||
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::Delete)) => match self.delete() {
|
||||
TreeNavResult::Exit => TerminalEditorResult::Exit,
|
||||
TreeNavResult::Continue => TerminalEditorResult::Continue
|
||||
}
|
||||
TerminalEvent::Input(Event::Key(Key::Backspace)) => match self.delete_prev() {
|
||||
TreeNavResult::Exit => TerminalEditorResult::Exit,
|
||||
TreeNavResult::Continue => TerminalEditorResult::Continue
|
||||
TerminalEvent::Input(Event::Key(Key::Backspace)) |
|
||||
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
||||
self.data.set(None);
|
||||
TerminalEditorResult::Exit
|
||||
}
|
||||
_ => 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use{
|
|||
index::{IndexView},
|
||||
sequence::{SequenceView},
|
||||
vec::{VecBuffer},
|
||||
integer::{RadixProjection},
|
||||
integer::{RadixProjection, DigitEditor},
|
||||
terminal::{
|
||||
Terminal,
|
||||
TerminalStyle,
|
||||
|
@ -27,9 +27,9 @@ use{
|
|||
make_label,
|
||||
TerminalView,
|
||||
TerminalEditor},
|
||||
string_editor::StringEditor,
|
||||
string_editor::{CharEditor},
|
||||
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 compositor = TerminalCompositor::new(term_port.inner());
|
||||
|
||||
let mut ed = StringEditor::new();
|
||||
|
||||
let mut term = Terminal::new(term_port.outer());
|
||||
let term_writer = term.get_writer();
|
||||
|
||||
async_std::task::spawn(
|
||||
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("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>")
|
||||
.map_item(
|
||||
|
@ -302,19 +119,33 @@ write::
|
|||
|
||||
// TypeEditor
|
||||
|
||||
let make_sub_editor = || {
|
||||
std::sync::Arc::new(std::sync::RwLock::new(StringEditor::new()))
|
||||
let make_char_editor = || {
|
||||
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(
|
||||
te.path_view()
|
||||
te.get_term_view()
|
||||
.offset(cgmath::Vector2::new(40,y))
|
||||
);
|
||||
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 {
|
||||
term_port.update();
|
||||
|
@ -343,10 +174,19 @@ write::
|
|||
}
|
||||
TerminalEvent::Input(Event::Key(Key::Up)) => { te.up(); }
|
||||
TerminalEvent::Input(Event::Key(Key::Down)) => { te.dn(); }
|
||||
TerminalEvent::Input(Event::Key(Key::Home)) => { te.goto_home(); }
|
||||
TerminalEvent::Input(Event::Key(Key::End)) => { te.goto_end(); }
|
||||
TerminalEvent::Input(Event::Key(Key::Home)) => {
|
||||
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'))) => {
|
||||
/*
|
||||
let mut strings = Vec::new();
|
||||
|
||||
let v = p.get_view().unwrap();
|
||||
|
@ -412,12 +252,27 @@ write::
|
|||
y += 1;
|
||||
|
||||
p = te.get_data_port().map(|string_editor| string_editor.read().unwrap().get_data_port());
|
||||
*/
|
||||
},
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue