objdiff-cli diff: Add horizontal scrolling

This commit is contained in:
Luke Street 2024-03-01 01:30:33 -07:00
parent cb13638e07
commit 3b1249e1ab
1 changed files with 86 additions and 39 deletions

View File

@ -125,7 +125,10 @@ pub fn run(args: Args) -> Result<()> {
click_xy: None, click_xy: None,
left_highlight: HighlightKind::None, left_highlight: HighlightKind::None,
right_highlight: HighlightKind::None, right_highlight: HighlightKind::None,
scroll: 0, scroll_x: 0,
scroll_state_x: ScrollbarState::default(),
scroll_y: 0,
scroll_state_y: ScrollbarState::default(),
per_page: 0, per_page: 0,
num_rows: 0, num_rows: 0,
symbol_name: args.symbol.clone(), symbol_name: args.symbol.clone(),
@ -136,7 +139,6 @@ pub fn run(args: Args) -> Result<()> {
right_sym: None, right_sym: None,
reload_time: None, reload_time: None,
time_format, time_format,
scroll_state: Default::default(),
}); });
state.reload()?; state.reload()?;
@ -195,7 +197,10 @@ struct FunctionDiffUi {
click_xy: Option<(u16, u16)>, click_xy: Option<(u16, u16)>,
left_highlight: HighlightKind, left_highlight: HighlightKind,
right_highlight: HighlightKind, right_highlight: HighlightKind,
scroll: usize, scroll_x: usize,
scroll_state_x: ScrollbarState,
scroll_y: usize,
scroll_state_y: ScrollbarState,
per_page: usize, per_page: usize,
num_rows: usize, num_rows: usize,
symbol_name: String, symbol_name: String,
@ -206,7 +211,6 @@ struct FunctionDiffUi {
right_sym: Option<ObjSymbol>, right_sym: Option<ObjSymbol>,
reload_time: Option<time::OffsetDateTime>, reload_time: Option<time::OffsetDateTime>,
time_format: Vec<time::format_description::FormatItem<'static>>, time_format: Vec<time::format_description::FormatItem<'static>>,
scroll_state: ScrollbarState,
} }
enum FunctionDiffResult { enum FunctionDiffResult {
@ -233,12 +237,13 @@ impl FunctionDiffUi {
]) ])
.split(chunks[1]); .split(chunks[1]);
self.per_page = chunks[1].height.saturating_sub(1) as usize; self.per_page = chunks[1].height.saturating_sub(2) as usize;
let max_scroll = self.num_rows.saturating_sub(self.per_page); let max_scroll_y = self.num_rows.saturating_sub(self.per_page);
if self.scroll > max_scroll { if self.scroll_y > max_scroll_y {
self.scroll = max_scroll; self.scroll_y = max_scroll_y;
} }
self.scroll_state = self.scroll_state.content_length(max_scroll).position(self.scroll); self.scroll_state_y =
self.scroll_state_y.content_length(max_scroll_y).position(self.scroll_y);
let mut line_l = Line::default(); let mut line_l = Line::default();
line_l line_l
@ -268,12 +273,19 @@ impl FunctionDiffUi {
|title: &'static str| Block::new().borders(Borders::TOP).gray().title(title.bold()); |title: &'static str| Block::new().borders(Borders::TOP).gray().title(title.bold());
let mut left_highlight = None; let mut left_highlight = None;
let mut max_width = 0;
if let Some(symbol) = &self.left_sym { if let Some(symbol) = &self.left_sym {
// Render left column // Render left column
let mut text = Text::default(); let mut text = Text::default();
let rect = margin_top(content_chunks[0], 1); let rect = content_chunks[0].inner(&Margin::new(0, 1));
let h = self.print_sym(&mut text, symbol, rect, &self.left_highlight); let h = self.print_sym(&mut text, symbol, rect, &self.left_highlight);
f.render_widget(Paragraph::new(text).block(create_block("TARGET")), content_chunks[0]); max_width = max_width.max(text.width());
f.render_widget(
Paragraph::new(text)
.block(create_block("TARGET"))
.scroll((0, self.scroll_x as u16)),
content_chunks[0],
);
if let Some(h) = h { if let Some(h) = h {
left_highlight = Some(h); left_highlight = Some(h);
} }
@ -283,25 +295,49 @@ impl FunctionDiffUi {
if let Some(symbol) = &self.right_sym { if let Some(symbol) = &self.right_sym {
// Render margin // Render margin
let mut text = Text::default(); let mut text = Text::default();
let rect = margin_top(content_chunks[1], 1).inner(&Margin::new(1, 0)); let rect = content_chunks[1].inner(&Margin::new(1, 1));
self.print_margin(&mut text, symbol, rect); self.print_margin(&mut text, symbol, rect);
f.render_widget(text, rect); f.render_widget(text, rect);
// Render right column // Render right column
let mut text = Text::default(); let mut text = Text::default();
let rect = margin_top(content_chunks[2], 1); let rect = content_chunks[2].inner(&Margin::new(0, 1));
let h = self.print_sym(&mut text, symbol, rect, &self.right_highlight); let h = self.print_sym(&mut text, symbol, rect, &self.right_highlight);
f.render_widget(Paragraph::new(text).block(create_block("CURRENT")), content_chunks[2]); max_width = max_width.max(text.width());
f.render_widget(
Paragraph::new(text)
.block(create_block("CURRENT"))
.scroll((0, self.scroll_x as u16)),
content_chunks[2],
);
if let Some(h) = h { if let Some(h) = h {
right_highlight = Some(h); right_highlight = Some(h);
} }
} }
// Render scrollbar let max_scroll_x =
max_width.saturating_sub(content_chunks[0].width.min(content_chunks[2].width) as usize);
if self.scroll_x > max_scroll_x {
self.scroll_x = max_scroll_x;
}
self.scroll_state_x =
self.scroll_state_x.content_length(max_scroll_x).position(self.scroll_x);
// Render scrollbars
f.render_stateful_widget( f.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::VerticalRight).begin_symbol(None).end_symbol(None), Scrollbar::new(ScrollbarOrientation::VerticalRight).begin_symbol(None).end_symbol(None),
margin_top(chunks[1], 1), chunks[1].inner(&Margin::new(0, 1)),
&mut self.scroll_state, &mut self.scroll_state_y,
);
f.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::HorizontalBottom).thumb_symbol(""),
content_chunks[0],
&mut self.scroll_state_x,
);
f.render_stateful_widget(
Scrollbar::new(ScrollbarOrientation::HorizontalBottom).thumb_symbol(""),
content_chunks[2],
&mut self.scroll_state_x,
); );
if let Some(new_highlight) = left_highlight { if let Some(new_highlight) = left_highlight {
@ -346,57 +382,57 @@ impl FunctionDiffUi {
KeyCode::Esc | KeyCode::Char('q') => return FunctionDiffResult::Break, KeyCode::Esc | KeyCode::Char('q') => return FunctionDiffResult::Break,
// Page up // Page up
KeyCode::PageUp => { KeyCode::PageUp => {
self.scroll = self.scroll.saturating_sub(self.per_page); self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
self.redraw = true; self.redraw = true;
} }
// Page up (shift + space) // Page up (shift + space)
KeyCode::Char(' ') if event.modifiers.contains(KeyModifiers::SHIFT) => { KeyCode::Char(' ') if event.modifiers.contains(KeyModifiers::SHIFT) => {
self.scroll = self.scroll.saturating_sub(self.per_page); self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
self.redraw = true; self.redraw = true;
} }
// Page down // Page down
KeyCode::Char(' ') | KeyCode::PageDown => { KeyCode::Char(' ') | KeyCode::PageDown => {
self.scroll += self.per_page; self.scroll_y += self.per_page;
self.redraw = true; self.redraw = true;
} }
// Page down (ctrl + f) // Page down (ctrl + f)
KeyCode::Char('f') if event.modifiers.contains(KeyModifiers::CONTROL) => { KeyCode::Char('f') if event.modifiers.contains(KeyModifiers::CONTROL) => {
self.scroll += self.per_page; self.scroll_y += self.per_page;
self.redraw = true; self.redraw = true;
} }
// Page up (ctrl + b) // Page up (ctrl + b)
KeyCode::Char('b') if event.modifiers.contains(KeyModifiers::CONTROL) => { KeyCode::Char('b') if event.modifiers.contains(KeyModifiers::CONTROL) => {
self.scroll = self.scroll.saturating_sub(self.per_page); self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
self.redraw = true; self.redraw = true;
} }
// Half page down (ctrl + d) // Half page down (ctrl + d)
KeyCode::Char('d') if event.modifiers.contains(KeyModifiers::CONTROL) => { KeyCode::Char('d') if event.modifiers.contains(KeyModifiers::CONTROL) => {
self.scroll += self.per_page / 2; self.scroll_y += self.per_page / 2;
self.redraw = true; self.redraw = true;
} }
// Half page up (ctrl + u) // Half page up (ctrl + u)
KeyCode::Char('u') if event.modifiers.contains(KeyModifiers::CONTROL) => { KeyCode::Char('u') if event.modifiers.contains(KeyModifiers::CONTROL) => {
self.scroll = self.scroll.saturating_sub(self.per_page / 2); self.scroll_y = self.scroll_y.saturating_sub(self.per_page / 2);
self.redraw = true; self.redraw = true;
} }
// Scroll down // Scroll down
KeyCode::Down | KeyCode::Char('j') => { KeyCode::Down | KeyCode::Char('j') => {
self.scroll += 1; self.scroll_y += 1;
self.redraw = true; self.redraw = true;
} }
// Scroll up // Scroll up
KeyCode::Up | KeyCode::Char('k') => { KeyCode::Up | KeyCode::Char('k') => {
self.scroll = self.scroll.saturating_sub(1); self.scroll_y = self.scroll_y.saturating_sub(1);
self.redraw = true; self.redraw = true;
} }
// Scroll to start // Scroll to start
KeyCode::Char('g') => { KeyCode::Char('g') => {
self.scroll = 0; self.scroll_y = 0;
self.redraw = true; self.redraw = true;
} }
// Scroll to end // Scroll to end
KeyCode::Char('G') => { KeyCode::Char('G') => {
self.scroll = self.num_rows; self.scroll_y = self.num_rows;
self.redraw = true; self.redraw = true;
} }
// Reload // Reload
@ -404,16 +440,34 @@ impl FunctionDiffUi {
self.redraw = true; self.redraw = true;
return FunctionDiffResult::Reload; return FunctionDiffResult::Reload;
} }
// Scroll right
KeyCode::Right | KeyCode::Char('l') => {
self.scroll_x += 1;
self.redraw = true;
}
// Scroll left
KeyCode::Left | KeyCode::Char('h') => {
self.scroll_x = self.scroll_x.saturating_sub(1);
self.redraw = true;
}
_ => {} _ => {}
} }
} }
Event::Mouse(event) => match event.kind { Event::Mouse(event) => match event.kind {
MouseEventKind::ScrollDown => { MouseEventKind::ScrollDown => {
self.scroll += 3; self.scroll_y += 3;
self.redraw = true; self.redraw = true;
} }
MouseEventKind::ScrollUp => { MouseEventKind::ScrollUp => {
self.scroll = self.scroll.saturating_sub(3); self.scroll_y = self.scroll_y.saturating_sub(3);
self.redraw = true;
}
MouseEventKind::ScrollRight => {
self.scroll_x += 3;
self.redraw = true;
}
MouseEventKind::ScrollLeft => {
self.scroll_x = self.scroll_x.saturating_sub(3);
self.redraw = true; self.redraw = true;
} }
MouseEventKind::Down(MouseButton::Left) => { MouseEventKind::Down(MouseButton::Left) => {
@ -440,7 +494,7 @@ impl FunctionDiffUi {
let base_addr = symbol.address as u32; let base_addr = symbol.address as u32;
let mut new_highlight = None; let mut new_highlight = None;
for (y, ins_diff) in for (y, ins_diff) in
symbol.instructions.iter().skip(self.scroll).take(rect.height as usize).enumerate() symbol.instructions.iter().skip(self.scroll_y).take(rect.height as usize).enumerate()
{ {
let mut sx = rect.x; let mut sx = rect.x;
let sy = rect.y + y as u16; let sy = rect.y + y as u16;
@ -530,7 +584,7 @@ impl FunctionDiffUi {
} }
fn print_margin(&self, out: &mut Text, symbol: &ObjSymbol, rect: Rect) { fn print_margin(&self, out: &mut Text, symbol: &ObjSymbol, rect: Rect) {
for ins_diff in symbol.instructions.iter().skip(self.scroll).take(rect.height as usize) { for ins_diff in symbol.instructions.iter().skip(self.scroll_y).take(rect.height as usize) {
if ins_diff.kind != ObjInsDiffKind::None { if ins_diff.kind != ObjInsDiffKind::None {
out.lines.push(Line::raw(match ins_diff.kind { out.lines.push(Line::raw(match ins_diff.kind {
ObjInsDiffKind::Delete => "<", ObjInsDiffKind::Delete => "<",
@ -591,10 +645,3 @@ pub fn match_percent_color(match_percent: f32) -> Color {
Color::LightRed Color::LightRed
} }
} }
#[inline]
fn margin_top(mut rect: Rect, n: u16) -> Rect {
rect.y = rect.y.saturating_add(n);
rect.height = rect.height.saturating_sub(n);
rect
}