fix: hide pane cursor while scrolled back
This commit is contained in:
parent
733b109e20
commit
e12c7a2cef
|
|
@ -1962,6 +1962,40 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn virtual_render_hides_focused_pane_cursor_while_scrolled_back() {
|
||||
let mut state = AppState::test_new();
|
||||
let mut ws = crate::workspace::Workspace::test_new("test");
|
||||
let pane_id = ws.tabs[0].root_pane;
|
||||
let mut bytes = Vec::new();
|
||||
for line in 0..80 {
|
||||
bytes.extend_from_slice(format!("line {line:02}\r\n").as_bytes());
|
||||
}
|
||||
let runtime = crate::pane::PaneRuntime::test_with_scrollback_bytes(20, 5, 4096, &bytes);
|
||||
ws.tabs[0].runtimes.insert(pane_id, runtime);
|
||||
|
||||
state.workspaces = vec![ws];
|
||||
state.active = Some(0);
|
||||
state.selected = 0;
|
||||
state.mode = crate::app::Mode::Terminal;
|
||||
|
||||
let area = Rect::new(0, 0, 80, 24);
|
||||
let _ = crate::server::render_stream::render_virtual(&mut state, area, true);
|
||||
let runtime = state.workspaces[0]
|
||||
.runtime(pane_id)
|
||||
.expect("pane runtime after initial render");
|
||||
runtime.scroll_up(6);
|
||||
assert!(crate::ui::pane_is_scrolled_back(runtime));
|
||||
|
||||
let (_buffer, cursor) =
|
||||
crate::server::render_stream::render_virtual(&mut state, area, true);
|
||||
|
||||
assert!(
|
||||
cursor.as_ref().is_none_or(|cursor| !cursor.visible),
|
||||
"cursor: {cursor:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_active_client_drives_shared_size_theme_and_fallback() {
|
||||
let mut server = test_headless_server();
|
||||
|
|
|
|||
|
|
@ -257,11 +257,11 @@ fn focused_terminal_cursor(app_state: &AppState) -> Option<CursorState> {
|
|||
.pane_infos
|
||||
.iter()
|
||||
.find(|info| info.is_focused)?;
|
||||
let rt = ws.runtimes.get(&info.id)?;
|
||||
let rt = ws.runtime(info.id)?;
|
||||
let cursor = rt.cursor_state(info.inner_rect, true)?;
|
||||
Some(CursorState {
|
||||
x: cursor.x,
|
||||
y: cursor.y,
|
||||
visible: cursor.visible,
|
||||
visible: cursor.visible && !crate::ui::pane_is_scrolled_back(rt),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ pub(crate) use self::{
|
|||
mobile_switcher_areas, mobile_switcher_max_scroll, mobile_switcher_target_at,
|
||||
mobile_switcher_workspace_doc_range, MobileSwitcherTarget,
|
||||
},
|
||||
panes::pane_is_scrolled_back,
|
||||
tabs::compute_tab_bar_view,
|
||||
widgets::{centered_popup_rect, modal_stack_areas},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ use crate::app::{AppState, Mode};
|
|||
use crate::layout::PaneInfo;
|
||||
use crate::pane::PaneRuntime;
|
||||
|
||||
pub(crate) fn pane_is_scrolled_back(rt: &PaneRuntime) -> bool {
|
||||
rt.scroll_metrics()
|
||||
.is_some_and(|metrics| metrics.offset_from_bottom > 0)
|
||||
}
|
||||
|
||||
fn stable_terminal_inner_rect(pane_inner: Rect) -> Rect {
|
||||
if pane_inner.width <= 4 {
|
||||
return pane_inner;
|
||||
|
|
@ -176,7 +181,8 @@ pub(super) fn render_panes(app: &AppState, frame: &mut Frame, area: Rect) {
|
|||
frame.render_widget(block, info.rect);
|
||||
}
|
||||
|
||||
rt.render(frame, info.inner_rect, info.is_focused && terminal_active);
|
||||
let show_cursor = info.is_focused && terminal_active && !pane_is_scrolled_back(rt);
|
||||
rt.render(frame, info.inner_rect, show_cursor);
|
||||
render_pane_scrollbar(app, frame, info, rt);
|
||||
|
||||
let should_dim = !info.is_focused && multi_pane && !terminal_active;
|
||||
|
|
|
|||
Loading…
Reference in New Issue