Skip to content

Commit 56264cd

Browse files
shnarazkFrederik Vestre
authored andcommitted
fix: align view after jumplist_picker (helix-editor#3743)
* Add `View::ensure_cursor_in_view_center` to adjust view after searching and jumping Also `offset_coodrs_to_in_view` was refactored to reduce duplicated position calculations. * Fix a wrong offset calculation in `offset_coords_to_in_view_center` It ignored `scrolloff` if `centering` is false.
1 parent 1be7bd1 commit 56264cd

File tree

2 files changed

+67
-37
lines changed

2 files changed

+67
-37
lines changed

helix-term/src/commands.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,12 +1667,7 @@ fn search_impl(
16671667
};
16681668

16691669
doc.set_selection(view.id, selection);
1670-
// TODO: is_cursor_in_view does the same calculation as ensure_cursor_in_view
1671-
if view.is_cursor_in_view(doc, 0) {
1672-
view.ensure_cursor_in_view(doc, scrolloff);
1673-
} else {
1674-
align_view(doc, view, Align::Center)
1675-
}
1670+
view.ensure_cursor_in_view_center(doc, scrolloff);
16761671
};
16771672
}
16781673

@@ -2434,8 +2429,10 @@ fn jumplist_picker(cx: &mut Context) {
24342429
(),
24352430
|cx, meta, action| {
24362431
cx.editor.switch(meta.id, action);
2432+
let config = cx.editor.config();
24372433
let (view, doc) = current!(cx.editor);
24382434
doc.set_selection(view.id, meta.selection.clone());
2435+
view.ensure_cursor_in_view_center(doc, config.scrolloff);
24392436
},
24402437
|editor, meta| {
24412438
let doc = &editor.documents.get(&meta.id)?;
@@ -4205,6 +4202,7 @@ fn match_brackets(cx: &mut Context) {
42054202

42064203
fn jump_forward(cx: &mut Context) {
42074204
let count = cx.count();
4205+
let config = cx.editor.config();
42084206
let view = view_mut!(cx.editor);
42094207
let doc_id = view.doc;
42104208

@@ -4218,12 +4216,13 @@ fn jump_forward(cx: &mut Context) {
42184216
}
42194217

42204218
doc.set_selection(view.id, selection);
4221-
align_view(doc, view, Align::Center);
4219+
view.ensure_cursor_in_view_center(doc, config.scrolloff);
42224220
};
42234221
}
42244222

42254223
fn jump_backward(cx: &mut Context) {
42264224
let count = cx.count();
4225+
let config = cx.editor.config();
42274226
let (view, doc) = current!(cx.editor);
42284227
let doc_id = doc.id();
42294228

@@ -4237,7 +4236,7 @@ fn jump_backward(cx: &mut Context) {
42374236
}
42384237

42394238
doc.set_selection(view.id, selection);
4240-
align_view(doc, view, Align::Center);
4239+
view.ensure_cursor_in_view_center(doc, config.scrolloff);
42414240
};
42424241
}
42434242

helix-view/src/view.rs

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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};
22
use 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
}

0 commit comments

Comments
 (0)