1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use crate::app::{ImageRenderResult, VisibleImage};
use crate::image_render::ImageProtocol;
use crate::ui::LinkRegion;
/// State for image rendering, caching, and link overlay tracking.
pub struct ImageState {
/// Image display mode: "native", "halfblock", or "none"
pub image_mode: String,
/// Show link previews (title, description, thumbnail) for URLs
pub show_link_previews: bool,
/// Link regions detected in the last rendered frame
pub link_regions: Vec<LinkRegion>,
/// Maps display text to hidden URL for attachment links
pub link_url_map: HashMap<String, String>,
/// Detected terminal image protocol (Kitty, iTerm2, Sixel, or Halfblock)
pub image_protocol: ImageProtocol,
/// Cell pixel dimensions (width, height) for Sixel encoding
pub cell_px: (u16, u16),
/// Images visible on screen for native protocol overlay (cleared each frame)
pub visible_images: Vec<VisibleImage>,
/// Previous scroll offset for Sixel stale pixel detection
pub sixel_prev_scroll: usize,
/// Previous frame's visible images, for skipping redundant image redraws
pub prev_visible_images: Vec<VisibleImage>,
/// Cache of pre-resized PNGs for native protocol
pub native_image_cache: HashMap<String, (String, u32, u32)>,
/// Next Kitty image ID to assign
pub next_kitty_image_id: u32,
/// Map from image path to Kitty image ID
pub kitty_image_ids: HashMap<String, u32>,
/// Set of image IDs already transmitted to the terminal
pub kitty_transmitted: HashSet<u32>,
/// Images to transmit this frame
pub kitty_pending_transmits: Vec<(u32, String, u16, u16)>,
/// Cache of cropped image base64 for iTerm2
pub iterm2_crop_cache: HashMap<(String, u16, u16), String>,
/// Cache of full Sixel-encoded images
pub sixel_cache: HashMap<String, String>,
/// Background image render channel (sender)
pub image_render_tx: mpsc::Sender<ImageRenderResult>,
/// Background image render channel (receiver)
pub image_render_rx: mpsc::Receiver<ImageRenderResult>,
/// In-flight background renders: (conv_id, timestamp, is_preview)
pub image_render_in_flight: HashSet<(String, i64, bool)>,
}
impl ImageState {
/// Create a new ImageState with the given render channels.
pub fn new(
image_render_tx: mpsc::Sender<ImageRenderResult>,
image_render_rx: mpsc::Receiver<ImageRenderResult>,
) -> Self {
use crate::image_render;
Self {
image_mode: "halfblock".to_string(),
show_link_previews: true,
link_regions: Vec::new(),
link_url_map: HashMap::new(),
image_protocol: image_render::detect_protocol(),
cell_px: image_render::detect_cell_pixel_size(),
visible_images: Vec::new(),
sixel_prev_scroll: 0,
prev_visible_images: Vec::new(),
native_image_cache: HashMap::new(),
next_kitty_image_id: 1,
kitty_image_ids: HashMap::new(),
kitty_transmitted: HashSet::new(),
kitty_pending_transmits: Vec::new(),
iterm2_crop_cache: HashMap::new(),
sixel_cache: HashMap::new(),
image_render_tx,
image_render_rx,
image_render_in_flight: HashSet::new(),
}
}
}