aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-04-01 02:06:35 -0500
committerJesse Luehrs <doy@tozt.net>2013-04-01 02:06:35 -0500
commitb7646b2d791cf10bd604aaee830fe22598b7d10d (patch)
tree9ba44d9aa729587e61b9b7c8671367d91fa8ef7e /src
parent10255902df82b54afa68290cd7ce59cdcf2014fa (diff)
downloadrust-term-b7646b2d791cf10bd604aaee830fe22598b7d10d.tar.gz
rust-term-b7646b2d791cf10bd604aaee830fe22598b7d10d.zip
provide a timeout for reads when trying to match an escape
Diffstat (limited to 'src')
-rw-r--r--src/io_helper.c38
-rw-r--r--src/term.rs23
-rw-r--r--src/util.rs27
3 files changed, 80 insertions, 8 deletions
diff --git a/src/io_helper.c b/src/io_helper.c
new file mode 100644
index 0000000..f4fa088
--- /dev/null
+++ b/src/io_helper.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <sys/select.h>
+
+int timed_read(int timeout)
+{
+ char byte;
+
+ if (timeout >= 0) {
+ fd_set readfds;
+ struct timeval t;
+
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+
+ t.tv_sec = timeout / 1000000;
+ t.tv_usec = timeout % 1000000;
+
+ if (select(1, &readfds, NULL, NULL, &t) == 1) {
+ if (read(0, &byte, 1) == 1) {
+ return byte;
+ }
+ else {
+ return -1;
+ }
+ }
+ else {
+ return -1;
+ }
+ }
+ else {
+ if (read(0, &byte, 1) == 1) {
+ return byte;
+ }
+ else {
+ return -1;
+ }
+ }
+}
diff --git a/src/term.rs b/src/term.rs
index 001138f..bb29025 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -93,15 +93,13 @@ impl Reader {
return Some(KeyCharacter(str::shift_char(&mut self.buf)));
}
- let mut buf = ~"";
- loop {
- let c = io::stdin().read_char();
- if c as int == -1 {
- return None;
- }
-
- str::push_char(&mut buf, c);
+ let first = util::timed_read(-1);
+ if first.is_none() {
+ return None;
+ }
+ let mut buf = str::from_char(*first.get_ref());
+ loop {
if !self.escapes.has_prefix(buf) {
return match self.escapes.find(buf) {
&Some(k) => { Some(k) }
@@ -112,6 +110,15 @@ impl Reader {
}
}
}
+
+ match util::timed_read(1000000) {
+ Some(next) => { str::push_char(&mut buf, next) }
+ None => {
+ str::push_str(&mut self.buf, buf);
+ let next = str::shift_char(&mut self.buf);
+ return Some(KeyCharacter(next));
+ }
+ }
}
}
}
diff --git a/src/util.rs b/src/util.rs
index 7ea5389..8ed877a 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,3 +1,5 @@
+use core::libc::c_int;
+
pub fn guard<T> (finally: ~fn (), body: &fn () -> T) -> T {
let _guard = Guard { finally: finally };
body()
@@ -218,3 +220,28 @@ fn check_has_prefix (trie: &Trie<int>, find: &str) {
fn check_not_has_prefix (trie: &Trie<int>, find: &str) {
fail_unless!(!trie.has_prefix(find));
}
+
+// XXX huge hack until there's a better built-in way to do this
+pub fn timed_read (timeout: int) -> Option<char> {
+ let first = unsafe { io_helper::timed_read(timeout as c_int) };
+ if first < 0 {
+ return None;
+ }
+
+ let mut buf = ~[first as u8];
+ let nbytes = str::utf8_char_width(first as u8);
+
+ for uint::range(0, nbytes - 1) |_| {
+ let next = unsafe { io_helper::timed_read(-1 as c_int) };
+ if next < 0 {
+ return None;
+ }
+ vec::push(&mut buf, next as u8);
+ }
+
+ Some(str::char_at(unsafe { str::raw::from_bytes(buf) }, 0))
+}
+
+extern mod io_helper {
+ fn timed_read (timeout: c_int) -> c_int;
+}