Skip to content

Commit 55cd4c7

Browse files
committed
Fix file history for all sizes
- Replace temporary fix by proper fix - Re-organize code related to setting selection and fetching data to make sure `self.items` is updated whenever necessary
1 parent 5c98e2f commit 55cd4c7

File tree

1 file changed

+66
-68
lines changed

1 file changed

+66
-68
lines changed

src/components/file_revlog.rs

Lines changed: 66 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use asyncgit::{
1919
diff_contains_file, get_commits_info, CommitId, RepoPathRef,
2020
},
2121
AsyncDiff, AsyncGitNotification, AsyncLog, DiffParams, DiffType,
22-
FetchStatus,
2322
};
2423
use chrono::{DateTime, Local};
2524
use crossbeam_channel::Sender;
@@ -125,7 +124,10 @@ impl FileRevlogComponent {
125124
&self.sender,
126125
Some(filter),
127126
));
128-
self.table_state.get_mut().select(Some(0));
127+
128+
self.items.clear();
129+
self.set_selection(open_request.selection.unwrap_or(0));
130+
129131
self.show()?;
130132

131133
self.diff.focus(false);
@@ -148,20 +150,9 @@ impl FileRevlogComponent {
148150
///
149151
pub fn update(&mut self) -> Result<()> {
150152
if let Some(ref mut git_log) = self.git_log {
151-
let log_changed =
152-
git_log.fetch()? == FetchStatus::Started;
153-
154-
let table_state = self.table_state.take();
155-
let start = table_state.selected().unwrap_or(0);
156-
self.table_state.set(table_state);
157-
158-
if self.items.needs_data(start, git_log.count()?)
159-
|| log_changed
160-
{
161-
self.fetch_commits()?;
162-
self.set_open_selection();
163-
}
153+
git_log.fetch()?;
164154

155+
self.fetch_commits_if_needed()?;
165156
self.update_diff()?;
166157
}
167158

@@ -224,45 +215,18 @@ impl FileRevlogComponent {
224215

225216
fn fetch_commits(&mut self) -> Result<()> {
226217
if let Some(git_log) = &mut self.git_log {
227-
let table_state = self.table_state.take();
218+
let offset = self.table_state.get_mut().offset();
228219

229220
let commits = get_commits_info(
230221
&self.repo_path.borrow(),
231-
&git_log.get_slice(0, SLICE_SIZE)?,
222+
&git_log.get_slice(offset, SLICE_SIZE)?,
232223
self.current_width.get(),
233224
);
234225

235226
if let Ok(commits) = commits {
236-
// 2023-04-12
237-
//
238-
// There is an issue with how windowing works in `self.items` and
239-
// `self.table_state`. Because of that issue, we currently have to pass
240-
// `0` as the first argument to `set_items`. If we did not do that, the
241-
// offset that is kept separately in `self.items` and `self.table_state`
242-
// would get out of sync, resulting in the table showing the wrong rows.
243-
//
244-
// The offset determines the number of rows `render_stateful_widget`
245-
// skips when rendering a table. When `set_items` is called, it clears
246-
// its internal `Vec` of items and sets `index_offset` based on the
247-
// parameter passed. Unfortunately, there is no way for us to pass this
248-
// information, `index_offset`, to `render_stateful_widget`. Because of
249-
// that, `render_stateful_widget` assumes that the rows provided by
250-
// `Table` are 0-indexed while in reality they are
251-
// `index_offset`-indexed.
252-
//
253-
// This fix makes the `FileRevlog` unable to show histories that have
254-
// more than `SLICE_SIZE` items, but since it is broken for larger
255-
// histories anyway, this seems acceptable for the time being.
256-
//
257-
// This issue can only properly be fixed upstream, in `tui-rs`. See
258-
// [tui-issue].
259-
//
260-
// [gitui-issue]: https://github.com/extrawurst/gitui/issues/1560
261-
// [tui-issue]: https://github.com/fdehau/tui-rs/issues/626
262-
self.items.set_items(0, commits);
227+
self.items.set_items(offset, commits);
263228
}
264229

265-
self.table_state.set(table_state);
266230
self.count_total = git_log.count()?;
267231
}
268232

@@ -275,7 +239,7 @@ impl FileRevlogComponent {
275239
let commit_id = table_state.selected().and_then(|selected| {
276240
self.items
277241
.iter()
278-
.nth(selected)
242+
.nth(selected.saturating_sub(table_state.offset()))
279243
.as_ref()
280244
.map(|entry| entry.id)
281245
});
@@ -347,10 +311,12 @@ impl FileRevlogComponent {
347311
})
348312
}
349313

350-
fn move_selection(&mut self, scroll_type: ScrollType) -> bool {
351-
let mut table_state = self.table_state.take();
352-
353-
let old_selection = table_state.selected().unwrap_or(0);
314+
fn move_selection(
315+
&mut self,
316+
scroll_type: ScrollType,
317+
) -> Result<()> {
318+
let old_selection =
319+
self.table_state.get_mut().selected().unwrap_or(0);
354320
let max_selection = self.get_max_selection();
355321
let height_in_items = self.current_height.get() / 2;
356322

@@ -374,20 +340,34 @@ impl FileRevlogComponent {
374340
self.queue.push(InternalEvent::Update(NeedsUpdate::DIFF));
375341
}
376342

377-
table_state.select(Some(new_selection));
378-
self.table_state.set(table_state);
343+
self.set_selection(new_selection);
344+
self.fetch_commits_if_needed()?;
345+
346+
Ok(())
347+
}
348+
349+
fn set_selection(&mut self, selection: usize) {
350+
let height_in_items = self.current_height.get() / 2;
351+
let new_offset = selection.saturating_sub(height_in_items);
379352

380-
needs_update
353+
*self.table_state.get_mut().offset_mut() = new_offset;
354+
self.table_state.get_mut().select(Some(selection));
381355
}
382356

383-
fn set_open_selection(&mut self) {
384-
if let Some(selection) =
385-
self.open_request.as_ref().and_then(|req| req.selection)
386-
{
387-
let mut table_state = self.table_state.take();
388-
table_state.select(Some(selection));
389-
self.table_state.set(table_state);
357+
fn fetch_commits_if_needed(&mut self) -> Result<()> {
358+
let selection =
359+
self.table_state.get_mut().selected().unwrap_or(0);
360+
let height_in_items = self.current_height.get() / 2;
361+
let new_offset = selection.saturating_sub(height_in_items);
362+
363+
if self.items.needs_data(
364+
new_offset,
365+
selection.saturating_add(height_in_items),
366+
) {
367+
self.fetch_commits()?;
390368
}
369+
370+
Ok(())
391371
}
392372

393373
fn get_selection(&self) -> Option<usize> {
@@ -425,10 +405,28 @@ impl FileRevlogComponent {
425405
.border_style(self.theme.block(true)),
426406
);
427407

428-
let mut table_state = self.table_state.take();
408+
let table_state = self.table_state.take();
409+
// We have to adjust the table state for drawing to account for the fact
410+
// that `self.items` not necessarily starts at index 0.
411+
//
412+
// When a user scrolls down, items outside of the current view are removed
413+
// when new data is fetched. Let’s have a look at an example: if the item at
414+
// index 50 is the first item in the current view and `self.items` has been
415+
// freshly fetched, the current offset is 50 and `self.items[0]` is the item
416+
// at index 50. Subtracting the current offset from the selected index
417+
// yields the correct index in `self.items`, in this case 0.
418+
let mut adjusted_table_state = TableState::default()
419+
.with_selected(table_state.selected().map(|selected| {
420+
selected.saturating_sub(table_state.offset())
421+
}))
422+
.with_offset(0);
429423

430424
f.render_widget(Clear, area);
431-
f.render_stateful_widget(table, area, &mut table_state);
425+
f.render_stateful_widget(
426+
table,
427+
area,
428+
&mut adjusted_table_state,
429+
);
432430

433431
draw_scrollbar(
434432
f,
@@ -547,36 +545,36 @@ impl Component for FileRevlogComponent {
547545
}
548546
} else if key_match(key, self.key_config.keys.move_up)
549547
{
550-
self.move_selection(ScrollType::Up);
548+
self.move_selection(ScrollType::Up)?;
551549
} else if key_match(
552550
key,
553551
self.key_config.keys.move_down,
554552
) {
555-
self.move_selection(ScrollType::Down);
553+
self.move_selection(ScrollType::Down)?;
556554
} else if key_match(
557555
key,
558556
self.key_config.keys.shift_up,
559557
) || key_match(
560558
key,
561559
self.key_config.keys.home,
562560
) {
563-
self.move_selection(ScrollType::Home);
561+
self.move_selection(ScrollType::Home)?;
564562
} else if key_match(
565563
key,
566564
self.key_config.keys.shift_down,
567565
) || key_match(
568566
key,
569567
self.key_config.keys.end,
570568
) {
571-
self.move_selection(ScrollType::End);
569+
self.move_selection(ScrollType::End)?;
572570
} else if key_match(key, self.key_config.keys.page_up)
573571
{
574-
self.move_selection(ScrollType::PageUp);
572+
self.move_selection(ScrollType::PageUp)?;
575573
} else if key_match(
576574
key,
577575
self.key_config.keys.page_down,
578576
) {
579-
self.move_selection(ScrollType::PageDown);
577+
self.move_selection(ScrollType::PageDown)?;
580578
}
581579
}
582580

0 commit comments

Comments
 (0)