fix: coalesce rapid viewport scrolling redraws
This commit is contained in:
+73
@@ -1433,6 +1433,8 @@ fn keys_ready(
|
||||
mut next: impl FnMut() -> io::Result<Option<Event>>,
|
||||
) -> io::Result<Option<Event>> {
|
||||
let mode = session.editor().mode();
|
||||
// Render before reversing/clamping a scroll or revealing a moved caret.
|
||||
let scroll = session.editor().viewport_scroll_action(&input);
|
||||
for handled in 1..=64 {
|
||||
session.handle(input);
|
||||
if handled == 64 || session.editor().mode() != mode || session.editor().should_quit() {
|
||||
@@ -1442,6 +1444,7 @@ fn keys_ready(
|
||||
if let Some(Event::Key(key)) = &pending
|
||||
&& let Some(next) = translate(*key)
|
||||
&& batch_key(session.editor(), key, &next)
|
||||
&& session.editor().viewport_scroll_action(&next) == scroll
|
||||
{
|
||||
input = next;
|
||||
} else {
|
||||
@@ -17998,6 +18001,76 @@ end
|
||||
assert!(terminal.backend().cursor_visible());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn queued_scrolls_coalesce_but_preserve_reversals_and_motion_barriers() {
|
||||
let directory = Directory::new();
|
||||
let text = (0..100)
|
||||
.map(|row| format!("row-{row}\n"))
|
||||
.collect::<String>();
|
||||
for (first, repeated, barrier) in [
|
||||
(
|
||||
Input::Ctrl('u'),
|
||||
'u',
|
||||
KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL),
|
||||
),
|
||||
(
|
||||
Input::Ctrl('d'),
|
||||
'd',
|
||||
KeyEvent::new(KeyCode::Home, KeyModifiers::NONE),
|
||||
),
|
||||
(
|
||||
Input::Down,
|
||||
'j',
|
||||
KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL),
|
||||
),
|
||||
] {
|
||||
let mut session =
|
||||
EditorSession::open(Some(directory.file("rows.txt", &text)), vec![], None).unwrap();
|
||||
let mut views = BufferViewports::default();
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(80, 12)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
let modifiers = if repeated == 'j' {
|
||||
KeyModifiers::NONE
|
||||
} else {
|
||||
KeyModifiers::CONTROL
|
||||
};
|
||||
let mut events = std::iter::repeat_n(
|
||||
Event::Key(KeyEvent::new(KeyCode::Char(repeated), modifiers)),
|
||||
7,
|
||||
)
|
||||
.chain([Event::Key(barrier)]);
|
||||
assert_eq!(
|
||||
keys_ready(&mut session, first, || Ok(events.next())).unwrap(),
|
||||
Some(Event::Key(barrier))
|
||||
);
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
if repeated == 'u' {
|
||||
assert_eq!(views.offsets[&session.editor().buffer_id()].0, 0);
|
||||
session.handle(Input::Ctrl('d'));
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
views.offsets[&session.editor().buffer_id()].0,
|
||||
usize::from(views.document.geometry.unwrap().1.height) / 2
|
||||
);
|
||||
} else if repeated == 'd' {
|
||||
assert_eq!(views.offsets[&session.editor().buffer_id()].0, 40);
|
||||
session.handle(Input::Home);
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert_eq!(views.offsets[&session.editor().buffer_id()].0, 0);
|
||||
} else {
|
||||
assert_eq!(session.editor().cursor().row, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn queued_navigation_preserves_counted_motions_visual_ranges_and_remaps() {
|
||||
let directory = Directory::new();
|
||||
|
||||
Reference in New Issue
Block a user