Skip to content

Commit

Permalink
Short-circuit the word and treesitter object movement commands
Browse files Browse the repository at this point in the history
The loop always iterates the number of times the user specified even
if the beginning/end of the document is reached.

For an extreme demonstration try the following commands, Helix will
hang for several seconds.
100000000w
100000000]c

Review feedback amended:
    - short-circuit the prev/next paragraph commands
  • Loading branch information
trink committed Feb 6, 2023
1 parent 9c98043 commit 9f15fa5
Showing 1 changed file with 27 additions and 4 deletions.
31 changes: 27 additions & 4 deletions helix-core/src/movement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,15 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
};

// Do the main work.
(0..count).fold(start_range, |r, _| {
slice.chars_at(r.head).range_to_target(target, r)
})
let mut r = start_range;
for _ in 0..count {
let tmp = slice.chars_at(r.head).range_to_target(target, r);
if r == tmp {
break;
}
r = tmp;
}
r
}

pub fn move_prev_paragraph(
Expand All @@ -251,13 +257,18 @@ pub fn move_prev_paragraph(
let mut lines = slice.lines_at(line);
lines.reverse();
let mut lines = lines.map(rope_is_line_ending).peekable();
let mut last_line = line;
for _ in 0..count {
while lines.next_if(|&e| e).is_some() {
line -= 1;
}
while lines.next_if(|&e| !e).is_some() {
line -= 1;
}
if line == last_line {
break;
}
last_line = line;
}

let head = slice.line_to_char(line);
Expand Down Expand Up @@ -293,13 +304,18 @@ pub fn move_next_paragraph(
line += 1;
}
let mut lines = slice.lines_at(line).map(rope_is_line_ending).peekable();
let mut last_line = line;
for _ in 0..count {
while lines.next_if(|&e| !e).is_some() {
line += 1;
}
while lines.next_if(|&e| e).is_some() {
line += 1;
}
if line == last_line {
break;
}
last_line = line;
}
let head = slice.line_to_char(line);
let anchor = if behavior == Movement::Move {
Expand Down Expand Up @@ -523,7 +539,14 @@ pub fn goto_treesitter_object(
// head of range should be at beginning
Some(Range::new(start_char, end_char))
};
(0..count).fold(range, |range, _| get_range(range).unwrap_or(range))
let mut last_range = range;
for _ in 0..count {
match get_range(last_range) {
Some(r) if r != last_range => last_range = r,
_ => break,
}
}
last_range
}

#[cfg(test)]
Expand Down

0 comments on commit 9f15fa5

Please sign in to comment.