commands: Improve scroll functions.

Followed kakoune's implementation, it's no longer janky and can scroll
all the way in either direction.
pull/8/head
Blaž Hrastnik 4 years ago
parent 565fb94afe
commit a5c4314940

@ -4,8 +4,8 @@ use helix_core::{
object, object,
regex::{self, Regex}, regex::{self, Regex},
register, selection, register, selection,
state::{Direction, Granularity, State}, state::{coords_at_pos, pos_at_coords, Direction, Granularity, State},
Change, ChangeSet, Range, Selection, Tendril, Transaction, Change, ChangeSet, Position, Range, Selection, Tendril, Transaction,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
@ -222,62 +222,60 @@ pub fn extend_next_word_end(cx: &mut Context) {
doc.set_selection(selection); doc.set_selection(selection);
} }
pub fn page_up(cx: &mut Context) { fn scroll(view: &mut View, offset: usize, direction: Direction) {
let view = cx.view(); use Direction::*;
if view.first_line < PADDING { let text = view.doc.text().slice(..);
let last_line = view.last_line();
let cursor = coords_at_pos(text, view.doc.selection().cursor());
let doc_last_line = text.len_lines() - 1;
if direction == Backward && view.first_line == 0
|| direction == Forward && last_line == doc_last_line
{
return; return;
} }
view.first_line = view.first_line.saturating_sub(view.area.height as usize); let scrolloff = PADDING; // min(user pref, half win width/height)
if !view.check_cursor_in_view() { // cursor visual offset
let text = view.doc.text(); let cursor_off = cursor.row - view.first_line;
let pos = text.line_to_char(view.last_line().saturating_sub(PADDING));
view.doc.set_selection(Selection::point(pos)); view.first_line = match direction {
Forward => view.first_line + offset,
Backward => view.first_line.saturating_sub(offset),
} }
} .min(doc_last_line);
pub fn page_down(cx: &mut Context) { // clamp into viewport
let view = cx.view(); let line = (view.first_line + cursor_off).clamp(
view.first_line += view.area.height as usize + PADDING; view.first_line + scrolloff,
view.first_line + view.last_line().saturating_sub(scrolloff),
);
if view.first_line < view.doc.text().len_lines() { let pos = pos_at_coords(text, Position::new(line, cursor.col)); // this func will properly truncate to line end
let text = view.doc.text();
let pos = text.line_to_char(view.first_line as usize);
view.doc.set_selection(Selection::point(pos)); view.doc.set_selection(Selection::point(pos));
}
} }
pub fn half_page_up(cx: &mut Context) { pub fn page_up(cx: &mut Context) {
let view = cx.view(); let view = cx.view();
if view.first_line < PADDING { scroll(view, view.area.height as usize, Direction::Backward);
return; }
}
view.first_line = view pub fn page_down(cx: &mut Context) {
.first_line let view = cx.view();
.saturating_sub(view.area.height as usize / 2); scroll(view, view.area.height as usize, Direction::Forward);
}
if !view.check_cursor_in_view() { pub fn half_page_up(cx: &mut Context) {
let text = &view.doc.text(); let view = cx.view();
let pos = text.line_to_char(view.last_line() - PADDING); scroll(view, view.area.height as usize / 2, Direction::Backward);
view.doc.set_selection(Selection::point(pos));
}
} }
pub fn half_page_down(cx: &mut Context) { pub fn half_page_down(cx: &mut Context) {
let view = cx.view(); let view = cx.view();
let lines = view.doc.text().len_lines(); scroll(view, view.area.height as usize / 2, Direction::Forward);
if view.first_line < lines.saturating_sub(view.area.height as usize) {
view.first_line += view.area.height as usize / 2;
}
if !view.check_cursor_in_view() {
let text = view.doc.text();
let pos = text.line_to_char(view.first_line as usize);
view.doc.set_selection(Selection::point(pos));
}
} }
// avoid select by default by having a visual mode switch that makes movements into selects
pub fn extend_char_left(cx: &mut Context) { pub fn extend_char_left(cx: &mut Context) {
let count = cx.count; let count = cx.count;
@ -439,8 +437,10 @@ pub fn search_selection(cx: &mut Context) {
pub fn select_line(cx: &mut Context) { pub fn select_line(cx: &mut Context) {
let count = cx.count; let count = cx.count;
let doc = cx.doc(); let doc = cx.doc();
let pos = doc.selection().primary(); let pos = doc.selection().primary();
let text = doc.text(); let text = doc.text();
let line = text.char_to_line(pos.head); let line = text.char_to_line(pos.head);
let start = text.line_to_char(line); let start = text.line_to_char(line);
let end = text.line_to_char(line + count).saturating_sub(1); let end = text.line_to_char(line + count).saturating_sub(1);

@ -35,17 +35,6 @@ impl View {
Ok(view) Ok(view)
} }
pub fn check_cursor_in_view(&self) -> bool {
let cursor = self.doc.selection().cursor();
let line = self.doc.text().char_to_line(cursor);
let document_end = self.first_line + self.area.height.saturating_sub(1) as usize;
if (line > document_end.saturating_sub(PADDING)) || (line < self.first_line + PADDING) {
return false;
}
true
}
pub fn ensure_cursor_in_view(&mut self) { pub fn ensure_cursor_in_view(&mut self) {
let cursor = self.doc.state.selection().cursor(); let cursor = self.doc.state.selection().cursor();
let line = self.doc.text().char_to_line(cursor); let line = self.doc.text().char_to_line(cursor);

Loading…
Cancel
Save