Skip to content

Commit 9df1d03

Browse files
committed
support prefetch in tile mode
1 parent 58682cc commit 9df1d03

File tree

4 files changed

+104
-16
lines changed

4 files changed

+104
-16
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "svt"
3-
version = "25.12.5"
3+
version = "25.12.6"
44
edition = "2024"
55
description = "Simple Viewer in Terminal - sxiv-like terminal image viewer"
66

src/app.rs

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -718,19 +718,25 @@ impl App {
718718
self.config.prefetch_count
719719
}
720720

721-
/// Prefetch adjacent images (next and previous) into the render cache.
721+
/// Prefetch adjacent images/pages into the render cache.
722722
/// Call this after the current image is fully displayed.
723723
pub fn prefetch_adjacent(&mut self, terminal_size: Rect) {
724724
// Skip if there's already a pending request (don't overwhelm the worker)
725725
if self.pending_request.is_some() {
726726
return;
727727
}
728-
729-
let prefetch_count = self.prefetch_count();
730-
if prefetch_count == 0 {
728+
if self.prefetch_count() == 0 {
731729
return;
732730
}
733731

732+
match self.view_mode {
733+
ViewMode::Single => self.prefetch_adjacent_single(terminal_size),
734+
ViewMode::Tile => self.prefetch_adjacent_tile(terminal_size),
735+
}
736+
}
737+
738+
/// Prefetch next/previous images in Single mode (with wrap-around).
739+
fn prefetch_adjacent_single(&mut self, terminal_size: Rect) {
734740
let image_area = Self::image_area(terminal_size);
735741
let (cell_w, cell_h) = self.picker.font_size();
736742
if cell_w == 0 || cell_h == 0 || image_area.width == 0 || image_area.height == 0 {
@@ -741,25 +747,24 @@ impl App {
741747
let max_h_px = u32::from(image_area.height) * u32::from(cell_h);
742748
let target = (max_w_px, max_h_px);
743749

744-
// Try to prefetch next and previous images
745750
let len = self.images.len();
746751
if len <= 1 {
747752
return;
748753
}
749754

750-
// Build list of indices to prefetch: next N, then prev N
755+
// Build list of indices: next images first, then previous images
756+
let prefetch_count = self.prefetch_count();
751757
let mut indices = Vec::with_capacity(prefetch_count * 2);
752758
for i in 1..=prefetch_count {
753-
indices.push((self.current_index + i) % len); // next
759+
indices.push((self.current_index + i) % len);
754760
}
755761
for i in 1..=prefetch_count {
756-
indices.push((self.current_index + len - i) % len); // prev
762+
indices.push((self.current_index + len - i) % len);
757763
}
758764

759765
for idx in indices {
760766
let path = &self.images[idx];
761767

762-
// Skip if already in cache
763768
let in_cache = self
764769
.render_cache
765770
.iter()
@@ -768,7 +773,6 @@ impl App {
768773
continue;
769774
}
770775

771-
// Send prefetch request
772776
self.worker.request(ImageRequest {
773777
path: path.clone(),
774778
target,
@@ -783,7 +787,90 @@ impl App {
783787
tile_grid: None,
784788
cell_size: None,
785789
});
786-
// Only prefetch one at a time to avoid overwhelming the worker
790+
break;
791+
}
792+
}
793+
794+
/// Prefetch next/previous pages in Tile mode (no wrap-around).
795+
fn prefetch_adjacent_tile(&mut self, terminal_size: Rect) {
796+
let image_area = Self::image_area(terminal_size);
797+
let (cell_w, cell_h) = self.picker.font_size();
798+
if cell_w == 0 || cell_h == 0 || image_area.width == 0 || image_area.height == 0 {
799+
return;
800+
}
801+
802+
let max_w_px = u32::from(image_area.width) * u32::from(cell_w);
803+
let max_h_px = u32::from(image_area.height) * u32::from(cell_h);
804+
let target = (max_w_px, max_h_px);
805+
806+
let grid = Self::calculate_tile_grid(terminal_size, self.config.cell_aspect_ratio);
807+
let (cols, rows) = grid;
808+
let tiles_per_page = cols * rows;
809+
if tiles_per_page == 0 {
810+
return;
811+
}
812+
813+
let len = self.images.len();
814+
let total_pages = len.div_ceil(tiles_per_page);
815+
if total_pages <= 1 {
816+
return;
817+
}
818+
819+
let current_page = self.tile_cursor / tiles_per_page;
820+
let prefetch_count = self.prefetch_count();
821+
822+
// Build list of page indices: next pages first, then previous pages
823+
let mut page_indices = Vec::with_capacity(prefetch_count * 2);
824+
for i in 1..=prefetch_count {
825+
let next_page = current_page + i;
826+
if next_page < total_pages {
827+
page_indices.push(next_page);
828+
}
829+
}
830+
for i in 1..=prefetch_count {
831+
if current_page >= i {
832+
page_indices.push(current_page - i);
833+
}
834+
}
835+
836+
for page in page_indices {
837+
let page_start = page * tiles_per_page;
838+
let cache_key = PathBuf::from(format!("__tile_page_{}", page_start));
839+
840+
let in_cache = self
841+
.render_cache
842+
.iter()
843+
.any(|r| r.path == cache_key && r.target == target && r.fit_mode == self.fit_mode);
844+
if in_cache {
845+
continue;
846+
}
847+
848+
let tile_paths: Vec<PathBuf> = self
849+
.images
850+
.iter()
851+
.skip(page_start)
852+
.take(tiles_per_page)
853+
.cloned()
854+
.collect();
855+
856+
if tile_paths.is_empty() {
857+
continue;
858+
}
859+
860+
self.worker.request(ImageRequest {
861+
path: cache_key,
862+
target,
863+
fit_mode: self.fit_mode,
864+
kgp_id: self.kgp_id,
865+
is_tmux: self.is_tmux,
866+
compress_level: self.config.compression_level(),
867+
tmux_kitty_max_pixels: self.config.tmux_kitty_max_pixels,
868+
trace_worker: self.config.trace_worker,
869+
view_mode: ViewMode::Tile,
870+
tile_paths: Some(tile_paths),
871+
tile_grid: Some(grid),
872+
cell_size: Some((cell_w, cell_h)),
873+
});
787874
break;
788875
}
789876
}

src/main.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,13 @@ fn run(images: Vec<PathBuf>, config: Config) -> Result<()> {
406406
// Transmits only after user stops navigating (debounce via nav_latch).
407407
app.prepare_render_request(terminal_rect, allow_transmission);
408408

409-
// Prefetch adjacent images after current image is fully displayed.
410-
// Note: Prefetch only in Single mode (Ready or Fit states).
409+
// Prefetch adjacent images/pages after current image is fully displayed.
411410
if allow_transmission
412411
&& matches!(
413412
indicator,
414-
crate::sender::StatusIndicator::Ready | crate::sender::StatusIndicator::Fit
413+
crate::sender::StatusIndicator::Ready
414+
| crate::sender::StatusIndicator::Fit
415+
| crate::sender::StatusIndicator::Tile
415416
)
416417
{
417418
app.prefetch_adjacent(terminal_rect);

0 commit comments

Comments
 (0)