#![allow(dead_code)] use rustbox; use rustbox::Color; use editor::Editor; use std::char; use std::time::duration::Duration; // Key codes const K_ENTER: u16 = 13; const K_TAB: u16 = 9; const K_SPACE: u16 = 32; const K_BACKSPACE: u16 = 127; const K_PAGEUP: u16 = 65519; const K_PAGEDOWN: u16 = 65518; const K_UP: u16 = 65517; const K_DOWN: u16 = 65516; const K_LEFT: u16 = 65515; const K_RIGHT: u16 = 65514; const K_ESC: u16 = 27; const K_CTRL_Q: u16 = 17; const K_CTRL_S: u16 = 19; pub struct TermUI { rb: rustbox::RustBox, editor: Editor, } impl TermUI { pub fn new() -> TermUI { TermUI { rb: rustbox::RustBox::init(&[None]).unwrap(), editor: Editor::new(), } } pub fn new_from_editor(editor: Editor) -> TermUI { TermUI { rb: rustbox::RustBox::init(&[None]).unwrap(), editor: editor, } } pub fn ui_loop(&mut self) { // Quitting flag let mut quit = false; let mut width = self.rb.width(); let mut height = self.rb.height(); self.editor.update_dim(height, width); loop { // Draw the editor to screen self.rb.clear(); self.draw_editor(&self.editor, (0, 0), (height-1, width-1)); self.rb.present(); // Handle events. We block on the first event, so that the // program doesn't loop like crazy, but then continue pulling // events in a non-blocking way until we run out of events // to handle. let mut e = self.rb.poll_event(); // Block until we get an event loop { match e { Ok(rustbox::Event::KeyEvent(modifier, key, character)) => { //println!(" {} {} {}", modifier, key, character); match key { K_CTRL_Q | K_ESC => { quit = true; break; }, K_CTRL_S => { self.editor.save_if_dirty(); }, K_PAGEUP => { self.editor.page_up(); }, K_PAGEDOWN => { self.editor.page_down(); }, K_UP => { self.editor.cursor_up(); }, K_DOWN => { self.editor.cursor_down(); }, K_LEFT => { self.editor.cursor_left(); }, K_RIGHT => { self.editor.cursor_right(); }, K_ENTER => { self.editor.insert_text_at_cursor("\n"); }, K_SPACE => { self.editor.insert_text_at_cursor(" "); }, K_TAB => { self.editor.insert_text_at_cursor("\t"); }, K_BACKSPACE => { self.editor.remove_text_behind_cursor(1); }, // Character 0 => { if let Option::Some(c) = char::from_u32(character) { self.editor.insert_text_at_cursor(c.to_string().as_slice()); } }, _ => {} } }, Ok(rustbox::Event::ResizeEvent(w, h)) => { width = w as uint; height = h as uint; self.editor.update_dim(height, width); } _ => { break; } } e = self.rb.peek_event(Duration::milliseconds(0)); // Get next event (if any) } // Quit if quit flag is set if quit { break; } } } pub fn draw_editor(&self, editor: &Editor, c1: (uint, uint), c2: (uint, uint)) { let mut tb_iter = editor.buffer.iter_at_char(editor.buffer.pos_2d_to_closest_1d(editor.view_pos)); let mut pline = c1.0; let mut pcol = c1.1; let mut line = editor.view_pos.0; let mut column = editor.view_pos.1; let mut pos = editor.buffer.pos_2d_to_closest_1d(editor.view_pos); let max_line = line + (c2.0 - c1.0); let max_col = column + (c2.1 - c1.1); let cursor_pos = editor.buffer.pos_2d_to_closest_1d(editor.cursor); loop { if let Option::Some(c) = tb_iter.next() { if c == '\n' { if pos == cursor_pos { self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, " ".to_string().as_slice()); } pline += 1; pcol = c1.1; line += 1; column = 0; } else { if pos == cursor_pos { self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, c.to_string().as_slice()); } else { self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::White, Color::Black, c.to_string().as_slice()); } pcol += 1; column += 1; } } else { // Show cursor at end of document if it's past the end of // the document if cursor_pos >= pos { self.rb.print(pcol, pline, rustbox::RB_NORMAL, Color::Black, Color::White, " "); } return; } if line > max_line { return; } // If we're past the edge of the display, go to the next line if column > max_col { tb_iter.next_line(); pline += 1; pcol = c1.1; line += 1; column = 0; if line > max_line { return; } } // If we're before the edge of the display, move forward to get // to it. loop { if column < editor.view_pos.1 { let nl = tb_iter.skip_non_newline_chars(editor.view_pos.1); if !nl { column = editor.view_pos.1; break; } else { pline += 1; line += 1; } if line > max_line { return; } } else { break; } } // Get the 1d position of the char to be printed next pos = editor.buffer.pos_2d_to_closest_1d((line, column)); } } }