support jumping to end in log (#43)

This commit is contained in:
Stephan Dilly 2020-05-11 14:34:10 +02:00
parent 45ee0e115c
commit fa2aabfee0
2 changed files with 66 additions and 25 deletions

View file

@ -68,7 +68,6 @@ impl StatusTree {
MoveSelection::Down => { MoveSelection::Down => {
self.selection_updown(selection, false) self.selection_updown(selection, false)
} }
MoveSelection::Left => self.selection_left(selection), MoveSelection::Left => self.selection_left(selection),
MoveSelection::Right => { MoveSelection::Right => {
self.selection_right(selection) self.selection_right(selection)

View file

@ -19,6 +19,7 @@ use tui::{
Frame, Frame,
}; };
#[derive(Default)]
struct LogEntry { struct LogEntry {
time: String, time: String,
author: String, author: String,
@ -62,14 +63,49 @@ const STYLE_MSG_SELECTED: Style =
Style::new().fg(Color::Reset).bg(COLOR_SELECTION_BG); Style::new().fg(Color::Reset).bg(COLOR_SELECTION_BG);
static ELEMENTS_PER_LINE: usize = 10; static ELEMENTS_PER_LINE: usize = 10;
static SLICE_SIZE: usize = 1000; static SLICE_SIZE: usize = 1200;
static SLICE_OFFSET_RELOAD_THRESHOLD: usize = 100; static SLICE_OFFSET_RELOAD_THRESHOLD: usize = 100;
///
#[derive(Default)]
struct ItemBatch {
index_offset: usize,
items: Vec<LogEntry>,
}
impl ItemBatch {
fn last_idx(&self) -> usize {
self.index_offset + self.items.len()
}
fn set_items(
&mut self,
start_index: usize,
commits: Vec<CommitInfo>,
) {
self.items.clear();
self.items.extend(commits.into_iter().map(LogEntry::from));
self.index_offset = start_index;
}
fn needs_data(&self, idx: usize, idx_max: usize) -> bool {
let want_min =
idx.saturating_sub(SLICE_OFFSET_RELOAD_THRESHOLD);
let want_max = idx
.saturating_add(SLICE_OFFSET_RELOAD_THRESHOLD)
.min(idx_max);
let needs_data_top = want_min < self.index_offset;
let needs_data_bottom = want_max > self.last_idx();
needs_data_bottom || needs_data_top
}
}
/// ///
pub struct Revlog { pub struct Revlog {
selection: usize, selection: usize,
selection_max: usize, selection_max: usize,
items: Vec<LogEntry>, items: ItemBatch,
git_log: AsyncLog, git_log: AsyncLog,
visible: bool, visible: bool,
first_open_done: bool, first_open_done: bool,
@ -81,7 +117,7 @@ impl Revlog {
/// ///
pub fn new(sender: &Sender<AsyncNotification>) -> Self { pub fn new(sender: &Sender<AsyncNotification>) -> Self {
Self { Self {
items: Vec::new(), items: ItemBatch::default(),
git_log: AsyncLog::new(sender.clone()), git_log: AsyncLog::new(sender.clone()),
selection: 0, selection: 0,
selection_max: 0, selection_max: 0,
@ -95,12 +131,13 @@ impl Revlog {
/// ///
pub fn draw<B: Backend>(&self, f: &mut Frame<B>, area: Rect) { pub fn draw<B: Backend>(&self, f: &mut Frame<B>, area: Rect) {
let height = area.height as usize; let height = area.height as usize;
let selection = self.selection; let selection =
self.selection.saturating_sub(self.items.index_offset);
let height_d2 = height as usize / 2; let height_d2 = height as usize / 2;
let min = selection.saturating_sub(height_d2); let min = selection.saturating_sub(height_d2);
let mut txt = Vec::new(); let mut txt = Vec::new();
for (idx, e) in self.items.iter().enumerate() { for (idx, e) in self.items.items.iter().enumerate() {
let tag = if let Some(tag_name) = self.tags.get(&e.hash) { let tag = if let Some(tag_name) = self.tags.get(&e.hash) {
tag_name.as_str() tag_name.as_str()
} else { } else {
@ -109,8 +146,10 @@ impl Revlog {
Self::add_entry(e, idx == selection, &mut txt, tag); Self::add_entry(e, idx == selection, &mut txt, tag);
} }
let title = let title = format!(
format!("commit {}/{}", selection, self.selection_max); "commit {}/{}",
self.selection, self.selection_max
);
f.render_widget( f.render_widget(
Paragraph::new( Paragraph::new(
@ -135,24 +174,10 @@ impl Revlog {
/// ///
pub fn update(&mut self) { pub fn update(&mut self) {
let next_idx = self.items.len();
let requires_more_data = next_idx
.saturating_sub(self.selection)
< SLICE_OFFSET_RELOAD_THRESHOLD;
self.selection_max = self.git_log.count().saturating_sub(1); self.selection_max = self.git_log.count().saturating_sub(1);
if requires_more_data { if self.items.needs_data(self.selection, self.selection_max) {
let commits = sync::get_commits_info( self.fetch_commits();
CWD,
&self.git_log.get_slice(next_idx, SLICE_SIZE),
);
if let Ok(commits) = commits {
self.items
.extend(commits.into_iter().map(LogEntry::from));
}
} }
if self.tags.is_empty() { if self.tags.is_empty() {
@ -160,6 +185,19 @@ impl Revlog {
} }
} }
fn fetch_commits(&mut self) {
let want_min = self.selection.saturating_sub(SLICE_SIZE / 2);
let commits = sync::get_commits_info(
CWD,
&self.git_log.get_slice(want_min, SLICE_SIZE),
);
if let Ok(commits) = commits {
self.items.set_items(want_min, commits);
}
}
fn move_selection(&mut self, scroll: ScrollType) { fn move_selection(&mut self, scroll: ScrollType) {
self.update_scroll_speed(); self.update_scroll_speed();
@ -176,7 +214,7 @@ impl Revlog {
self.selection.saturating_add(speed_int) self.selection.saturating_add(speed_int)
} }
ScrollType::Home => 0, ScrollType::Home => 0,
_ => self.selection, ScrollType::End => self.selection_max,
}; };
self.selection = cmp::min(self.selection, self.selection_max); self.selection = cmp::min(self.selection, self.selection_max);
@ -296,6 +334,10 @@ impl Component for Revlog {
self.move_selection(ScrollType::Home); self.move_selection(ScrollType::Home);
true true
} }
keys::SHIFT_DOWN | keys::END => {
self.move_selection(ScrollType::End);
true
}
_ => false, _ => false,
}; };
} }