290 lines
11 KiB
Rust
290 lines
11 KiB
Rust
use {
|
|
crate::{
|
|
core::{OuterViewPort, ViewPort},
|
|
list::{
|
|
ListCursor, ListCursorMode,
|
|
ListSegment, ListSegmentSequence,
|
|
ListEditor
|
|
},
|
|
sequence::{SequenceView, decorator::{SeqDecorStyle, PTYSeqDecorate}},
|
|
singleton::{SingletonBuffer, SingletonView},
|
|
terminal::{
|
|
make_label, TerminalEditor, TerminalEditorResult, TerminalEvent, TerminalStyle,
|
|
TerminalView,
|
|
},
|
|
tree_nav::{TerminalTreeEditor, TreeCursor, TreeNav, TreeNavResult},
|
|
diagnostics::{Diagnostics},
|
|
vec::VecBuffer,
|
|
color::{bg_style_from_depth, fg_style_from_depth}
|
|
},
|
|
std::sync::{Arc, RwLock},
|
|
termion::event::{Event, Key},
|
|
cgmath::Vector2
|
|
};
|
|
|
|
pub struct PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
|
{
|
|
pub editor: ListEditor<ItemEditor>,
|
|
|
|
split_char: char,
|
|
|
|
style: SeqDecorStyle,
|
|
depth: usize,
|
|
|
|
port: ViewPort<dyn TerminalView>
|
|
}
|
|
|
|
impl<ItemEditor> PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
|
{
|
|
pub fn new(
|
|
make_item_editor: impl Fn() -> Arc<RwLock<ItemEditor>> + Send + Sync + 'static,
|
|
style: SeqDecorStyle,
|
|
split_char: char,
|
|
depth: usize
|
|
) -> Self {
|
|
let port = ViewPort::new();
|
|
PTYListEditor {
|
|
editor: ListEditor::new(make_item_editor, depth),
|
|
style,
|
|
depth,
|
|
split_char,
|
|
port
|
|
}
|
|
}
|
|
|
|
pub fn from_editor(
|
|
editor: ListEditor<ItemEditor>,
|
|
style: SeqDecorStyle,
|
|
split_char: char,
|
|
depth: usize
|
|
) -> Self {
|
|
let port = ViewPort::new();
|
|
PTYListEditor {
|
|
editor,
|
|
split_char,
|
|
style,
|
|
depth,
|
|
port
|
|
}
|
|
}
|
|
|
|
pub fn get_data_port(&self) -> OuterViewPort<dyn SequenceView<Item = Arc<RwLock<ItemEditor>>>> {
|
|
self.editor.get_data_port()
|
|
}
|
|
|
|
pub fn clear(&mut self) {
|
|
self.editor.clear();
|
|
}
|
|
|
|
pub fn get_item(&self) -> Option<Arc<RwLock<ItemEditor>>> {
|
|
self.editor.get_item()
|
|
}
|
|
|
|
pub fn set_depth(&mut self, depth: usize) {
|
|
self.depth = depth;
|
|
}
|
|
|
|
pub fn set_style(&mut self, style: SeqDecorStyle) {
|
|
self.style = style;
|
|
}
|
|
}
|
|
|
|
impl<ItemEditor> TerminalEditor for PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
|
{
|
|
fn get_term_view(&self) -> OuterViewPort<dyn TerminalView> {
|
|
self.editor
|
|
.get_seg_seq_view()
|
|
.pty_decorate(self.style, self.depth)
|
|
}
|
|
|
|
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
|
let mut cur = self.editor.cursor.get();
|
|
if let Some(idx) = cur.idx {
|
|
match cur.mode {
|
|
ListCursorMode::Insert => match event {
|
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
|
if idx > 0 && idx <= self.editor.data.len() as isize {
|
|
cur.idx = Some(idx as isize - 1);
|
|
self.editor.cursor.set(cur);
|
|
self.editor.data.remove(idx as usize - 1);
|
|
|
|
if self.editor.data.len() > 0 {
|
|
TerminalEditorResult::Continue
|
|
} else {
|
|
TerminalEditorResult::Exit
|
|
}
|
|
} else {
|
|
TerminalEditorResult::Exit
|
|
}
|
|
}
|
|
TerminalEvent::Input(Event::Key(Key::Delete)) => {
|
|
if idx < self.editor.data.len() as isize {
|
|
self.editor.data.remove(idx as usize);
|
|
TerminalEditorResult::Continue
|
|
} else {
|
|
TerminalEditorResult::Exit
|
|
}
|
|
}
|
|
TerminalEvent::Input(Event::Key(Key::Char('\t')))
|
|
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
|
self.editor.set_leaf_mode(ListCursorMode::Select);
|
|
TerminalEditorResult::Continue
|
|
}
|
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
|
self.editor.goto(TreeCursor::none());
|
|
TerminalEditorResult::Exit
|
|
}
|
|
_ => {
|
|
let new_edit = (self.editor.make_item_editor)();
|
|
self.editor.data.insert(idx as usize, new_edit.clone());
|
|
self.editor.set_leaf_mode(ListCursorMode::Select);
|
|
|
|
let mut ne = new_edit.write().unwrap();
|
|
ne.goto(TreeCursor::home());
|
|
|
|
match ne.handle_terminal_event(event) {
|
|
TerminalEditorResult::Exit => {
|
|
self.editor.cursor.set(ListCursor {
|
|
mode: ListCursorMode::Insert,
|
|
idx: Some(idx as isize + 1),
|
|
});
|
|
}
|
|
_ => {}
|
|
}
|
|
TerminalEditorResult::Continue
|
|
}
|
|
},
|
|
ListCursorMode::Select => {
|
|
match event {
|
|
TerminalEvent::Input(Event::Key(Key::Char('\t')))
|
|
| TerminalEvent::Input(Event::Key(Key::Insert)) => {
|
|
self.editor.set_leaf_mode(ListCursorMode::Insert);
|
|
TerminalEditorResult::Continue
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
|
if *c == self.split_char {
|
|
let c = self.editor.cursor.get();
|
|
self.editor.goto(TreeCursor::none());
|
|
self.editor.cursor.set(ListCursor {
|
|
mode: ListCursorMode::Insert,
|
|
idx: Some(1 + c.idx.unwrap_or(0))
|
|
});
|
|
} else {
|
|
if let Some(e) = self.editor.get_item() {
|
|
match e.write().unwrap().handle_terminal_event(&TerminalEvent::Input(Event::Key(Key::Char(*c)))) {
|
|
TerminalEditorResult::Exit => {
|
|
self.editor.cursor.set(ListCursor {
|
|
mode: ListCursorMode::Insert,
|
|
idx: Some(idx as isize + 1),
|
|
});
|
|
}
|
|
TerminalEditorResult::Continue => {
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
TerminalEditorResult::Continue
|
|
}
|
|
ev => {
|
|
if let Some(e) = self.editor.get_item() {
|
|
match e.write().unwrap().handle_terminal_event(ev) {
|
|
TerminalEditorResult::Exit => {
|
|
|
|
match ev {
|
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
|
self.editor.data.remove(idx as usize);
|
|
self.editor.cursor.set(ListCursor {
|
|
mode: ListCursorMode::Insert,
|
|
idx: Some(idx as isize),
|
|
});
|
|
}
|
|
_ => {
|
|
self.editor.cursor.set(ListCursor {
|
|
mode: ListCursorMode::Insert,
|
|
idx: Some(idx as isize + 1),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
TerminalEditorResult::Continue => {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
TerminalEditorResult::Continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
TerminalEditorResult::Continue
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<ItemEditor> TreeNav for PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
|
{
|
|
fn get_cursor_warp(&self) -> TreeCursor {
|
|
self.editor.get_cursor_warp()
|
|
}
|
|
|
|
fn get_cursor(&self) -> TreeCursor {
|
|
self.editor.get_cursor()
|
|
}
|
|
|
|
fn goby(&mut self, direction: Vector2<isize>) -> TreeNavResult {
|
|
self.editor.goby(direction)
|
|
}
|
|
|
|
fn goto(&mut self, cursor: TreeCursor) -> TreeNavResult {
|
|
self.editor.goto(cursor)
|
|
}
|
|
}
|
|
|
|
impl<ItemEditor> Diagnostics for PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + Diagnostics + ?Sized + Send + Sync + 'static
|
|
{
|
|
fn get_msg_port(&self) -> OuterViewPort<dyn SequenceView<Item = crate::diagnostics::Message>> {
|
|
self.editor
|
|
.get_data_port()
|
|
.enumerate()
|
|
.map(
|
|
|(idx, item_editor)| {
|
|
let idx = *idx;
|
|
item_editor.read().unwrap()
|
|
.get_msg_port()
|
|
.map(
|
|
move |msg| {
|
|
let mut msg = msg.clone();
|
|
msg.addr.insert(0, idx);
|
|
msg
|
|
}
|
|
)
|
|
}
|
|
)
|
|
.flatten()
|
|
}
|
|
}
|
|
|
|
impl<ItemEditor> TerminalTreeEditor for PTYListEditor<ItemEditor>
|
|
where ItemEditor: TerminalTreeEditor + ?Sized + Send + Sync + 'static
|
|
{}
|
|
|
|
use crate::{
|
|
char_editor::CharEditor,
|
|
sequence::SequenceViewExt
|
|
};
|
|
|
|
impl PTYListEditor<CharEditor> {
|
|
pub fn get_string(&self) -> String {
|
|
self.get_data_port().map(|ce| ce.read().unwrap().get()).get_view().unwrap().iter().collect::<String>()
|
|
}
|
|
}
|
|
|