From 978f5114d82b51f2327c08faf2bf692181bf2408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Fri, 9 Apr 2021 18:48:56 +0900 Subject: [PATCH] Horizontal scrolling! It only took a year to get around to it. --- helix-term/src/ui/editor.rs | 16 +++++++++------- helix-view/src/view.rs | 26 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 5426e014..d32f7864 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -189,18 +189,20 @@ impl EditorView { } else if grapheme == "\t" { visual_x += (tab_width as u16); } else { - if visual_x >= viewport.width { - // if we're offscreen just keep going until we hit a new line - // TODO: will need tweaking when we also take into account - // horizontal scrolling - continue; - } + let out_of_bounds = visual_x < view.first_col as u16 + || visual_x >= viewport.width + view.first_col as u16; // Cow will prevent allocations if span contained in a single slice // which should really be the majority case let grapheme = Cow::from(grapheme); let width = grapheme_width(&grapheme) as u16; + if out_of_bounds { + // if we're offscreen just keep going until we hit a new line + visual_x += width; + continue; + } + // ugh,interleave highlight spans with diagnostic spans let is_diagnostic = doc.diagnostics.iter().any(|diagnostic| { diagnostic.range.start <= char_index @@ -214,7 +216,7 @@ impl EditorView { }; surface.set_string( - viewport.x + visual_x, + viewport.x + visual_x - view.first_col as u16, viewport.y + line, grapheme, style, diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 89caaf3e..93bb005e 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use crate::{Document, DocumentId, ViewId}; use helix_core::{ + coords_at_pos, graphemes::{grapheme_width, RopeGraphemes}, Position, RopeSlice, Selection, }; @@ -56,6 +57,7 @@ pub struct View { pub id: ViewId, pub doc: DocumentId, pub first_line: usize, + pub first_col: usize, pub area: Rect, pub jumps: JumpList, } @@ -66,6 +68,7 @@ impl View { id: ViewId::default(), doc, first_line: 0, + first_col: 0, area: Rect::default(), // will get calculated upon inserting into tree jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel }; @@ -75,18 +78,30 @@ impl View { pub fn ensure_cursor_in_view(&mut self, doc: &Document) { let cursor = doc.selection(self.id).cursor(); - let line = doc.text().char_to_line(cursor); - let document_end = self.first_line + (self.area.height as usize).saturating_sub(2); + let pos = coords_at_pos(doc.text().slice(..), cursor); + let line = pos.row; + let col = pos.col; + let last_line = self.first_line + (self.area.height as usize).saturating_sub(2); - // TODO: side scroll + // TODO: not ideal + const OFFSET: usize = 7; // 1 diagnostic + 5 linenr + 1 gutter + let last_col = self.first_col + (self.area.width as usize - OFFSET); - if line > document_end.saturating_sub(PADDING) { + if line > last_line.saturating_sub(PADDING) { // scroll down - self.first_line += line - (document_end.saturating_sub(PADDING)); + self.first_line += line - (last_line.saturating_sub(PADDING)); } else if line < self.first_line + PADDING { // scroll up self.first_line = line.saturating_sub(PADDING); } + + if col > last_col.saturating_sub(PADDING) { + // scroll right + self.first_col += col - (last_col.saturating_sub(PADDING)); + } else if col < self.first_col + PADDING { + // scroll left + self.first_col = col.saturating_sub(PADDING); + } } /// Calculates the last visible line on screen @@ -130,6 +145,7 @@ impl View { } let row = line - self.first_line as usize; + let col = col - self.first_col as usize; Some(Position::new(row, col)) }