Skip to content

Commit 3b1249e

Browse files
committed
objdiff-cli diff: Add horizontal scrolling
1 parent cb13638 commit 3b1249e

File tree

1 file changed

+86
-39
lines changed

1 file changed

+86
-39
lines changed

objdiff-cli/src/cmd/diff.rs

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ pub fn run(args: Args) -> Result<()> {
125125
click_xy: None,
126126
left_highlight: HighlightKind::None,
127127
right_highlight: HighlightKind::None,
128-
scroll: 0,
128+
scroll_x: 0,
129+
scroll_state_x: ScrollbarState::default(),
130+
scroll_y: 0,
131+
scroll_state_y: ScrollbarState::default(),
129132
per_page: 0,
130133
num_rows: 0,
131134
symbol_name: args.symbol.clone(),
@@ -136,7 +139,6 @@ pub fn run(args: Args) -> Result<()> {
136139
right_sym: None,
137140
reload_time: None,
138141
time_format,
139-
scroll_state: Default::default(),
140142
});
141143
state.reload()?;
142144

@@ -195,7 +197,10 @@ struct FunctionDiffUi {
195197
click_xy: Option<(u16, u16)>,
196198
left_highlight: HighlightKind,
197199
right_highlight: HighlightKind,
198-
scroll: usize,
200+
scroll_x: usize,
201+
scroll_state_x: ScrollbarState,
202+
scroll_y: usize,
203+
scroll_state_y: ScrollbarState,
199204
per_page: usize,
200205
num_rows: usize,
201206
symbol_name: String,
@@ -206,7 +211,6 @@ struct FunctionDiffUi {
206211
right_sym: Option<ObjSymbol>,
207212
reload_time: Option<time::OffsetDateTime>,
208213
time_format: Vec<time::format_description::FormatItem<'static>>,
209-
scroll_state: ScrollbarState,
210214
}
211215

212216
enum FunctionDiffResult {
@@ -233,12 +237,13 @@ impl FunctionDiffUi {
233237
])
234238
.split(chunks[1]);
235239

236-
self.per_page = chunks[1].height.saturating_sub(1) as usize;
237-
let max_scroll = self.num_rows.saturating_sub(self.per_page);
238-
if self.scroll > max_scroll {
239-
self.scroll = max_scroll;
240+
self.per_page = chunks[1].height.saturating_sub(2) as usize;
241+
let max_scroll_y = self.num_rows.saturating_sub(self.per_page);
242+
if self.scroll_y > max_scroll_y {
243+
self.scroll_y = max_scroll_y;
240244
}
241-
self.scroll_state = self.scroll_state.content_length(max_scroll).position(self.scroll);
245+
self.scroll_state_y =
246+
self.scroll_state_y.content_length(max_scroll_y).position(self.scroll_y);
242247

243248
let mut line_l = Line::default();
244249
line_l
@@ -268,12 +273,19 @@ impl FunctionDiffUi {
268273
|title: &'static str| Block::new().borders(Borders::TOP).gray().title(title.bold());
269274

270275
let mut left_highlight = None;
276+
let mut max_width = 0;
271277
if let Some(symbol) = &self.left_sym {
272278
// Render left column
273279
let mut text = Text::default();
274-
let rect = margin_top(content_chunks[0], 1);
280+
let rect = content_chunks[0].inner(&Margin::new(0, 1));
275281
let h = self.print_sym(&mut text, symbol, rect, &self.left_highlight);
276-
f.render_widget(Paragraph::new(text).block(create_block("TARGET")), content_chunks[0]);
282+
max_width = max_width.max(text.width());
283+
f.render_widget(
284+
Paragraph::new(text)
285+
.block(create_block("TARGET"))
286+
.scroll((0, self.scroll_x as u16)),
287+
content_chunks[0],
288+
);
277289
if let Some(h) = h {
278290
left_highlight = Some(h);
279291
}
@@ -283,25 +295,49 @@ impl FunctionDiffUi {
283295
if let Some(symbol) = &self.right_sym {
284296
// Render margin
285297
let mut text = Text::default();
286-
let rect = margin_top(content_chunks[1], 1).inner(&Margin::new(1, 0));
298+
let rect = content_chunks[1].inner(&Margin::new(1, 1));
287299
self.print_margin(&mut text, symbol, rect);
288300
f.render_widget(text, rect);
289301

290302
// Render right column
291303
let mut text = Text::default();
292-
let rect = margin_top(content_chunks[2], 1);
304+
let rect = content_chunks[2].inner(&Margin::new(0, 1));
293305
let h = self.print_sym(&mut text, symbol, rect, &self.right_highlight);
294-
f.render_widget(Paragraph::new(text).block(create_block("CURRENT")), content_chunks[2]);
306+
max_width = max_width.max(text.width());
307+
f.render_widget(
308+
Paragraph::new(text)
309+
.block(create_block("CURRENT"))
310+
.scroll((0, self.scroll_x as u16)),
311+
content_chunks[2],
312+
);
295313
if let Some(h) = h {
296314
right_highlight = Some(h);
297315
}
298316
}
299317

300-
// Render scrollbar
318+
let max_scroll_x =
319+
max_width.saturating_sub(content_chunks[0].width.min(content_chunks[2].width) as usize);
320+
if self.scroll_x > max_scroll_x {
321+
self.scroll_x = max_scroll_x;
322+
}
323+
self.scroll_state_x =
324+
self.scroll_state_x.content_length(max_scroll_x).position(self.scroll_x);
325+
326+
// Render scrollbars
301327
f.render_stateful_widget(
302328
Scrollbar::new(ScrollbarOrientation::VerticalRight).begin_symbol(None).end_symbol(None),
303-
margin_top(chunks[1], 1),
304-
&mut self.scroll_state,
329+
chunks[1].inner(&Margin::new(0, 1)),
330+
&mut self.scroll_state_y,
331+
);
332+
f.render_stateful_widget(
333+
Scrollbar::new(ScrollbarOrientation::HorizontalBottom).thumb_symbol("■"),
334+
content_chunks[0],
335+
&mut self.scroll_state_x,
336+
);
337+
f.render_stateful_widget(
338+
Scrollbar::new(ScrollbarOrientation::HorizontalBottom).thumb_symbol("■"),
339+
content_chunks[2],
340+
&mut self.scroll_state_x,
305341
);
306342

307343
if let Some(new_highlight) = left_highlight {
@@ -346,74 +382,92 @@ impl FunctionDiffUi {
346382
KeyCode::Esc | KeyCode::Char('q') => return FunctionDiffResult::Break,
347383
// Page up
348384
KeyCode::PageUp => {
349-
self.scroll = self.scroll.saturating_sub(self.per_page);
385+
self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
350386
self.redraw = true;
351387
}
352388
// Page up (shift + space)
353389
KeyCode::Char(' ') if event.modifiers.contains(KeyModifiers::SHIFT) => {
354-
self.scroll = self.scroll.saturating_sub(self.per_page);
390+
self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
355391
self.redraw = true;
356392
}
357393
// Page down
358394
KeyCode::Char(' ') | KeyCode::PageDown => {
359-
self.scroll += self.per_page;
395+
self.scroll_y += self.per_page;
360396
self.redraw = true;
361397
}
362398
// Page down (ctrl + f)
363399
KeyCode::Char('f') if event.modifiers.contains(KeyModifiers::CONTROL) => {
364-
self.scroll += self.per_page;
400+
self.scroll_y += self.per_page;
365401
self.redraw = true;
366402
}
367403
// Page up (ctrl + b)
368404
KeyCode::Char('b') if event.modifiers.contains(KeyModifiers::CONTROL) => {
369-
self.scroll = self.scroll.saturating_sub(self.per_page);
405+
self.scroll_y = self.scroll_y.saturating_sub(self.per_page);
370406
self.redraw = true;
371407
}
372408
// Half page down (ctrl + d)
373409
KeyCode::Char('d') if event.modifiers.contains(KeyModifiers::CONTROL) => {
374-
self.scroll += self.per_page / 2;
410+
self.scroll_y += self.per_page / 2;
375411
self.redraw = true;
376412
}
377413
// Half page up (ctrl + u)
378414
KeyCode::Char('u') if event.modifiers.contains(KeyModifiers::CONTROL) => {
379-
self.scroll = self.scroll.saturating_sub(self.per_page / 2);
415+
self.scroll_y = self.scroll_y.saturating_sub(self.per_page / 2);
380416
self.redraw = true;
381417
}
382418
// Scroll down
383419
KeyCode::Down | KeyCode::Char('j') => {
384-
self.scroll += 1;
420+
self.scroll_y += 1;
385421
self.redraw = true;
386422
}
387423
// Scroll up
388424
KeyCode::Up | KeyCode::Char('k') => {
389-
self.scroll = self.scroll.saturating_sub(1);
425+
self.scroll_y = self.scroll_y.saturating_sub(1);
390426
self.redraw = true;
391427
}
392428
// Scroll to start
393429
KeyCode::Char('g') => {
394-
self.scroll = 0;
430+
self.scroll_y = 0;
395431
self.redraw = true;
396432
}
397433
// Scroll to end
398434
KeyCode::Char('G') => {
399-
self.scroll = self.num_rows;
435+
self.scroll_y = self.num_rows;
400436
self.redraw = true;
401437
}
402438
// Reload
403439
KeyCode::Char('r') => {
404440
self.redraw = true;
405441
return FunctionDiffResult::Reload;
406442
}
443+
// Scroll right
444+
KeyCode::Right | KeyCode::Char('l') => {
445+
self.scroll_x += 1;
446+
self.redraw = true;
447+
}
448+
// Scroll left
449+
KeyCode::Left | KeyCode::Char('h') => {
450+
self.scroll_x = self.scroll_x.saturating_sub(1);
451+
self.redraw = true;
452+
}
407453
_ => {}
408454
}
409455
}
410456
Event::Mouse(event) => match event.kind {
411457
MouseEventKind::ScrollDown => {
412-
self.scroll += 3;
458+
self.scroll_y += 3;
413459
self.redraw = true;
414460
}
415461
MouseEventKind::ScrollUp => {
416-
self.scroll = self.scroll.saturating_sub(3);
462+
self.scroll_y = self.scroll_y.saturating_sub(3);
463+
self.redraw = true;
464+
}
465+
MouseEventKind::ScrollRight => {
466+
self.scroll_x += 3;
467+
self.redraw = true;
468+
}
469+
MouseEventKind::ScrollLeft => {
470+
self.scroll_x = self.scroll_x.saturating_sub(3);
417471
self.redraw = true;
418472
}
419473
MouseEventKind::Down(MouseButton::Left) => {
@@ -440,7 +494,7 @@ impl FunctionDiffUi {
440494
let base_addr = symbol.address as u32;
441495
let mut new_highlight = None;
442496
for (y, ins_diff) in
443-
symbol.instructions.iter().skip(self.scroll).take(rect.height as usize).enumerate()
497+
symbol.instructions.iter().skip(self.scroll_y).take(rect.height as usize).enumerate()
444498
{
445499
let mut sx = rect.x;
446500
let sy = rect.y + y as u16;
@@ -530,7 +584,7 @@ impl FunctionDiffUi {
530584
}
531585

532586
fn print_margin(&self, out: &mut Text, symbol: &ObjSymbol, rect: Rect) {
533-
for ins_diff in symbol.instructions.iter().skip(self.scroll).take(rect.height as usize) {
587+
for ins_diff in symbol.instructions.iter().skip(self.scroll_y).take(rect.height as usize) {
534588
if ins_diff.kind != ObjInsDiffKind::None {
535589
out.lines.push(Line::raw(match ins_diff.kind {
536590
ObjInsDiffKind::Delete => "<",
@@ -591,10 +645,3 @@ pub fn match_percent_color(match_percent: f32) -> Color {
591645
Color::LightRed
592646
}
593647
}
594-
595-
#[inline]
596-
fn margin_top(mut rect: Rect, n: u16) -> Rect {
597-
rect.y = rect.y.saturating_add(n);
598-
rect.height = rect.height.saturating_sub(n);
599-
rect
600-
}

0 commit comments

Comments
 (0)