@@ -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};
22use helix_core::{
33 pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
44};
@@ -169,6 +169,15 @@ impl View {
169169 &self,
170170 doc: &Document,
171171 scrolloff: usize,
172+ ) -> Option<(usize, usize)> {
173+ self.offset_coords_to_in_view_center(doc, scrolloff, false)
174+ }
175+
176+ pub fn offset_coords_to_in_view_center(
177+ &self,
178+ doc: &Document,
179+ scrolloff: usize,
180+ centering: bool,
172181 ) -> Option<(usize, usize)> {
173182 let cursor = doc
174183 .selection(self.id)
@@ -180,47 +189,69 @@ impl View {
180189
181190 let inner_area = self.inner_area(doc);
182191 let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1);
183−
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
186− // as we type
187− let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
188−
189192 let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize;
190193
191− let row = if line > last_line.saturating_sub(scrolloff) {
192− // scroll down
193− self.offset.row + line - (last_line.saturating_sub(scrolloff))
194− } else if line < self.offset.row + scrolloff {
195− // scroll up
196− line.saturating_sub(scrolloff)
197− } else {
198− self.offset.row
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
197+ // as we type
198+ let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
199+
200+ let row = if line > last_line.saturating_sub(scrolloff) {
201+ // scroll down
202+ self.offset.row + line - (last_line.saturating_sub(scrolloff))
203+ } else if line < self.offset.row + scrolloff {
204+ // scroll up
205+ line.saturating_sub(scrolloff)
206+ } else {
207+ self.offset.row
208+ };
209+
210+ let col = if col > last_col.saturating_sub(scrolloff) {
211+ // scroll right
212+ self.offset.col + col - (last_col.saturating_sub(scrolloff))
213+ } else if col < self.offset.col + scrolloff {
214+ // scroll left
215+ col.saturating_sub(scrolloff)
216+ } else {
217+ self.offset.col
218+ };
219+ (row, col)
199220 };
200−
201− let col = if col > last_col.saturating_sub(scrolloff) {
202− // scroll right
203− self.offset.col + col - (last_col.saturating_sub(scrolloff))
204− } else if col < self.offset.col + scrolloff {
205− // scroll left
206− col.saturating_sub(scrolloff)
221+ let current_offset = (self.offset.row, self.offset.col);
222+ if centering {
223+ // return None if cursor is out of view
224+ let offset = new_offset(0);
225+ (offset == current_offset).then(|| {
226+ if scrolloff == 0 {
227+ offset
228+ } else {
229+ new_offset(scrolloff)
230+ }
231+ })
207232 } else {
208− self.offset.col
209− };
210− if row == self.offset.row && col == self.offset.col {
211− None
212− } else {
213− Some((row, col))
233+ // return None if cursor is in (view - scrolloff)
234+ let offset = new_offset(scrolloff);
235+ (offset != current_offset).then(|| offset) // TODO: use 'then_some' when 1.62 <= MSRV
214236 }
215237 }
216238
217239 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) {
219241 self.offset.row = row;
220242 self.offset.col = col;
221243 }
222244 }
223245
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;
250+ } else {
251+ align_view(doc, self, Align::Center);
252+ }
253+ }
254+
224255 pub fn is_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) -> bool {
225256 self.offset_coords_to_in_view(doc, scrolloff).is_none()
226257 }