@@ -1,4 +1,4 @@
1−use crate::{editor::GutterType, graphics::Rect, Document, DocumentId, ViewId};
1+use crate::{align_view, editor::GutterType, graphics::Rect, Align, Document, DocumentId, ViewId};
2use helix_core::{
2use helix_core::{
3 pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
3 pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
@@ -169,6 +169,15 @@ impl View {
170 doc: &Document,
170 doc: &Document,
171 scrolloff: usize,
171 scrolloff: usize,
172+ ) -> Option<(usize, usize)> {
173+ self.offset_coords_to_in_view_center(doc, scrolloff, false)
176+ pub fn offset_coords_to_in_view_center(
172 ) -> Option<(usize, usize)> {
181 ) -> Option<(usize, usize)> {
173 let cursor = doc
182 let cursor = doc
174 .selection(self.id)
183 .selection(self.id)
@@ -180,47 +189,69 @@ impl View {
181 let inner_area = self.inner_area(doc);
190 let inner_area = self.inner_area(doc);
182 let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1);
191 let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1);
184− // - 1 so we have at least one gap in the middle.
185− // a height of 6 with padding of 3 on each side will keep shifting the view back and forth
187− let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
189 let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize;
192 let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize;
194+ let new_offset = |scrolloff: usize| {
195+ // - 1 so we have at least one gap in the middle.
196+ // a height of 6 with padding of 3 on each side will keep shifting the view back and forth
198+ let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
191− let row = if line > last_line.saturating_sub(scrolloff) {
200+ let row = if line > last_line.saturating_sub(scrolloff) {
192− // scroll down
201+ // scroll down
193− self.offset.row + line - (last_line.saturating_sub(scrolloff))
202+ self.offset.row + line - (last_line.saturating_sub(scrolloff))
194− } else if line < self.offset.row + scrolloff {
203+ } else if line < self.offset.row + scrolloff {
195− // scroll up
204+ // scroll up
205+ line.saturating_sub(scrolloff)
210+ let col = if col > last_col.saturating_sub(scrolloff) {
196− line.saturating_sub(scrolloff)
212+ self.offset.col + col - (last_col.saturating_sub(scrolloff))
197− } else {
213+ } else if col < self.offset.col + scrolloff {
215+ col.saturating_sub(scrolloff)
198− self.offset.row
217+ self.offset.col
200−
221+ let current_offset = (self.offset.row, self.offset.col);
201− let col = if col > last_col.saturating_sub(scrolloff) {
222+ if centering {
202− // scroll right
223+ // return None if cursor is out of view
203− self.offset.col + col - (last_col.saturating_sub(scrolloff))
224+ let offset = new_offset(0);
204− } else if col < self.offset.col + scrolloff {
225+ (offset == current_offset).then(|| {
205− // scroll left
226+ if scrolloff == 0 {
206− col.saturating_sub(scrolloff)
227+ offset
229+ new_offset(scrolloff)
208− self.offset.col
233+ // return None if cursor is in (view - scrolloff)
209− };
234+ let offset = new_offset(scrolloff);
210− if row == self.offset.row && col == self.offset.col {
235+ (offset != current_offset).then(|| offset) // TODO: use 'then_some' when 1.62 <= MSRV
217 pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) {
239 pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) {
218− if let Some((row, col)) = self.offset_coords_to_in_view(doc, scrolloff) {
240+ if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, false) {
219 self.offset.row = row;
241 self.offset.row = row;
220 self.offset.col = col;
242 self.offset.col = col;
246+ pub fn ensure_cursor_in_view_center(&mut self, doc: &Document, scrolloff: usize) {
247+ if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, true) {
248+ self.offset.row = row;
249+ self.offset.col = col;
251+ align_view(doc, self, Align::Center);
224 pub fn is_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) -> bool {
255 pub fn is_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) -> bool {
225 self.offset_coords_to_in_view(doc, scrolloff).is_none()
256 self.offset_coords_to_in_view(doc, scrolloff).is_none()