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

Code before:
                let current_line_num = doc.text().char_to_line(cursor);
                let current_line_start = doc.text().line_to_char(current_line_num);
                let left = doc.text().slice(current_line_start..cursor);
                left.chars().all(|c| c.is_whitespace())
            });

            if !cursors_after_whitespace {
                move_parent_node_end(cx);
                return;
            }
        }

        insert_tab(cx);
    }

    pub fn insert_tab(cx: &mut Context) {
        insert_tab_impl(cx, 1)
    }

    fn insert_tab_impl(cx: &mut Context, count: usize) {
        let (view, doc) = current!(cx.editor);
        // TODO: round out to nearest indentation level (for example a line with 3 spaces should
        // indent by one to reach 4 spaces).

        let indent = Tendril::from(doc.indent_style.as_str().repeat(count));
        let transaction = Transaction::insert(
            doc.text(),
            &doc.selection(view.id).clone().cursors(doc.text().slice(..)),
            indent,
        );
        doc.apply(&transaction, view.id);
    }

    pub fn insert_char_interactive(cx: &mut Context) {
        let count = cx.count();

        // need to wait for next key
        cx.on_next_key(move |cx, event| {
            match event {
                KeyEvent {
                    code: KeyCode::Char(ch),
                    ..
                } => {
                    for _ in 0..count {
                        insert::insert_char(cx, ch)
                    }
                }
                KeyEvent {
                    code: KeyCode::Enter,
                    ..
                } => {

Review comment (suggestion):
handling `count` is done here rather than in the new `insert_char` command because it needs to be taken into account if this TODO is ever fixed; putting it outside `insert_tab` makes it more likely to be forgotten.

Code after:
                let cursor = range.cursor(doc.text().slice(..));
                let current_line_num = doc.text().char_to_line(cursor);
                let current_line_start = doc.text().line_to_char(current_line_num);
                let left = doc.text().slice(current_line_start..cursor);
                left.chars().all(|c| c.is_whitespace())
            });

            if !cursors_after_whitespace {
                move_parent_node_end(cx);
                return;
            }
        }

        insert_tab(cx);
    }

    pub fn insert_tab(cx: &mut Context) {
        insert_tab_impl(cx, 1)
    }

    fn insert_tab_impl(cx: &mut Context, count: usize) {
        let (view, doc) = current!(cx.editor);
        // TODO: round out to nearest indentation level (for example a line with 3 spaces should
        // indent by one to reach 4 spaces).

        let indent = Tendril::from(doc.indent_style.as_str().repeat(count));
        let transaction = Transaction::insert(
            doc.text(),
            &doc.selection(view.id).clone().cursors(doc.text().slice(..)),
            indent,
        );
        doc.apply(&transaction, view.id);
    }

    pub fn append_char_interactive(cx: &mut Context) {
        // Save the current mode, so we can restore it later.
        let mode = cx.editor.mode;
        append_mode(cx);
        insert_selection_interactive(cx, mode);
    }

    pub fn insert_char_interactive(cx: &mut Context) {
        let mode = cx.editor.mode;
        insert_mode(cx);
        insert_selection_interactive(cx, mode);
    }

    fn insert_selection_interactive(cx: &mut Context, old_mode: Mode) {
        let count = cx.count();

        // need to wait for next key