it's almost working !!

This commit is contained in:
itsjunetime
2025-06-02 17:41:04 -06:00
parent b09ce88d9f
commit 4d764cd4f9
7 changed files with 298 additions and 41 deletions
Generated
+134 -6
View File
@@ -41,6 +41,21 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anes" name = "anes"
version = "0.1.6" version = "0.1.6"
@@ -386,6 +401,18 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"windows-link",
]
[[package]] [[package]]
name = "ciborium" name = "ciborium"
version = "0.2.2" version = "0.2.2"
@@ -968,6 +995,19 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "flexi_logger"
version = "0.30.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb03342077df16d5b1400d7bed00156882846d7a479ff61a6f10594bcc3423d8"
dependencies = [
"chrono",
"log",
"nu-ansi-term",
"regex",
"thiserror 2.0.12",
]
[[package]] [[package]]
name = "float-ord" name = "float-ord"
version = "0.3.2" version = "0.3.2"
@@ -1331,6 +1371,30 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.2",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "icy_sixel" name = "icy_sixel"
version = "0.1.3" version = "0.1.3"
@@ -1880,6 +1944,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
[[package]]
name = "nu-ansi-term"
version = "0.50.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
dependencies = [
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.6" version = "0.4.6"
@@ -2937,11 +3010,13 @@ dependencies = [
"criterion", "criterion",
"crossterm", "crossterm",
"csscolorparser 0.7.2", "csscolorparser 0.7.2",
"flexi_logger",
"flume", "flume",
"futures-util", "futures-util",
"image", "image",
"itertools 0.14.0", "itertools 0.14.0",
"kittage", "kittage",
"log",
"memmap2", "memmap2",
"mimalloc", "mimalloc",
"mupdf", "mupdf",
@@ -3627,7 +3702,7 @@ version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
dependencies = [ dependencies = [
"windows-core", "windows-core 0.58.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@@ -3637,13 +3712,26 @@ version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [ dependencies = [
"windows-implement", "windows-implement 0.58.0",
"windows-interface", "windows-interface 0.58.0",
"windows-result", "windows-result 0.2.0",
"windows-strings", "windows-strings 0.1.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-link",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]] [[package]]
name = "windows-implement" name = "windows-implement"
version = "0.58.0" version = "0.58.0"
@@ -3655,6 +3743,17 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "windows-interface" name = "windows-interface"
version = "0.58.0" version = "0.58.0"
@@ -3666,6 +3765,17 @@ dependencies = [
"syn 2.0.104", "syn 2.0.104",
] ]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.1.3" version = "0.1.3"
@@ -3681,16 +3791,34 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-strings" name = "windows-strings"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.2.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
+5
View File
@@ -29,6 +29,7 @@ ratatui = { git = "https://github.com/itsjunetime/ratatui.git" }
ratatui-image = { git = "https://github.com/itsjunetime/ratatui-image.git", branch = "vb64_on_personal", default-features = false } ratatui-image = { git = "https://github.com/itsjunetime/ratatui-image.git", branch = "vb64_on_personal", default-features = false }
# ratatui-image = { path = "./ratatui-image", default-features = false } # ratatui-image = { path = "./ratatui-image", default-features = false }
crossterm = { version = "0.29.0", features = ["event-stream"] } crossterm = { version = "0.29.0", features = ["event-stream"] }
# crossterm = { path = "../crossterm", features = ["event-stream"] }
image = { version = "0.25.1", features = ["pnm", "rayon", "png"], default-features = false } image = { version = "0.25.1", features = ["pnm", "rayon", "png"], default-features = false }
notify = { version = "8.0.0", features = ["crossbeam-channel"] } notify = { version = "8.0.0", features = ["crossbeam-channel"] }
tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] } tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros"] }
@@ -43,6 +44,10 @@ rayon = { version = "*", default-features = false }
kittage = { path = "../kittage/", features = ["crossterm-tokio", "image-crate"] } kittage = { path = "../kittage/", features = ["crossterm-tokio", "image-crate"] }
memmap2 = "*" memmap2 = "*"
# logging
log = "0.4.27"
flexi_logger = "0.30.2"
# for tracing with tokio-console # for tracing with tokio-console
console-subscriber = { version = "0.4.0", optional = true } console-subscriber = { version = "0.4.0", optional = true }
csscolorparser = { version = "0.7.0" } csscolorparser = { version = "0.7.0" }
+5 -4
View File
@@ -76,11 +76,11 @@ pub async fn run_conversion_loop(
// then we go through all the indices available to us and find the first one that has an // then we go through all the indices available to us and find the first one that has an
// image available to steal // image available to steal
let Some((page_info, new_iter)) = (idx_start..page) let Some((page_info, new_iter, page_num)) = (idx_start..page)
.interleave(page..idx_end) .interleave(page..idx_end)
.enumerate() .enumerate()
// .skip(*iteration) // .skip(*iteration)
.find_map(|(i_idx, p_idx)| images[p_idx].take().map(|p| (p, i_idx))) .find_map(|(i_idx, p_idx)| images[p_idx].take().map(|p| (p, i_idx, p_idx)))
else { else {
return Ok(None); return Ok(None);
}; };
@@ -124,10 +124,11 @@ pub async fn run_conversion_loop(
match kittage::image::Image::shm_from( match kittage::image::Image::shm_from(
dyn_img, dyn_img,
format!("__tdf_kittage_{pid}_page_{page}").into() format!("__tdf_kittage_{pid}_page_{page_num}").into()
) { ) {
Ok((mut img, map)) => { Ok((mut img, map)) => {
img.num_or_id = NumberOrId::Id(NonZeroU32::new(page as u32 + 1).unwrap()); img.num_or_id =
NumberOrId::Id(NonZeroU32::new(page_num as u32 + 1).unwrap());
ConvertedImage::Kitty { ConvertedImage::Kitty {
img: MaybeTransferred::NotYet(img, map), img: MaybeTransferred::NotYet(img, map),
area area
+48
View File
@@ -0,0 +1,48 @@
use std::io::Write;
use crossterm::event::EventStream;
use kittage::{AsyncInputReader, ImageId, action::Action, error::TransmitError};
#[derive(Debug)]
pub struct DbgWriter<W: Write> {
w: W,
#[cfg(debug_assertions)]
buf: String
}
impl<W: Write> Write for DbgWriter<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
#[cfg(debug_assertions)]
{
if let Ok(s) = std::str::from_utf8(buf) {
self.buf.push_str(s);
}
}
self.w.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
#[cfg(debug_assertions)]
{
log::debug!("wrote {:?}", self.buf);
self.buf.clear();
}
self.w.flush()
}
}
pub async fn run_action<'image, 'data, 'es>(
action: Action<'image, 'data>,
ev_stream: &'es mut EventStream
) -> Result<ImageId, TransmitError<'image, 'data, <&'es mut EventStream as AsyncInputReader>::Error>>
{
let writer = DbgWriter {
w: std::io::stdout().lock(),
#[cfg(debug_assertions)]
buf: String::new()
};
action
.execute_async(writer, ev_stream)
.await
.map(|(_, i)| i)
}
+1
View File
@@ -9,6 +9,7 @@ pub enum PrerenderLimit {
} }
pub mod converter; pub mod converter;
pub mod kitty;
pub mod renderer; pub mod renderer;
pub mod skip; pub mod skip;
pub mod tui; pub mod tui;
+90 -21
View File
@@ -2,7 +2,7 @@ use core::error::Error;
use std::{ use std::{
borrow::Cow, borrow::Cow,
ffi::OsString, ffi::OsString,
io::{BufReader, Read, StdoutLock, Write, stdout}, io::{BufReader, Read, Write, stdout},
num::{NonZeroU32, NonZeroUsize}, num::{NonZeroU32, NonZeroUsize},
path::PathBuf path::PathBuf
}; };
@@ -16,10 +16,12 @@ use crossterm::{
} }
}; };
use flume::{Sender, r#async::RecvStream}; use flume::{Sender, r#async::RecvStream};
use flexi_logger::FileSpec;
use futures_util::{FutureExt, stream::StreamExt}; use futures_util::{FutureExt, stream::StreamExt};
use kittage::{ use kittage::{
ImageDimensions, PixelFormat, ImageDimensions, PixelFormat,
action::Action, action::Action,
delete::{ClearOrDelete, DeleteConfig, WhichToDelete},
display::{DisplayConfig, DisplayLocation}, display::{DisplayConfig, DisplayLocation},
error::TransmitError, error::TransmitError,
image::Image as KImage, image::Image as KImage,
@@ -27,10 +29,11 @@ use kittage::{
}; };
use notify::{Event, EventKind, RecursiveMode, Watcher}; use notify::{Event, EventKind, RecursiveMode, Watcher};
use ratatui::{Terminal, backend::CrosstermBackend}; use ratatui::{Terminal, backend::CrosstermBackend};
use ratatui_image::picker::Picker; use ratatui_image::picker::{Picker, ProtocolType};
use tdf::{ use tdf::{
PrerenderLimit, PrerenderLimit,
converter::{ConvertedPage, ConverterMsg, MaybeTransferred, run_conversion_loop}, converter::{ConvertedPage, ConverterMsg, MaybeTransferred, run_conversion_loop},
kitty::run_action,
renderer::{self, RenderError, RenderInfo, RenderNotif}, renderer::{self, RenderError, RenderInfo, RenderNotif},
tui::{BottomMessage, InputAction, MessageSetting, Tui} tui::{BottomMessage, InputAction, MessageSetting, Tui}
}; };
@@ -97,6 +100,23 @@ async fn main() -> Result<(), WrappedErr> {
) )
})?; })?;
// need to keep it around throughout the lifetime of the program, but don't rly need to use it.
// Just need to make sure it doesn't get dropped yet.
let mut maybe_logger = None;
if std::env::var("RUST_LOG").is_ok() {
maybe_logger =
Some(
flexi_logger::Logger::try_with_env()
.map_err(|e| WrappedErr(format!("Couldn't create initial logger: {e}")))?
.log_to_file(FileSpec::try_from("./debug.log").map_err(|e| {
WrappedErr(format!("Couldn't create FileSpec for logger: {e}"))
})?)
.start()
.map_err(|e| WrappedErr(format!("Can't start logger: {e}")))?
);
}
let (watch_to_render_tx, render_rx) = flume::unbounded(); let (watch_to_render_tx, render_rx) = flume::unbounded();
let tui_tx = watch_to_render_tx.clone(); let tui_tx = watch_to_render_tx.clone();
@@ -233,6 +253,7 @@ async fn main() -> Result<(), WrappedErr> {
let (to_converter, from_main) = flume::unbounded(); let (to_converter, from_main) = flume::unbounded();
let (to_main, from_converter) = flume::unbounded(); let (to_main, from_converter) = flume::unbounded();
let is_kitty = picker.protocol_type() == ProtocolType::Kitty;
tokio::spawn(run_conversion_loop(to_main, from_main, picker, 20)); tokio::spawn(run_conversion_loop(to_main, from_main, picker, 20));
let file_name = path.file_name().map_or_else( let file_name = path.file_name().map_or_else(
@@ -266,6 +287,17 @@ async fn main() -> Result<(), WrappedErr> {
) )
})?; })?;
if is_kitty {
run_action(
Action::Delete(DeleteConfig {
effect: ClearOrDelete::Delete,
which: WhichToDelete::IdRange(NonZeroU32::new(1).unwrap()..=NonZeroU32::MAX)
}),
&mut ev_stream
)
.await?;
}
let fullscreen = flags.fullscreen.unwrap_or_default(); let fullscreen = flags.fullscreen.unwrap_or_default();
let main_area = Tui::main_layout(&term.get_frame(), fullscreen); let main_area = Tui::main_layout(&term.get_frame(), fullscreen);
tui_tx tui_tx
@@ -326,9 +358,10 @@ async fn enter_redraw_loop(
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn Error>> {
loop { loop {
let mut needs_redraw = true; let mut needs_redraw = true;
let next_ev = ev_stream.next().fuse();
tokio::select! { tokio::select! {
// First we check if we have any keystrokes // First we check if we have any keystrokes
Some(ev) = ev_stream.next().fuse() => { Some(ev) = next_ev => {
// If we can't get user input, just crash. // If we can't get user input, just crash.
let ev = ev.expect("Couldn't get any user input"); let ev = ev.expect("Couldn't get any user input");
@@ -386,9 +419,9 @@ async fn enter_redraw_loop(
to_display = tui.render(f, &main_area); to_display = tui.render(f, &main_area);
})?; })?;
let mut stdout = stdout().lock();
let mut maybe_err = Ok(()); let mut maybe_err = Ok(());
for (img, area) in to_display { let mut to_replace = Vec::new();
for (page_num, img, area) in to_display {
let config = DisplayConfig { let config = DisplayConfig {
location: DisplayLocation { location: DisplayLocation {
x: area.x.into(), x: area.x.into(),
@@ -398,6 +431,8 @@ async fn enter_redraw_loop(
..DisplayConfig::default() ..DisplayConfig::default()
}; };
log::debug!("looking at img {img:#?}");
maybe_err = match img { maybe_err = match img {
MaybeTransferred::NotYet(image, _map) => { MaybeTransferred::NotYet(image, _map) => {
let mut fake_image = KImage { let mut fake_image = KImage {
@@ -416,16 +451,22 @@ async fn enter_redraw_loop(
}; };
std::mem::swap(image, &mut fake_image); std::mem::swap(image, &mut fake_image);
let res = Action::TransmitAndDisplay { log::debug!("Actually trying to display an image now: {fake_image:?}...");
let res = run_action(
Action::TransmitAndDisplay {
image: fake_image, image: fake_image,
config, config,
placement_id: None placement_id: None
} },
.execute_async(&mut stdout, &mut ev_stream) &mut ev_stream
)
.await; .await;
log::debug!("And it should've gone through: {res:?}!...");
match res { match res {
Ok((_, img_id)) => { Ok(img_id) => {
// We need the `_map` to be dropped here, but can't explicitly carry it // We need the `_map` to be dropped here, but can't explicitly carry it
// over to here. So we're just relying on the overwrite of `img` to // over to here. So we're just relying on the overwrite of `img` to
// drop `_map` (and thus unmap the memory) for us // drop `_map` (and thus unmap the memory) for us
@@ -433,40 +474,68 @@ async fn enter_redraw_loop(
Ok(()) Ok(())
} }
Err(e) => Err(match e { Err(e) => Err(match e {
TransmitError::Writing( TransmitError::Writing(action, e) => {
Action::TransmitAndDisplay { if let Action::TransmitAndDisplay {
image: failed_img, .. image: failed_img, ..
}, } = *action
e {
) => {
*image = failed_img; *image = failed_img;
} else {
to_replace.push(page_num);
}
e.to_string()
}
_ => {
to_replace.push(page_num);
e.to_string() e.to_string()
} }
_ => e.to_string()
}) })
} }
} }
MaybeTransferred::Transferred(image_id) => Action::Display { MaybeTransferred::Transferred(image_id) => {
let e = run_action(
Action::Display {
image_id: *image_id, image_id: *image_id,
placement_id: NonZeroU32::new(1).unwrap(), placement_id: NonZeroU32::new(1).unwrap(),
config config
} },
.execute_async(&mut stdout, &mut ev_stream) &mut ev_stream
)
.await .await
.map(|(_, _)| ()) .map(|_| ())
.map_err(|e| e.to_string()) .map_err(|e| e.to_string());
log::debug!("Just tried to display: {e:?}");
e
}
}; };
} }
for page_num in to_replace {
tui.page_failed_display(page_num);
}
if let Err(e) = maybe_err { if let Err(e) = maybe_err {
tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!( tui.set_msg(MessageSetting::Some(BottomMessage::Error(format!(
"Couldn't transfer image to the terminal: {e}" "Couldn't transfer image to the terminal: {e}"
)))); ))));
} }
execute!(&mut stdout, EndSynchronizedUpdate)?; execute!(stdout().lock(), EndSynchronizedUpdate)?;
} }
} }
execute!(
term.backend_mut(),
LeaveAlternateScreen,
crossterm::cursor::Show
)?;
disable_raw_mode()?;
drop(maybe_logger);
Ok(())
} }
fn on_notify_ev( fn on_notify_ev(
+8 -3
View File
@@ -133,7 +133,7 @@ impl Tui {
&'s mut self, &'s mut self,
frame: &mut Frame<'_>, frame: &mut Frame<'_>,
full_layout: &RenderLayout full_layout: &RenderLayout
) -> Vec<(&'s mut MaybeTransferred, Rect)> { ) -> Vec<(usize, &'s mut MaybeTransferred, Rect)> {
if self.showing_help_msg { if self.showing_help_msg {
self.render_help_msg(frame); self.render_help_msg(frame);
return vec![]; return vec![];
@@ -293,11 +293,12 @@ impl Tui {
let to_display = page_widths let to_display = page_widths
.into_iter() .into_iter()
.filter_map(|(width, img)| { .enumerate()
.filter_map(|(idx, (width, img))| {
let maybe_img = let maybe_img =
Self::render_single_page(frame, img, Rect { width, ..img_area }); Self::render_single_page(frame, img, Rect { width, ..img_area });
img_area.x += width; img_area.x += width;
maybe_img maybe_img.map(|(img, r)| (idx + self.page, img, r))
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -400,6 +401,10 @@ impl Tui {
}; };
} }
pub fn page_failed_display(&mut self, page_num: usize) {
self.rendered[page_num].img = None;
}
pub fn got_num_results_on_page(&mut self, page_num: usize, num_results: usize) { pub fn got_num_results_on_page(&mut self, page_num: usize, num_results: usize) {
self.rendered[page_num].num_results = Some(num_results); self.rendered[page_num].num_results = Some(num_results);
} }