From c35796ef070e6b33c5cf3e961a6c55fe817fb72d Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 17 Dec 2017 02:30:53 -0800 Subject: add simultaneous binary/hex views, notion of selected view --- main.rs | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 126 insertions(+), 31 deletions(-) diff --git a/main.rs b/main.rs index 9792daf..b46cb48 100644 --- a/main.rs +++ b/main.rs @@ -166,12 +166,46 @@ impl Edits { } trait EditMode { - fn render_bytes(&self, cursor: u64, width: u16, start: u64, bytes: std::slice::Iter) -> String; + fn render_bytes(&self, cursor: u64, width: u16, selected: bool, start: u64, bytes: std::slice::Iter) -> String; // translates from the width of the display (terminal) // to the number of bytes this edit mode can display fn element_width(&self, display_width: u16) -> u64; fn dec_sub_elem(&mut self, amount: u64); fn inc_sub_elem(&mut self, amount: u64); + fn name(&self) -> &str; +} + +struct ASCIIMode { +} + +impl EditMode for ASCIIMode { + fn render_bytes(&self, cursor: u64, width: u16, selected: bool, start: u64, bytes: std::slice::Iter) -> String { + let mut ascii_text = "".to_owned(); + let mut i: usize = 0; + for b in bytes { + if cursor == start + i as u64 { + ascii_text.push_str(&format!("{}", color::Fg(color::Yellow))); + if selected { + ascii_text.push_str(&format!("{}", termion::style::Bold)); + } + ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); + if selected { + ascii_text.push_str(&format!("{}", termion::style::Reset)); + } + ascii_text.push_str(&format!("{}", color::Fg(color::Reset))); + } else { + ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); + } + i = i + 1; + } + ascii_text + } + fn element_width(&self, display_width: u16) -> u64 { + display_width as u64 + } + fn dec_sub_elem(&mut self, amount: u64) { } + fn inc_sub_elem(&mut self, amount: u64) { } + fn name(&self) -> &str { &"ASCII" } } struct BinaryMode { @@ -179,22 +213,23 @@ struct BinaryMode { } impl EditMode for BinaryMode { - fn render_bytes(&self, cursor: u64, width: u16, start: u64, bytes: std::slice::Iter) -> String { + fn render_bytes(&self, cursor: u64, width: u16, selected: bool, start: u64, bytes: std::slice::Iter) -> String { let mut text = "".to_owned(); -// let mut ascii_text = "".to_owned(); let col_size = 1; let mut i: usize = 0; for b in bytes { if cursor == start + i as u64 { text.push_str(&format!("{}", color::Fg(color::Yellow))); -// ascii_text.push_str(&format!("{}", color::Fg(color::Yellow))); + if selected { + text.push_str(&format!("{}", termion::style::Bold)); + } text.push_str(&format!("{:08b}", b)); -// ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); + if selected { + text.push_str(&format!("{}", termion::style::Reset)); + } text.push_str(&format!("{}", color::Fg(color::Reset))); -// ascii_text.push_str(&format!("{}", color::Fg(color::Reset))); } else { text.push_str(&format!("{:08b}", b)); -// ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); } if i % col_size == (col_size - 1) { text.push_str(" "); @@ -215,6 +250,7 @@ impl EditMode for BinaryMode { fn inc_sub_elem(&mut self, amount: u64) { self.sub_elem_idx = self.sub_elem_idx + amount as u8; } + fn name(&self) -> &str { &"Binary" } } struct HexMode { @@ -222,29 +258,24 @@ struct HexMode { } impl EditMode for HexMode { - fn render_bytes(&self, cursor: u64, width: u16, start: u64, bytes: std::slice::Iter) -> String { + fn render_bytes(&self, cursor: u64, width: u16, selected: bool, start: u64, bytes: std::slice::Iter) -> String { let mut text = "".to_owned(); let mut ascii_text = "".to_owned(); - let col_size = 4; + let col_size = 8; let mut i: usize = 0; - let selected = true; for b in bytes { if cursor == start + i as u64 { text.push_str(&format!("{}", color::Fg(color::Yellow))); - ascii_text.push_str(&format!("{}", color::Fg(color::Yellow))); if selected { text.push_str(&format!("{}", termion::style::Bold)); } text.push_str(&format!("{:02x}", b)); - ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); if selected { text.push_str(&format!("{}", termion::style::Reset)); } text.push_str(&format!("{}", color::Fg(color::Reset))); - ascii_text.push_str(&format!("{}", color::Fg(color::Reset))); } else { text.push_str(&format!("{:02x}", b)); - ascii_text.push_str(&format!("{}", ascii_or_dot(b.to_owned()) as char)); } if i % col_size == (col_size - 1) { text.push_str(" "); @@ -253,15 +284,7 @@ impl EditMode for HexMode { } i = i + 1; } - /* - * 12 == "
: " - * i / col_size for the extra space between columns - * i * 3 for 3 characters per byte - * + 1 for padding.. - */ - let hex_line_width = 12 + i / col_size + i * 3 + 1; - let padding = format!("{: >line_width$}", "", line_width = width as usize - hex_line_width - i); - format!("0x{:08x}: {}{}{}", start, text, padding, ascii_text).to_owned() + format!("0x{:08x}: {}", start, text).to_owned() } fn element_width(&self, display_width: u16) -> u64 { (display_width as u64 - 13) / 17 * 4 @@ -272,6 +295,7 @@ impl EditMode for HexMode { fn inc_sub_elem(&mut self, amount: u64) { self.sub_elem_idx = self.sub_elem_idx + amount as u8; } + fn name(&self) -> &str { &"Hex" } } struct Program<'a, 'b> { @@ -289,13 +313,14 @@ struct Program<'a, 'b> { edits: Edits, status: String, edit_views: Vec<&'b mut EditMode>, - current_edit_idx: usize + current_edit_idx: usize, + ascii_mode: &'b mut EditMode //screen: AlternateScreen> } impl <'a, 'b> Program<'a, 'b> { fn lines_to_draw(&self) -> u64 { - self.view_byte_height() / self.edit_views.len() as u64 + self.view_byte_height() / (self.edit_views.len() as u64) } fn seek_to(&mut self, dest: u64) { self.cursor = dest; @@ -357,6 +382,15 @@ impl <'a, 'b> Program<'a, 'b> { self.seek = self.cursor - (self.cursor % bytes_per_line); } } + + fn current_edit_view(&self) -> &EditMode { + if self.current_edit_idx == self.edit_views.len() { + self.ascii_mode + } else { + self.edit_views[self.current_edit_idx] +// *self.edit_views.get_mut(self.current_edit_idx).unwrap() + } + } } fn launch_interface(w: u16, h: u16, filename: String) { @@ -394,7 +428,8 @@ fn launch_interface(w: u16, h: u16, filename: String) { &mut hexmode, &mut binmode ], - current_edit_idx: 0 + current_edit_idx: 0, + ascii_mode: &mut ASCIIMode {} }; tcsetattr(0, TCSANOW, &state.new_term).unwrap(); @@ -412,7 +447,8 @@ fn launch_interface(w: u16, h: u16, filename: String) { enum Mode { Edit, - ReadAddress + ReadAddress, + ViewSelection } fn interface_loop(state: &mut Program) { @@ -422,6 +458,23 @@ fn interface_loop(state: &mut Program) { for input in stdin.events() { match state.state { + Mode::ViewSelection => { + match input.unwrap() { + Event::Key(Key::Up) => { + + } + Event::Key(Key::Down) => { + + } + Event::Key(Key::Char(' ')) => { + + } + Event::Key(Key::Esc) => { + state.state = Mode::Edit + } + _ => { } + } + } Mode::Edit => { match input.unwrap() { Event::Key(Key::Char('\n')) => { @@ -467,17 +520,27 @@ fn interface_loop(state: &mut Program) { state.seek -= amount; } } + Event::Key(Key::Ctrl('a')) => { + state.status = "asf".to_string(); + state.state = Mode::ViewSelection; + } Event::Key(Key::Char('q')) => { break; } + // nahhhh.. + Event::Key(Key::Ctrl('c')) => { + state.status = "caught ctrl-c?".to_string(); + } Event::Key(Key::Ctrl('\t')) => { - // switch to previous edit mode + state.current_edit_idx -= 1; + state.current_edit_idx = state.current_edit_idx % (state.edit_views.len() + 1); } Event::Key(Key::Ctrl(x)) => { state.status = format!("ctrl {}", x); } Event::Key(Key::Char('\t')) => { - // switch to next edit mode + state.current_edit_idx += 1; + state.current_edit_idx = state.current_edit_idx % (state.edit_views.len() + 1); } // would prefer shift+t Event::Unsupported(vec) => { @@ -628,10 +691,36 @@ fn render_interface(state: &mut Program) { for i in 0..state.lines_to_draw() { for j in 0..state.edit_views.len() { - let view = &state.edit_views[j]; + let view = state.edit_views.get(j).unwrap(); let slice_start = width * i; let slice_end = slice_start + width; - write!(iface, "{}", view.render_bytes(state.cursor, state.width, start as u64 + slice_start, buffer[(slice_start as usize)..(slice_end as usize)].iter())).unwrap(); + let line = view.render_bytes( + state.cursor, + state.width, + view.name() == state.current_edit_view().name(), + start as u64 + slice_start, + buffer[(slice_start as usize)..(slice_end as usize)].iter() + ); + write!(iface, "{}", line).unwrap(); + if j == 0 { + // ripped from HexMode display + /* + * 12 == "
: " + * i / col_size for the extra space between columns + * i * 3 for 3 characters per byte + * + 1 for padding.. + */ + let hex_line_width = 12 + width / 4 + width * 3 + 1; + let padding = format!("{: >line_width$}", "", line_width = state.width as usize - hex_line_width as usize - width as usize); + write!(iface, "{}", padding); + write!(iface, " {}", state.ascii_mode.render_bytes( + state.cursor, + state.width, + state.ascii_mode.name() == state.current_edit_view().name(), + start as u64 + slice_start, + buffer[(slice_start as usize)..(slice_end as usize)].iter() + )); + } if i < state.lines_to_draw() - 1 || j < (state.edit_views.len() - 1) { write!(iface, "\n").unwrap(); } @@ -650,6 +739,12 @@ fn render_interface(state: &mut Program) { write!(state.screen, "{}{:-^2$}", cursor::Goto(xmid-12, ymid+2), "", MODAL_WIDTH).unwrap(); write!(state.screen, "{}{}", cursor::Goto(xmid-9, ymid-0), state.input_buf.iter().cloned().collect::()).unwrap(); } + Mode::ViewSelection => { + let xmid = state.width as u16 / 2; + let ymid = state.height as u16 / 2; + write!(state.screen, "{}{:-^2$}", cursor::Goto(xmid-12, ymid - 4), "", MODAL_WIDTH).unwrap(); + write!(state.screen, "{}|{:-^2$}|", cursor::Goto(xmid-12, ymid - 3), "Select views", MODAL_WIDTH - 2).unwrap(); + } _ => {} } state.screen.flush().unwrap(); -- cgit v1.1