Repository: helix-editor/helix
File: helix-term/src/commands.rs (Rust)

Code before:
    let (view, doc) = current_ref!(cx.editor);
    let text = doc.text().slice(..);

    // This is not necessarily exact if there is virtual text like soft wrap.
    // It's ok though because the extra jump labels will not be rendered.
    let start = text.line_to_char(text.char_to_line(view.offset.anchor));
    let end = text.line_to_char(view.estimate_last_doc_line(doc) + 1);

    let primary_selection = doc.selection(view.id).primary();
    let cursor = primary_selection.cursor(text);
    let cursor_fwd = movement::move_prev_word_start(text, Range::point(cursor), 1);
    let mut cursor_fwd = if cursor_fwd.anchor == cursor {
        Range::point(cursor_fwd.head)
    } else {
        Range::point(cursor)
    };
    let mut cursor_rev = cursor_fwd;
    loop {
        let mut changed = false;
        if cursor_fwd.head < end {
            cursor_fwd = movement::move_next_word_end(text, cursor_fwd, 1);
            let range = movement::move_prev_word_start(text, cursor_fwd, 1);
            // The cursor is on a word longer than 2 characters.
            if RopeGraphemes::new(text.slice(range.head..))
                .take(2)
                .all(|g| g.chars().all(char_is_word))
            {
                words.push(range.flip());
            }
            changed = true;
            if words.len() == jump_label_limit {
                break;
            }
        }
        if cursor_rev.head > start {
            cursor_rev = movement::move_prev_word_start(text, cursor_rev, 1);
            // The cursor is on a word longer than 2 characters.
            if RopeGraphemes::new(text.slice(cursor_rev.head..))
                .take(2)
                .all(|g| g.chars().all(char_is_word))
            {
                words.push(movement::move_next_word_end(text, cursor_rev, 1).flip());
            }
            changed = true;
            if words.len() == jump_label_limit {
                break;
            }
        }
        if !changed {
            break;
        }

Review comment (refactor):
Ah looks like we have some duplicates in the ranges:

<details><summary>Ranges from the reproduction case...</summary>

```rust
[
	Range { anchor: 19, head: 25, .. },
	Range { anchor: 15, head: 9, .. },
	Range { anchor: 19, head: 25, .. },
	Range { anchor: 27, head: 31, .. },
	Range { anchor: 27, head: 31, .. },
	Range { anchor: 5, head: 0, .. },
	Range { anchor: 32, head: 38, .. },
	Range { anchor: 32, head: 39, .. },
	Range { anchor: 42, head: 50, .. },
	Range { anchor: 42, head: 50, .. },
	Range { anchor: 52, head: 57, .. },
	Range { anchor: 52, head: 58, .. },
	Range { anchor: 60, head: 65, .. },
	Range { anchor: 66, head: 76, .. },
	Range { anchor: 66, head: 77, .. },
	Range { anchor: 80, head: 86, .. },
	Range { anchor: 80, head: 86, .. },
	Range { anchor: 88, head: 92, .. },
	Range { anchor: 88, head: 92, .. },
	Range { anchor: 93, head: 98, .. },
	Range { anchor: 93, head: 99, .. },
	Range { anchor: 101, head: 105, .. },
	Range { anchor: 106, head: 110, .. },
	Range { anchor: 106, head: 110, .. },
	Range { anchor: 111, head: 117, .. },
	Range { anchor: 111, head: 118, .. },
	Range { anchor: 120, head: 124, .. },
	Range { anchor: 125, head: 129, .. },
	Range { anchor: 125, head: 129, .. },
	Range { anchor: 130, head: 134, .. },
	Range { anchor: 130, head: 135, .. },
	Range { anchor: 137, head: 141, .. },
	Range { anchor: 137, head: 141, .. }
]
```

</details>

`gwaw` there is going to a valid label, it's just not visible since that one is overlapped by another label.

It looks like the `eb`-like movement trips over punctuation and can re-select the last word

Code after:
    let text = doc.text().slice(..);

    let mut new_selection_ranges = SmallVec::new();
    let mut cumulative_length_diff: i128 = 0;
    let mut changes = vec![];

    for range in selection {
        let selected_text: Cow<str> = range.fragment(text);
        let new_from = ((range.from() as i128) + cumulative_length_diff) as usize;
        let incremented = [increment::integer, increment::date_time]
            .iter()
            .find_map(|incrementor| incrementor(selected_text.as_ref(), amount));

        amount += increase_by;

        match incremented {
            None => {
                let new_range = Range::new(
                    new_from,
                    (range.to() as i128 + cumulative_length_diff) as usize,
                );
                new_selection_ranges.push(new_range);
            }
            Some(new_text) => {
                let new_range = Range::new(new_from, new_from + new_text.len());
                cumulative_length_diff += new_text.len() as i128 - selected_text.len() as i128;
                new_selection_ranges.push(new_range);
                changes.push((range.from(), range.to(), Some(new_text.into())));
            }
        }
    }

    if !changes.is_empty() {
        let new_selection = Selection::new(new_selection_ranges, selection.primary_index());
        let transaction = Transaction::change(doc.text(), changes.into_iter());
        let transaction = transaction.with_selection(new_selection);
        doc.apply(&transaction, view.id);
        exit_select_mode(cx);
    }
}

fn record_macro(cx: &mut Context) {
    if let Some((reg, mut keys)) = cx.editor.macro_recording.take() {
        // Remove the keypress which ends the recording
        keys.pop();
        let s = keys
            .into_iter()
            .map(|key| {
                let s = key.to_string();
                if s.chars().count() == 1 {
                    s