Implemented ^W.
This commit is contained in:
parent
4a32bbb9af
commit
21222baa71
3 changed files with 54 additions and 32 deletions
|
@ -1,12 +1,15 @@
|
|||
extern crate unicode_segmentation;
|
||||
|
||||
use std::io::Write;
|
||||
use termion::{clear, cursor, color};
|
||||
use termion::raw::RawTerminal;
|
||||
use crate::layout::Layout;
|
||||
use crate::utils;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
const PROMPT: &str = "Add alarm: ";
|
||||
|
||||
|
||||
// Input buffer.
|
||||
pub struct Buffer {
|
||||
content: String,
|
||||
// Used for error messages.
|
||||
|
@ -23,21 +26,46 @@ impl Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
// Return reference to buffer content.
|
||||
pub fn read(&mut self) -> &String {
|
||||
self.altered = false;
|
||||
&self.content
|
||||
}
|
||||
|
||||
// Append char to buffer.
|
||||
pub fn push(&mut self, value: char) {
|
||||
self.altered = true;
|
||||
// Reset error message.
|
||||
self.message = None;
|
||||
self.content.push(value);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<char> {
|
||||
self.altered = true;
|
||||
// Remove last char. Return true if a char was removed.
|
||||
pub fn strip_char(&mut self) -> bool {
|
||||
// Reset error message.
|
||||
self.message = None;
|
||||
self.content.pop()
|
||||
if self.content.pop().is_some() {
|
||||
self.altered = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Remove last word. Return true if a word was removed.
|
||||
pub fn strip_word(&mut self) -> bool {
|
||||
// Reset error message.
|
||||
self.message = None;
|
||||
let iter = UnicodeSegmentation::split_word_bound_indices(
|
||||
self.content.as_str().trim_end());
|
||||
|
||||
if let Some((index, _)) = iter.last() {
|
||||
self.content.truncate(index);
|
||||
self.altered = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
|
@ -63,6 +91,7 @@ impl Buffer {
|
|||
layout: &mut Layout,
|
||||
) -> Result<(), std::io::Error>
|
||||
{
|
||||
// Write error message if present and return.
|
||||
if let Some(msg) = self.message {
|
||||
write!(stdout,
|
||||
"{}{}{}{}{}{}",
|
||||
|
@ -85,13 +114,6 @@ impl Buffer {
|
|||
PROMPT,
|
||||
cursor::Show,
|
||||
&self.content)?;
|
||||
layout.cursor.col =
|
||||
layout.buffer.col
|
||||
+ 11
|
||||
+ utils::unicode_length(&self.content);
|
||||
// TODO: This would be a much better alternative, but panics because
|
||||
// of interference with async_reader.
|
||||
//layout.cursor.col = stdout.cursor_pos()?.0;
|
||||
} else {
|
||||
// Clear buffer display.
|
||||
write!(stdout,
|
||||
|
|
|
@ -29,7 +29,6 @@ pub struct Layout {
|
|||
pub roster_width: u16,
|
||||
pub roster_height: u16,
|
||||
pub buffer: Position,
|
||||
pub cursor: Position,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
|
@ -51,7 +50,6 @@ impl Layout {
|
|||
roster_width: 0,
|
||||
roster_height: 0,
|
||||
buffer: Position {col: 0, line: 0},
|
||||
cursor: Position {col: 1, line: 1},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,9 +137,6 @@ impl Layout {
|
|||
line: self.height,
|
||||
col: 1,
|
||||
};
|
||||
|
||||
// Cursor. Column will be set by main loop.
|
||||
self.cursor.line = self.buffer.line;
|
||||
}
|
||||
|
||||
pub fn set_roster_width(&mut self, width: u16) {
|
||||
|
|
37
src/lib.rs
37
src/lib.rs
|
@ -17,7 +17,6 @@ use termion::{clear, cursor, style};
|
|||
use termion::raw::{IntoRawMode, RawTerminal};
|
||||
use termion::event::Key;
|
||||
use termion::input::TermRead;
|
||||
//use termion::cursor::DetectCursorPos;
|
||||
use buffer::Buffer;
|
||||
use clock::Clock;
|
||||
use layout::Layout;
|
||||
|
@ -102,10 +101,12 @@ pub fn run(
|
|||
}
|
||||
|
||||
// Update input buffer display, if requested.
|
||||
/*
|
||||
if buffer.altered {
|
||||
buffer.draw(&mut stdout, &mut layout)?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
*/
|
||||
|
||||
// Update elapsed time.
|
||||
let elapsed = if clock.paused {
|
||||
|
@ -194,14 +195,6 @@ pub fn run(
|
|||
countdown.draw(&mut stdout);
|
||||
}
|
||||
|
||||
// Move cursor to buffer position.
|
||||
if insert_mode {
|
||||
write!(
|
||||
stdout,
|
||||
"{}",
|
||||
cursor::Goto(layout.cursor.col, layout.cursor.line))?;
|
||||
}
|
||||
|
||||
// Check any spawned child process.
|
||||
if let Some(ref mut child) = spawned {
|
||||
match child.try_wait() {
|
||||
|
@ -228,6 +221,12 @@ pub fn run(
|
|||
stdout.flush()?;
|
||||
}
|
||||
|
||||
// Update buffer whenever the cursor is visible.
|
||||
if insert_mode || buffer.altered {
|
||||
buffer.draw(&mut stdout, &mut layout)?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
|
||||
// Process input.
|
||||
if let Some(key) = input_keys.next() {
|
||||
match key.expect("Error reading input") {
|
||||
|
@ -248,21 +247,27 @@ pub fn run(
|
|||
}
|
||||
},
|
||||
// Escape ^W, and ^U clear input buffer.
|
||||
Key::Esc | Key::Ctrl('w') | Key::Ctrl('u') => {
|
||||
Key::Esc | Key::Ctrl('u') => {
|
||||
buffer.reset();
|
||||
insert_mode = false;
|
||||
update_menu = true;
|
||||
layout.force_redraw = true;
|
||||
},
|
||||
// ^W removes last word.
|
||||
Key::Ctrl('w') => {
|
||||
if !buffer.strip_word() {
|
||||
insert_mode = false;
|
||||
update_menu = true;
|
||||
layout.force_redraw = true;
|
||||
}
|
||||
},
|
||||
// Backspace.
|
||||
Key::Backspace => {
|
||||
// Delete last char in buffer.
|
||||
if buffer.pop().is_some() {
|
||||
if buffer.is_empty() {
|
||||
insert_mode = false;
|
||||
update_menu = true;
|
||||
layout.force_redraw = true;
|
||||
}
|
||||
if buffer.strip_char() && buffer.is_empty() {
|
||||
insert_mode = false;
|
||||
update_menu = true;
|
||||
layout.force_redraw = true;
|
||||
}
|
||||
},
|
||||
// Forward every char if in insert mode.
|
||||
|
|
Loading…
Reference in a new issue