Skip to content

Commit 7e05ca0

Browse files
committed
search_impl will only align cursor center when it isn't in view
1 parent aa4d0b4 commit 7e05ca0

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

helix-term/src/commands.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,14 @@ fn split_selection_on_newline(cx: &mut Context) {
11701170
doc.set_selection(view.id, selection);
11711171
}
11721172

1173-
fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Regex, extend: bool) {
1173+
fn search_impl(
1174+
doc: &mut Document,
1175+
view: &mut View,
1176+
contents: &str,
1177+
regex: &Regex,
1178+
extend: bool,
1179+
scrolloff: usize,
1180+
) {
11741181
let text = doc.text().slice(..);
11751182
let selection = doc.selection(view.id);
11761183

@@ -1205,7 +1212,11 @@ fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Rege
12051212
};
12061213

12071214
doc.set_selection(view.id, selection);
1208-
align_view(doc, view, Align::Center);
1215+
if view.is_cursor_in_view(doc, 0) {
1216+
view.ensure_cursor_in_view(doc, scrolloff);
1217+
} else {
1218+
align_view(doc, view, Align::Center)
1219+
}
12091220
};
12101221
}
12111222

@@ -1221,6 +1232,8 @@ fn search_completions(cx: &mut Context, reg: Option<char>) -> Vec<String> {
12211232
// TODO: use one function for search vs extend
12221233
fn search(cx: &mut Context) {
12231234
let reg = cx.register.unwrap_or('/');
1235+
let scrolloff = cx.editor.config.scrolloff;
1236+
12241237
let (_, doc) = current!(cx.editor);
12251238

12261239
// TODO: could probably share with select_on_matches?
@@ -1245,14 +1258,15 @@ fn search(cx: &mut Context) {
12451258
if event != PromptEvent::Update {
12461259
return;
12471260
}
1248-
search_impl(doc, view, &contents, &regex, false);
1261+
search_impl(doc, view, &contents, &regex, false, scrolloff);
12491262
},
12501263
);
12511264

12521265
cx.push_layer(Box::new(prompt));
12531266
}
12541267

12551268
fn search_next_impl(cx: &mut Context, extend: bool) {
1269+
let scrolloff = cx.editor.config.scrolloff;
12561270
let (view, doc) = current!(cx.editor);
12571271
let registers = &cx.editor.registers;
12581272
if let Some(query) = registers.read('/') {
@@ -1267,7 +1281,7 @@ fn search_next_impl(cx: &mut Context, extend: bool) {
12671281
.case_insensitive(case_insensitive)
12681282
.build()
12691283
{
1270-
search_impl(doc, view, &contents, &regex, extend);
1284+
search_impl(doc, view, &contents, &regex, extend, scrolloff);
12711285
} else {
12721286
// get around warning `mutable_borrow_reservation_conflict`
12731287
// which will be a hard error in the future

helix-view/src/view.rs

+29
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,35 @@ impl View {
121121
}
122122
}
123123

124+
pub fn is_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) -> bool {
125+
let cursor = doc
126+
.selection(self.id)
127+
.primary()
128+
.cursor(doc.text().slice(..));
129+
130+
let Position { col, row: line } =
131+
visual_coords_at_pos(doc.text().slice(..), cursor, doc.tab_width());
132+
133+
let inner_area = self.inner_area();
134+
let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1);
135+
136+
// - 1 so we have at least one gap in the middle.
137+
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
138+
// as we type
139+
let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
140+
141+
let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize;
142+
143+
if (line > last_line.saturating_sub(scrolloff)) || (line < self.offset.row + scrolloff) {
144+
return false;
145+
}
146+
147+
if (col > last_col.saturating_sub(scrolloff)) || (col < self.offset.col + scrolloff) {
148+
return false;
149+
}
150+
true
151+
}
152+
124153
/// Calculates the last visible line on screen
125154
#[inline]
126155
pub fn last_line(&self, doc: &Document) -> usize {

0 commit comments

Comments
 (0)