fix: image appearing over alternate screen
This commit is contained in:
+76
-48
@@ -287,8 +287,7 @@ struct SavedCursor {
|
||||
}
|
||||
|
||||
/// Alternate screen buffer state.
|
||||
#[derive(Clone)]
|
||||
struct AlternateScreen {
|
||||
pub struct AlternateScreen {
|
||||
grid: Vec<Vec<Cell>>,
|
||||
line_map: Vec<usize>,
|
||||
cursor_col: usize,
|
||||
@@ -296,6 +295,7 @@ struct AlternateScreen {
|
||||
saved_cursor: SavedCursor,
|
||||
scroll_top: usize,
|
||||
scroll_bottom: usize,
|
||||
pub image_storage: ImageStorage,
|
||||
}
|
||||
|
||||
/// Kitty-style ring buffer for scrollback history.
|
||||
@@ -472,7 +472,7 @@ pub struct Terminal {
|
||||
/// Saved cursor state (DECSC/DECRC).
|
||||
saved_cursor: SavedCursor,
|
||||
/// Alternate screen buffer (for fullscreen apps like vim, less).
|
||||
alternate_screen: Option<AlternateScreen>,
|
||||
pub alternate_screen: Option<AlternateScreen>,
|
||||
/// Whether we're currently using the alternate screen.
|
||||
pub using_alternate_screen: bool,
|
||||
/// Application cursor keys mode (DECCKM) - arrows send ESC O instead of ESC [.
|
||||
@@ -775,16 +775,19 @@ impl Terminal {
|
||||
return; // Already in alternate screen
|
||||
}
|
||||
|
||||
// Save main screen state
|
||||
self.alternate_screen = Some(AlternateScreen {
|
||||
grid: self.grid.clone(),
|
||||
line_map: self.line_map.clone(),
|
||||
cursor_col: self.cursor_col,
|
||||
cursor_row: self.cursor_row,
|
||||
saved_cursor: self.saved_cursor.clone(),
|
||||
scroll_top: self.scroll_top,
|
||||
scroll_bottom: self.scroll_bottom,
|
||||
});
|
||||
// Create alternate screen if it doesn't exist, otherwise reuse it
|
||||
if self.alternate_screen.is_none() {
|
||||
self.alternate_screen = Some(AlternateScreen {
|
||||
grid: self.grid.clone(),
|
||||
line_map: self.line_map.clone(),
|
||||
cursor_col: self.cursor_col,
|
||||
cursor_row: self.cursor_row,
|
||||
saved_cursor: self.saved_cursor.clone(),
|
||||
scroll_top: self.scroll_top,
|
||||
scroll_bottom: self.scroll_bottom,
|
||||
image_storage: ImageStorage::new(),
|
||||
});
|
||||
}
|
||||
|
||||
// Clear the screen for alternate buffer
|
||||
self.grid = vec![vec![Cell::default(); self.cols]; self.rows];
|
||||
@@ -812,10 +815,10 @@ impl Terminal {
|
||||
return; // Not in alternate screen
|
||||
}
|
||||
|
||||
if let Some(saved) = self.alternate_screen.take() {
|
||||
self.grid = saved.grid;
|
||||
self.line_map = saved.line_map;
|
||||
self.saved_cursor = saved.saved_cursor;
|
||||
if let Some(saved) = self.alternate_screen.as_ref() {
|
||||
self.grid = saved.grid.clone();
|
||||
self.line_map = saved.line_map.clone();
|
||||
self.saved_cursor = saved.saved_cursor.clone();
|
||||
self.scroll_top = saved.scroll_top;
|
||||
self.scroll_bottom = saved.scroll_bottom;
|
||||
// Clamp cursor positions to current grid dimensions (defensive)
|
||||
@@ -2721,51 +2724,76 @@ impl Terminal {
|
||||
|
||||
// Convert cursor_row to absolute row (accounting for scrollback)
|
||||
// This allows images to scroll with terminal content
|
||||
let absolute_row = self.scrollback.len() + self.cursor_row;
|
||||
let absolute_row = if self.using_alternate_screen {
|
||||
self.cursor_row
|
||||
} else {
|
||||
self.scrollback.len() + self.cursor_row
|
||||
};
|
||||
|
||||
// Process the command
|
||||
let (response, placement_result) =
|
||||
log::debug!(
|
||||
"Routing image command to {}: cursor_col={}, absolute_row={}, using_alt={}",
|
||||
if self.using_alternate_screen { "alternate" } else { "main" },
|
||||
self.cursor_col,
|
||||
absolute_row,
|
||||
self.using_alternate_screen
|
||||
);
|
||||
let (response, placement_result) = if self.using_alternate_screen {
|
||||
if let Some(ref mut alt) = self.alternate_screen {
|
||||
alt.image_storage.process_command(
|
||||
cmd,
|
||||
self.cursor_col,
|
||||
absolute_row,
|
||||
self.cell_width,
|
||||
self.cell_height,
|
||||
)
|
||||
} else {
|
||||
// This should not happen if using_alternate_screen is true
|
||||
(None, None)
|
||||
}
|
||||
} else {
|
||||
self.image_storage.process_command(
|
||||
cmd,
|
||||
self.cursor_col,
|
||||
absolute_row,
|
||||
self.cell_width,
|
||||
self.cell_height,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
// Queue the response to send back to the application
|
||||
if let Some(resp) = response {
|
||||
self.response_queue.extend_from_slice(resp.as_bytes());
|
||||
}
|
||||
|
||||
// Move cursor after image placement per Kitty protocol spec:
|
||||
// "After placing an image on the screen the cursor must be moved to the
|
||||
// right by the number of cols in the image placement rectangle and down
|
||||
// by the number of rows in the image placement rectangle."
|
||||
// However, if C=1 was specified, don't move the cursor.
|
||||
if let Some(placement) = placement_result {
|
||||
if !placement.suppress_cursor_move
|
||||
&& !placement.virtual_placement
|
||||
{
|
||||
// Move cursor to the right and down by the image dimensions
|
||||
self.cursor_col += placement.cols;
|
||||
let new_row = self.cursor_row + placement.rows;
|
||||
if new_row >= self.rows {
|
||||
// Need to scroll
|
||||
let scroll_amount = new_row - self.rows + 1;
|
||||
self.scroll_up(scroll_amount);
|
||||
self.cursor_row = self.rows - 1;
|
||||
} else {
|
||||
self.cursor_row = new_row;
|
||||
// Move cursor after image placement per Kitty protocol spec:
|
||||
// "After placing an image on the screen the cursor must be moved to the
|
||||
// right by the number of cols in the image placement rectangle and down
|
||||
// by the number of rows in the image placement rectangle."
|
||||
// However, if C=1 was specified, don't move the cursor.
|
||||
if let Some(placement) = placement_result {
|
||||
self.dirty = true;
|
||||
if !placement.suppress_cursor_move
|
||||
&& !placement.virtual_placement
|
||||
{
|
||||
// Move cursor to the right and and down by the image dimensions
|
||||
self.cursor_col += placement.cols;
|
||||
let new_row = self.cursor_row + placement.rows;
|
||||
if new_row >= self.rows {
|
||||
// Need to scroll
|
||||
let scroll_amount = new_row - self.rows + 1;
|
||||
self.scroll_up(scroll_amount);
|
||||
self.cursor_row = self.rows - 1;
|
||||
} else {
|
||||
self.cursor_row = new_row;
|
||||
}
|
||||
// If cursor is now beyond the right edge, it will be handled by the normal
|
||||
// cursor movement logic (wrapping/scrolling) if applicable.
|
||||
log::debug!(
|
||||
"Cursor moved after image placement: col={}, row={} (moved {}x{} cells)",
|
||||
self.cursor_col, self.cursor_row, placement.cols, placement.rows
|
||||
);
|
||||
}
|
||||
}
|
||||
// If cursor is now beyond the right edge, it will be handled by the normal
|
||||
// cursor movement logic (wrapping/scrolling) if applicable.
|
||||
log::debug!(
|
||||
"Cursor moved after image placement: col={}, row={} (moved {}x{} cells)",
|
||||
self.cursor_col, self.cursor_row, placement.cols, placement.rows
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user