aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/term.rs96
-rw-r--r--test/rl.rs32
2 files changed, 117 insertions, 11 deletions
diff --git a/src/term.rs b/src/term.rs
index 27fc8c9..ae21cc0 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -3,9 +3,12 @@
#[crate_type = "lib"];
use core::libc::c_int;
+use core::option::{Option,Some,None};
+use core::io::ReaderUtil;
pub use ios::{cooked,cbreak,raw,echo,size};
use info::{init,escape,escape2};
+use util::Trie;
struct Writer {
priv cleanup: bool,
@@ -59,6 +62,99 @@ impl Drop for Writer {
}
}
+enum Keypress {
+ KeyCharacter(char),
+ KeyBackspace,
+ KeyReturn,
+ KeyTab,
+ KeyCtrl(char),
+ KeyF(int),
+ KeyUp,
+ KeyDown,
+ KeyLeft,
+ KeyRight,
+ KeyHome,
+ KeyEnd,
+ KeyInsert,
+ KeyDelete,
+ KeyEscape,
+}
+
+struct Reader {
+ priv escapes: ~Trie<Keypress>,
+}
+
+pub fn Reader () -> Reader {
+ Reader { escapes: build_escapes_trie() }
+}
+
+impl Reader {
+ pub fn read (&self) -> Option<Keypress> {
+ let mut buf = ~"";
+ loop {
+ let c = io::stdin().read_char();
+ if c as int == -1 {
+ return None;
+ }
+
+ str::push_char(&mut buf, c);
+ io::print(str::escape_default(buf));
+
+ if !self.escapes.has_prefix(buf) {
+ match self.escapes.find(buf) {
+ &Some(k) => { return Some(k) }
+ &None => {
+ if str::len(buf) == 1 {
+ return Some(KeyCharacter(str::char_at(buf, 0)));
+ }
+ else {
+ // XXX this is... suboptimal
+ // really, we need to do an ungetc sort of thing
+ // with the characters in buf, and then just
+ // return the first character as a KeyCharacter
+ fail!("unknown escape");
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// XXX this whole thing needs to be able to deal with caps that don't exist
+fn build_escapes_trie () -> ~Trie<Keypress> {
+ let mut trie = ~Trie();
+
+ trie.insert(escape("kbs"), KeyBackspace);
+ trie.insert(escape("cr"), KeyReturn);
+ trie.insert(escape("ht"), KeyTab);
+
+ trie.insert(escape("kcuu1"), KeyUp);
+ trie.insert(escape("kcud1"), KeyDown);
+ trie.insert(escape("kcub1"), KeyLeft);
+ trie.insert(escape("kcuf1"), KeyRight);
+
+ trie.insert(escape("khome"), KeyHome);
+ trie.insert(escape("kend"), KeyEnd);
+ trie.insert(escape("kich1"), KeyInsert);
+ trie.insert(escape("kdch1"), KeyDelete);
+
+ for uint::range(1, 12) |i| {
+ trie.insert(escape(fmt!("kf%d", i as int)), KeyF(i as int));
+ }
+
+ for uint::range(1, 26) |i| {
+ let s = str::from_char(i as char);
+ if (trie.find(s).is_none()) {
+ trie.insert(s, KeyCtrl(i as char));
+ }
+ }
+
+ trie.insert(str::from_char(27 as char), KeyEscape);
+
+ trie
+}
+
pub fn isatty() -> bool {
unsafe { c_isatty(0) as bool }
}
diff --git a/test/rl.rs b/test/rl.rs
index 9b096b4..fe1103b 100644
--- a/test/rl.rs
+++ b/test/rl.rs
@@ -1,11 +1,12 @@
extern mod term;
-use core::io::ReaderUtil;
+use term::{KeyCharacter,KeyEscape,KeyUp,KeyDown,KeyLeft,KeyRight};
-fn term_app (body: &fn (w: &term::Writer)) {
+fn term_app (body: &fn (r: &term::Reader, w: &term::Writer)) {
let writer = term::Writer(true);
+ let reader = term::Reader();
do term::ios::preserve {
writer.alternate_screen(true);
- body(&writer);
+ body(&reader, &writer);
}
}
@@ -30,7 +31,7 @@ fn draw_ground (w: &term::Writer, x: uint, y: uint) {
fn main () {
let (cols, rows) = term::size();
- do term_app |w| {
+ do term_app |r, w| {
term::cbreak();
term::echo(false);
w.clear();
@@ -41,13 +42,22 @@ fn main () {
let mut cursor = true;
loop {
draw_character(w, x, y);
- match io::stdin().read_char() {
- 'q' => { break }
- 'h' if x > 0 => { draw_ground(w, x, y); x -= 1 }
- 'j' if y < rows - 1 => { draw_ground(w, x, y); y += 1 }
- 'k' if y > 0 => { draw_ground(w, x, y); y -= 1 }
- 'l' if x < cols - 1 => { draw_ground(w, x, y); x += 1 }
- ' ' => { w.cursor(cursor); cursor = !cursor }
+ let k = match r.read() {
+ Some(key) => key,
+ None => break,
+ };
+ draw_ground(w, x, y);
+
+ match k {
+ KeyCharacter('q') | KeyEscape => { break }
+
+ KeyCharacter('h') | KeyLeft if x > 0 => { x -= 1 }
+ KeyCharacter('j') | KeyDown if y < rows - 1 => { y += 1 }
+ KeyCharacter('k') | KeyUp if y > 0 => { y -= 1 }
+ KeyCharacter('l') | KeyRight if x < cols - 1 => { x += 1 }
+
+ KeyCharacter(' ') => { w.cursor(cursor); cursor = !cursor }
+
_ => { }
}
}