#![feature(trait_alias)] #![feature(assoc_char_funcs)] pub mod core; pub mod index; pub mod grid; pub mod sequence; pub mod singleton; pub mod terminal; pub mod string_editor; use { async_std::{task}, std::{ sync::{Arc, RwLock} }, cgmath::{Vector2, Point2}, termion::event::{Event, Key}, crate::{ core::{View, Observer, ObserverExt, ViewPort}, index::{ImplIndexView}, terminal::{ TerminalView, TerminalAtom, TerminalStyle, TerminalEvent, Terminal, TerminalCompositor }, grid::{GridOffset, GridWindowIterator}, singleton::{SingletonView, SingletonBuffer}, string_editor::{StringEditor} } }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> #[async_std::main] async fn main() { let term_port = ViewPort::::new(); let mut compositor = TerminalCompositor::new(term_port.inner()); compositor.push(ViewPort::::with_view(Arc::new(ScrambleBackground)).into_outer()); let mut term = Terminal::new(term_port.outer()); let term_writer = term.get_writer(); task::spawn(async move { /*\ <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> Setup Views <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> \*/ let window_size_port = ViewPort::new(); let mut window_size = SingletonBuffer::new(Vector2::new(0, 0), window_size_port.inner()); //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> // string editor let mut editor = StringEditor::new(); let edit_view_port = ViewPort::new(); let edit_view = string_editor::insert_view::StringEditView::new( editor.get_cursor_port(), editor.get_data_port().to_sequence(), edit_view_port.inner() ); compositor.push( edit_view_port.outer() .map_item( |_pos, atom| atom.add_style_back( TerminalStyle::fg_color((200,200,200)) .add(TerminalStyle::bg_color((0,0,0))) .add(TerminalStyle::bold(true))) ) ); //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> // another view of the string, without editor compositor.push( editor.get_data_port() .to_sequence() .to_index() .map_key( |idx| Point2::new(*idx as i16, 2), |pt| if pt.y == 2 { Some(pt.x as usize) } else { None } ).map_item( |_key, c| TerminalAtom::new(*c, TerminalStyle::fg_color((0, 200, 0))) ) ); /*\ <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> Event Loop <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> \*/ loop { match term.next_event().await { TerminalEvent::Resize(size) => window_size.set(size), TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(), TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(), TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0), TerminalEvent::Input(Event::Key(Key::End)) => editor.goto_end(), TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {}, TerminalEvent::Input(Event::Key(Key::Char(c))) => editor.insert(c), TerminalEvent::Input(Event::Key(Key::Delete)) => editor.delete(), TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); }, TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break, _ => {} } } }); /*\ <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> Terminal Rendering <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> \*/ term_writer.show().await.ok(); } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> struct Checkerboard; impl ImplIndexView for Checkerboard { type Key = Point2; type Value = TerminalAtom; fn get(&self, pos: &Point2) -> Option { if pos.x == 0 || pos.x == 1 || pos.x > 17 || pos.y == 0 || pos.y > 8 { // border Some(TerminalAtom::new_bg((20, 10, 10))) } else { // field if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) { Some(TerminalAtom::new_bg((0, 0, 0))) } else { Some(TerminalAtom::new_bg((200, 200, 200))) } } } fn area(&self) -> Option>> { Some(GridWindowIterator::from(Point2::new(0,0) .. Point2::new(20,10)).collect()) } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> struct TermLabel(String); impl ImplIndexView for TermLabel { type Key = Point2; type Value = TerminalAtom; fn get(&self, pos: &Point2) -> Option { if pos.y == 5 { Some(TerminalAtom::from(self.0.chars().nth(pos.x as usize)?)) } else { None } } fn area(&self) -> Option>> { Some( GridWindowIterator::from( Point2::new(0, 5) .. Point2::new(self.0.chars().count() as i16, 6) ).collect() ) } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> struct ScrambleBackground; impl ImplIndexView for ScrambleBackground { type Key = Point2; type Value = TerminalAtom; fn get(&self, pos: &Point2) -> Option { if ((pos.x/2) % 2 == 0) ^ (pos.y % 2 == 0) { Some(TerminalAtom::new(char::from((35+(5*pos.y+pos.x)%40) as u8), TerminalStyle::fg_color((40, 40, 40)))) } else { Some(TerminalAtom::new(char::from((35+(pos.y+9*pos.x)%40) as u8), TerminalStyle::fg_color((90, 90, 90)))) } } fn area(&self) -> Option>> { None } }