Skip to content

Commit 2d8b481

Browse files
WizardOhio24Stephan Dilly
authored and
Stephan Dilly
committed
Fix select branch list scrolling (#380)
Closes #368
1 parent 22d9417 commit 2d8b481

File tree

1 file changed

+99
-77
lines changed

1 file changed

+99
-77
lines changed

src/components/select_branch.rs

+99-77
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use super::{
33
DrawableComponent,
44
};
55
use crate::{
6+
components::ScrollType,
67
keys::SharedKeyConfig,
78
queue::{Action, InternalEvent, NeedsUpdate, Queue},
8-
strings, ui,
9+
strings,
10+
ui::{self, calc_scroll_top},
911
};
1012
use asyncgit::{
1113
sync::{
@@ -14,7 +16,7 @@ use asyncgit::{
1416
CWD,
1517
};
1618
use crossterm::event::Event;
17-
use std::{cmp, convert::TryFrom};
19+
use std::{cell::Cell, convert::TryInto};
1820
use tui::{
1921
backend::Backend,
2022
layout::{Alignment, Rect},
@@ -32,6 +34,7 @@ pub struct SelectBranchComponent {
3234
branch_names: Vec<BranchForDisplay>,
3335
visible: bool,
3436
selection: u16,
37+
scroll_top: Cell<usize>,
3538
queue: Queue,
3639
theme: SharedTheme,
3740
key_config: SharedKeyConfig,
@@ -56,22 +59,28 @@ impl DrawableComponent for SelectBranchComponent {
5659
ui::rect_inside(MIN_SIZE, f.size().into(), area);
5760
let area = area.intersection(rect);
5861

59-
let scroll_threshold = area.height / 3;
60-
let scroll =
61-
self.selection.saturating_sub(scroll_threshold);
62+
let height_in_lines =
63+
(area.height as usize).saturating_sub(2);
64+
65+
self.scroll_top.set(calc_scroll_top(
66+
self.scroll_top.get(),
67+
height_in_lines,
68+
self.selection as usize,
69+
));
6270

6371
f.render_widget(Clear, area);
6472
f.render_widget(
65-
Paragraph::new(
66-
self.get_text(&self.theme, area.width)?,
67-
)
73+
Paragraph::new(self.get_text(
74+
&self.theme,
75+
area.width,
76+
height_in_lines,
77+
)?)
6878
.block(
6979
Block::default()
7080
.title(strings::SELECT_BRANCH_POPUP_MSG)
7181
.borders(Borders::ALL)
7282
.border_type(BorderType::Thick),
7383
)
74-
.scroll((scroll, 0))
7584
.alignment(Alignment::Left),
7685
area,
7786
);
@@ -135,9 +144,9 @@ impl Component for SelectBranchComponent {
135144
if e == self.key_config.exit_popup {
136145
self.hide()
137146
} else if e == self.key_config.move_down {
138-
self.move_selection(true)
147+
return self.move_selection(ScrollType::Up);
139148
} else if e == self.key_config.move_up {
140-
self.move_selection(false)
149+
return self.move_selection(ScrollType::Down);
141150
} else if e == self.key_config.enter {
142151
if let Err(e) = self.switch_to_selected_branch() {
143152
log::error!("switch branch error: {}", e);
@@ -211,6 +220,7 @@ impl SelectBranchComponent {
211220
branch_names: Vec::new(),
212221
visible: false,
213222
selection: 0,
223+
scroll_top: Cell::new(0),
214224
queue,
215225
theme,
216226
key_config,
@@ -248,28 +258,31 @@ impl SelectBranchComponent {
248258
}
249259

250260
///
251-
fn move_selection(&mut self, inc: bool) {
252-
let mut new_selection = self.selection;
253-
254-
new_selection = if inc {
255-
new_selection.saturating_add(1)
256-
} else {
257-
new_selection.saturating_sub(1)
261+
fn move_selection(&mut self, scroll: ScrollType) -> Result<bool> {
262+
let num_branches: u16 = self.branch_names.len().try_into()?;
263+
let num_branches = num_branches.saturating_sub(1);
264+
265+
let mut new_selection = match scroll {
266+
ScrollType::Up => self.selection.saturating_add(1),
267+
ScrollType::Down => self.selection.saturating_sub(1),
268+
_ => self.selection,
258269
};
259-
new_selection = cmp::max(new_selection, 0);
260270

261-
if let Ok(max) =
262-
u16::try_from(self.branch_names.len().saturating_sub(1))
263-
{
264-
self.selection = cmp::min(new_selection, max);
271+
if new_selection > num_branches {
272+
new_selection = num_branches;
265273
}
274+
275+
self.selection = new_selection;
276+
277+
Ok(true)
266278
}
267279

268280
/// Get branches to display
269281
fn get_text(
270282
&self,
271283
theme: &SharedTheme,
272284
width_available: u16,
285+
height: usize,
273286
) -> Result<Text> {
274287
const COMMIT_HASH_LENGTH: usize = 8;
275288
const IS_HEAD_STAR_LENGTH: usize = 3; // "* "
@@ -286,7 +299,12 @@ impl SelectBranchComponent {
286299
.saturating_sub(THREE_DOTS_LENGTH);
287300
let mut txt = Vec::new();
288301

289-
for (i, displaybranch) in self.branch_names.iter().enumerate()
302+
for (i, displaybranch) in self
303+
.branch_names
304+
.iter()
305+
.skip(self.scroll_top.get())
306+
.take(height)
307+
.enumerate()
290308
{
291309
let mut commit_message =
292310
displaybranch.top_commit_message.clone();
@@ -310,63 +328,67 @@ impl SelectBranchComponent {
310328
let is_head_str =
311329
if displaybranch.is_head { "*" } else { " " };
312330

313-
txt.push(Spans::from(if self.selection as usize == i {
314-
vec![
315-
Span::styled(
316-
format!("{} ", is_head_str),
317-
theme.commit_author(true),
318-
),
319-
Span::styled(
320-
format!(
321-
">{:w$} ",
322-
branch_name,
323-
w = branch_name_length
331+
txt.push(Spans::from(
332+
if self.selection as usize - self.scroll_top.get()
333+
== i
334+
{
335+
vec![
336+
Span::styled(
337+
format!("{} ", is_head_str),
338+
theme.commit_author(true),
339+
),
340+
Span::styled(
341+
format!(
342+
">{:w$} ",
343+
branch_name,
344+
w = branch_name_length
345+
),
346+
theme.commit_author(true),
347+
),
348+
Span::styled(
349+
format!(
350+
"{} ",
351+
displaybranch
352+
.top_commit
353+
.get_short_string()
354+
),
355+
theme.commit_hash(true),
324356
),
325-
theme.commit_author(true),
326-
),
327-
Span::styled(
328-
format!(
329-
"{} ",
330-
displaybranch
331-
.top_commit
332-
.get_short_string()
357+
Span::styled(
358+
commit_message.to_string(),
359+
theme.text(true, true),
333360
),
334-
theme.commit_hash(true),
335-
),
336-
Span::styled(
337-
commit_message.to_string(),
338-
theme.text(true, true),
339-
),
340-
]
341-
} else {
342-
vec![
343-
Span::styled(
344-
format!("{} ", is_head_str),
345-
theme.commit_author(false),
346-
),
347-
Span::styled(
348-
format!(
349-
" {:w$} ",
350-
branch_name,
351-
w = branch_name_length
361+
]
362+
} else {
363+
vec![
364+
Span::styled(
365+
format!("{} ", is_head_str),
366+
theme.commit_author(false),
352367
),
353-
theme.commit_author(false),
354-
),
355-
Span::styled(
356-
format!(
357-
"{} ",
358-
displaybranch
359-
.top_commit
360-
.get_short_string()
368+
Span::styled(
369+
format!(
370+
" {:w$} ",
371+
branch_name,
372+
w = branch_name_length
373+
),
374+
theme.commit_author(false),
375+
),
376+
Span::styled(
377+
format!(
378+
"{} ",
379+
displaybranch
380+
.top_commit
381+
.get_short_string()
382+
),
383+
theme.commit_hash(false),
361384
),
362-
theme.commit_hash(false),
363-
),
364-
Span::styled(
365-
commit_message.to_string(),
366-
theme.text(true, false),
367-
),
368-
]
369-
}));
385+
Span::styled(
386+
commit_message.to_string(),
387+
theme.text(true, false),
388+
),
389+
]
390+
},
391+
));
370392
}
371393

372394
Ok(Text::from(txt))

0 commit comments

Comments
 (0)