@@ -7,9 +7,13 @@ use crate::{
77};
88
99use helix_core::{
10− char_idx_at_visual_offset, doc_formatter::TextFormat, syntax::Highlight,
11− text_annotations::TextAnnotations, visual_offset_from_anchor, visual_offset_from_block,
12− Position, RopeSlice, Selection, Transaction,
10+ char_idx_at_visual_offset,
11+ doc_formatter::TextFormat,
12+ syntax::Highlight,
13+ text_annotations::TextAnnotations,
14+ visual_offset_from_anchor, visual_offset_from_block, Position, RopeSlice, Selection,
15+ Transaction,
16+ VisualOffsetError::{PosAfterMaxRow, PosBeforeAnchorRow},
1317};
1418
1519use std::{
@@ -213,46 +217,38 @@ impl View {
213217 // - 1 so we have at least one gap in the middle.
214218 // a height of 6 with padding of 3 on each side will keep shifting the view back and forth
215219 // as we type
216− let scrolloff = scrolloff.min(viewport.height.saturating_sub(1) as usize / 2);
220+ let scrolloff = if CENTERING {
221+ 0
222+ } else {
223+ scrolloff.min(viewport.height.saturating_sub(1) as usize / 2)
224+ };
217225
218226 let cursor = doc.selection(self.id).primary().cursor(doc_text);
219227 let mut offset = self.offset;
228+ let off = visual_offset_from_anchor(
229+ doc_text,
230+ offset.anchor,
231+ cursor,
232+ &text_fmt,
233+ &annotations,
234+ vertical_viewport_end,
235+ );
220236
221− let (visual_off, mut at_top) = if cursor >= offset.anchor {
222− let off = visual_offset_from_anchor(
223− doc_text,
224− offset.anchor,
225− cursor,
226− &text_fmt,
227− &annotations,
228− vertical_viewport_end,
229− );
230− (off, false)
231− } else if CENTERING {
232− // cursor out of view
233− return None;
234− } else {
235− (None, true)
236− };
237−
238− let new_anchor = match visual_off {
239− Some((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => {
240− if CENTERING && visual_pos.row < offset.vertical_offset {
237+ let (new_anchor, at_top) = match off {
238+ Ok((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => {
239+ if CENTERING {
241240 // cursor out of view
242241 return None;
243242 }
244− at_top = true;
245− true
243+ (true, true)
246244 }
247− Some((visual_pos, _)) if visual_pos.row + scrolloff + 1 >= vertical_viewport_end => {
248− if CENTERING && visual_pos.row >= vertical_viewport_end {
249− // cursor out of view
250− return None;
251− }
252− true
245+ Ok((visual_pos, _)) if visual_pos.row + scrolloff >= vertical_viewport_end => {
246+ (true, false)
253247 }
254− Some(_) => false,
255− None => true,
248+ Ok((_, _)) => (false, false),
249+ Err(_) if CENTERING => return None,
250+ Err(PosBeforeAnchorRow) => (true, true),
251+ Err(PosAfterMaxRow) => (true, false),
256252 };
257253
258254 if new_anchor {
@@ -269,8 +265,8 @@ impl View {
269265 offset.horizontal_offset = 0;
270266 } else {
271267 // determine the current visual column of the text
272− let col = visual_off
273− .unwrap_or_else(|| {
268+ let col = off
269+ .unwrap_or_else(|_| {
274270 visual_offset_from_block(
275271 doc_text,
276272 offset.anchor,
@@ -360,8 +356,9 @@ impl View {
360356 );
361357
362358 match pos {
363− Some((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset),
364− None => visual_height.saturating_sub(1),
359+ Ok((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset),
360+ Err(PosAfterMaxRow) => visual_height.saturating_sub(1),
361+ Err(PosBeforeAnchorRow) => 0,
365362 }
366363 }
367364
@@ -390,7 +387,8 @@ impl View {
390387 &text_fmt,
391388 &annotations,
392389 viewport.height as usize,
393− )?
390+ )
391+ .ok()?
394392 .0;
395393 if pos.row < self.offset.vertical_offset {
396394 return None;