Skip to content

Commit c5867e2

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 7400d5b commit c5867e2

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;
@@ -126,7 +125,10 @@ impl FileRevlogComponent {
126125
&self.sender,
127126
Some(filter),
128127
));
129-
self.table_state.get_mut().select(Some(0));
128+
129+
self.items.clear();
130+
self.set_selection(open_request.selection.unwrap_or(0));
131+
130132
self.show()?;
131133

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

156+
self.fetch_commits_if_needed()?;
166157
self.update_diff()?;
167158
}
168159

@@ -225,45 +216,18 @@ impl FileRevlogComponent {
225216

226217
fn fetch_commits(&mut self) -> Result<()> {
227218
if let Some(git_log) = &mut self.git_log {
228-
let table_state = self.table_state.take();
219+
let offset = self.table_state.get_mut().offset();
229220

230221
let commits = get_commits_info(
231222
&self.repo_path.borrow(),
232-
&git_log.get_slice(0, SLICE_SIZE)?,
223+
&git_log.get_slice(offset, SLICE_SIZE)?,
233224
self.current_width.get(),
234225
);
235226

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

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

@@ -276,7 +240,7 @@ impl FileRevlogComponent {
276240
let commit_id = table_state.selected().and_then(|selected| {
277241
self.items
278242
.iter()
279-
.nth(selected)
243+
.nth(selected.saturating_sub(table_state.offset()))
280244
.as_ref()
281245
.map(|entry| entry.id)
282246
});
@@ -348,10 +312,12 @@ impl FileRevlogComponent {
348312
})
349313
}
350314

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

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

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

381-
needs_update
354+
*self.table_state.get_mut().offset_mut() = new_offset;
355+
self.table_state.get_mut().select(Some(selection));
382356
}
383357

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

394374
fn get_selection(&self) -> Option<usize> {
@@ -426,10 +406,28 @@ impl FileRevlogComponent {
426406
.border_style(self.theme.block(true)),
427407
);
428408

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

431425
f.render_widget(Clear, area);
432-
f.render_stateful_widget(table, area, &mut table_state);
426+
f.render_stateful_widget(
427+
table,
428+
area,
429+
&mut adjusted_table_state,
430+
);
433431

434432
draw_scrollbar(
435433
f,
@@ -548,36 +546,36 @@ impl Component for FileRevlogComponent {
548546
}
549547
} else if key_match(key, self.key_config.keys.move_up)
550548
{
551-
self.move_selection(ScrollType::Up);
549+
self.move_selection(ScrollType::Up)?;
552550
} else if key_match(
553551
key,
554552
self.key_config.keys.move_down,
555553
) {
556-
self.move_selection(ScrollType::Down);
554+
self.move_selection(ScrollType::Down)?;
557555
} else if key_match(
558556
key,
559557
self.key_config.keys.shift_up,
560558
) || key_match(
561559
key,
562560
self.key_config.keys.home,
563561
) {
564-
self.move_selection(ScrollType::Home);
562+
self.move_selection(ScrollType::Home)?;
565563
} else if key_match(
566564
key,
567565
self.key_config.keys.shift_down,
568566
) || key_match(
569567
key,
570568
self.key_config.keys.end,
571569
) {
572-
self.move_selection(ScrollType::End);
570+
self.move_selection(ScrollType::End)?;
573571
} else if key_match(key, self.key_config.keys.page_up)
574572
{
575-
self.move_selection(ScrollType::PageUp);
573+
self.move_selection(ScrollType::PageUp)?;
576574
} else if key_match(
577575
key,
578576
self.key_config.keys.page_down,
579577
) {
580-
self.move_selection(ScrollType::PageDown);
578+
self.move_selection(ScrollType::PageDown)?;
581579
}
582580
}
583581

0 commit comments

Comments
 (0)