From 84dd024e5a6175ff5e18c7a8338f468d5f16944f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 3 Apr 2013 02:45:34 -0500 Subject: oops, forgot to commit this --- src/hexes.rs | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 src/hexes.rs diff --git a/src/hexes.rs b/src/hexes.rs new file mode 100644 index 0000000..e3b2aa2 --- /dev/null +++ b/src/hexes.rs @@ -0,0 +1,418 @@ +use info; +use ios::{cooked,cbreak,echo}; +use trie::Trie; + +mod util; + +enum Keypress { + KeyCharacter(char), + KeyBackspace, + KeyReturn, + KeyTab, + KeyCtrl(char), + KeyF(int), + KeyUp, + KeyDown, + KeyLeft, + KeyRight, + KeyHome, + KeyEnd, + KeyInsert, + KeyDelete, + KeyEscape, +} + +struct Term { + priv r: Reader, + priv w: Writer, +} + +pub fn Term () -> Term { + info::init(); + + cbreak(); + echo(false); + + print(info::keypad_xmit()); + print(info::enter_ca_mode()); + print(info::exit_attribute_mode()); + print(info::cursor_normal()); + print(info::clear_screen()); + + Term { r: Reader(), w: Writer() } +} + +impl Term { + pub fn clear (&mut self) { + self.w.clear(); + } + + pub fn move (&mut self, col: uint, row: uint) { + self.w.move(col, row); + } + + pub fn fg_color (&mut self, color: info::Color) { + self.w.fg_color(color); + } + + pub fn bg_color (&mut self, color: info::Color) { + self.w.bg_color(color); + } + + pub fn reset_color (&mut self) { + self.w.reset_color(); + } + + pub fn underline (&mut self, enabled: bool) { + self.w.underline(enabled); + } + + pub fn standout (&mut self, enabled: bool) { + self.w.standout(enabled); + } + + pub fn reverse (&mut self, enabled: bool) { + self.w.reverse(enabled); + } + + pub fn bold (&mut self, enabled: bool) { + self.w.bold(enabled); + } + + pub fn blink (&mut self, enabled: bool) { + self.w.blink(enabled); + } + + pub fn cursor (&mut self, enabled: bool) { + self.w.cursor(enabled); + } + + pub fn alternate_screen (&mut self, enabled: bool) { + self.w.alternate_screen(enabled); + } + + pub fn write (&mut self, text: &str) { + self.w.write(text); + } + + pub fn flush (&mut self) { + self.w.flush(); + } + + pub fn read (&mut self) -> Option { + self.w.flush(); + self.r.read() + } +} + +impl Drop for Term { + fn finalize (&self) { + print(info::keypad_xmit()); + print(info::exit_ca_mode()); + print(info::exit_attribute_mode()); + print(info::cursor_normal()); + + // XXX should really restore the previous termios mode... + cooked(); + } +} + +struct Writer { + priv buf: ~str, + priv state: AttrState, +} + +struct AttrState { + fg: Option, + bg: Option, + underline: bool, + standout: bool, + reverse: bool, + bold: bool, + blink: bool, +} + +fn Writer () -> Writer { + Writer { buf: ~"", state: AttrState() } +} + +fn AttrState () -> AttrState { + AttrState { + fg: None, + bg: None, + underline: false, + standout: false, + reverse: false, + bold: false, + blink: false, + } +} + +impl Writer { + fn clear (&mut self) { + self.buf.push_str(info::clear_screen()); + } + + fn move (&mut self, col: uint, row: uint) { + if col == 0u && row == 0u { + self.buf.push_str(info::cursor_home()); + } + else { + self.buf.push_str(info::cursor_address(row, col)); + } + } + + fn fg_color (&mut self, color: info::Color) { + match self.state.fg { + Some(c) if c == color => {} + _ => { + self.state.fg = Some(color); + self.buf.push_str(info::set_a_foreground(color)); + } + } + } + + fn bg_color (&mut self, color: info::Color) { + match self.state.bg { + Some(c) if c == color => {} + _ => { + self.state.bg = Some(color); + self.buf.push_str(info::set_a_background(color)); + } + } + } + + fn underline (&mut self, enabled: bool) { + if self.state.underline != enabled { + self.state.underline = enabled; + if enabled { + self.buf.push_str(info::enter_underline_mode()); + } + else { + self.buf.push_str(info::exit_underline_mode()); + } + } + } + + fn standout (&mut self, enabled: bool) { + if self.state.standout != enabled { + self.state.standout = enabled; + if enabled { + self.buf.push_str(info::enter_standout_mode()); + } + else { + self.buf.push_str(info::exit_standout_mode()); + } + } + } + + fn reverse (&mut self, enabled: bool) { + if self.state.reverse != enabled { + self.state.reverse = enabled; + if enabled { + self.buf.push_str(info::enter_reverse_mode()); + } + else { + self.apply_state(); + } + } + } + + fn bold (&mut self, enabled: bool) { + if self.state.bold != enabled { + self.state.bold = enabled; + if enabled { + self.buf.push_str(info::enter_bold_mode()); + } + else { + self.apply_state(); + } + } + } + + fn blink (&mut self, enabled: bool) { + if self.state.blink != enabled { + self.state.blink = enabled; + if enabled { + self.buf.push_str(info::enter_blink_mode()); + } + else { + self.apply_state(); + } + } + } + + fn reset_color (&mut self) { + self.state.fg = None; + self.state.bg = None; + self.buf.push_str(info::orig_pair()); + } + + fn reset_attributes (&mut self) { + self.state = AttrState(); + self.apply_state(); + } + + fn apply_state (&mut self) { + self.buf.push_str(info::exit_attribute_mode()); + match self.state.fg { + Some(c) => self.fg_color(c), + None => (), + } + match self.state.bg { + Some(c) => self.bg_color(c), + None => (), + } + if self.state.underline { + self.underline(true); + } + if self.state.standout { + self.standout(true); + } + if self.state.reverse { + self.reverse(true); + } + if self.state.bold { + self.bold(true); + } + if self.state.blink { + self.blink(true); + } + } + + fn cursor (&mut self, enabled: bool) { + if enabled { + self.buf.push_str(info::cursor_invisible()); + } + else { + self.buf.push_str(info::cursor_normal()); + } + } + + fn alternate_screen (&mut self, enabled: bool) { + if enabled { + self.buf.push_str(info::enter_ca_mode()); + } + else { + self.buf.push_str(info::exit_ca_mode()); + } + } + + fn write (&mut self, text: &str) { + self.buf.push_str(text); + } + + fn flush (&mut self) { + print(self.buf); + io::stdout().flush(); + self.buf = ~""; + } +} + +struct Reader { + priv escapes: Trie, + priv buf: ~str, +} + +pub fn Reader () -> Reader { + Reader { escapes: build_escapes_trie(), buf: ~"" } +} + +impl Reader { + fn read (&mut self) -> Option { + if self.buf.len() > 0 { + return Some(self.next_key()); + } + + 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) { + /* XXX i think this is a borrow check bug, should look into + * it at some point */ + //return match self.escapes.find(buf) { + // &Some(k) => { Some(k) } + // &None => { + // self.unget(buf); + // self.read() + // } + //} + { + let k = self.escapes.find(buf); + if k.is_some() { + return *k; + } + } + self.unget(buf); + return self.read(); + } + + match util::timed_read(1000000) { + Some(next) => { buf.push_char(next) } + None => { + self.unget(buf); + return self.read(); + } + } + } + } + + fn unget (&mut self, buf: &str) { + self.buf.push_str(buf); + } + + fn next_key (&mut self) -> Keypress { + assert!(self.buf.len() > 0); + for uint::range_rev(self.buf.len(), 0) |i| { + match self.escapes.find(self.buf.slice(0, i)) { + &Some(k) => { + for uint::range(0, i) |_| { + str::shift_char(&mut self.buf); + } + return k + } + &None => { } + } + } + let next = str::shift_char(&mut self.buf); + return KeyCharacter(next); + } +} + +// XXX this whole thing needs to be able to deal with caps that don't exist +fn build_escapes_trie () -> Trie { + let mut trie = Trie(); + + trie.insert(info::key_backspace(), KeyBackspace); + trie.insert(info::carriage_return(), KeyReturn); + trie.insert(info::tab(), KeyTab); + + trie.insert(info::key_up(), KeyUp); + trie.insert(info::key_down(), KeyDown); + trie.insert(info::key_left(), KeyLeft); + trie.insert(info::key_right(), KeyRight); + + trie.insert(info::key_home(), KeyHome); + trie.insert(info::key_end(), KeyEnd); + trie.insert(info::key_ic(), KeyInsert); + trie.insert(info::key_dc(), KeyDelete); + + for uint::range(1, 12) |i| { + trie.insert(info::key_f(i), 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 +} -- cgit v1.2.3