From 6f45df322bc37ff508f919a362bc71fb21f6ec08 Mon Sep 17 00:00:00 2001 From: CptPotato <3957610+CptPotato@users.noreply.github.com> Date: Sun, 5 Feb 2023 13:23:10 +0100 Subject: [PATCH] WIP: auto indent on `insert_at_line_start` --- helix-term/src/commands.rs | 82 +++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d1dc92236cf0a..4d91b3c213c00 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -15,7 +15,9 @@ use helix_core::{ history::UndoKind, increment, indent, indent::IndentStyle, - line_ending::{get_line_ending_of_str, line_end_char_index, str_is_line_ending}, + line_ending::{ + get_line_ending_of_str, line_end_char_index, line_without_line_ending, str_is_line_ending, + }, match_brackets, movement::{self, move_vertically_visual, Direction}, object, pos_at_coords, @@ -2659,9 +2661,85 @@ fn last_picker(cx: &mut Context) { } // I inserts at the first nonwhitespace character of each line with a selection +// If the line is empty, automatically indent fn insert_at_line_start(cx: &mut Context) { - goto_first_nonwhitespace(cx); enter_insert_mode(cx); + + let (view, doc) = current!(cx.editor); + + let text = doc.text().slice(..); + let contents = doc.text(); + let selection = doc.selection(view.id); + + let language_config = doc.language_config(); + let syntax = doc.syntax(); + let tab_width = doc.tab_width(); + + let mut ranges = SmallVec::with_capacity(selection.len()); + let mut offs = 0; + + let mut transaction = Transaction::change_by_selection(contents, selection, |range| { + let cursor = range.from(); + let cursor_line = text.char_to_line(cursor); + + let doc_end = contents.len_chars(); + if range.from() == doc_end { + ranges.push(Range::point(doc_end + offs)); + return (doc_end, doc_end, None); + } + + let line_content = line_without_line_ending(&text, cursor_line); + if line_content.len_chars() == 0 { + // line is empty => auto indent + let (line_end_index, line_end_offset_width) = if cursor_line == 0 { + (0, 0) + } else { + ( + line_end_char_index(&doc.text().slice(..), cursor_line), + doc.line_ending.len_chars(), + ) + }; + + let indent = indent::indent_for_newline( + language_config, + syntax, + &doc.indent_style, + tab_width, + text, + cursor_line, + line_end_index, + cursor_line, + ); + + let indent_len = indent.len(); + let mut text = String::with_capacity(indent_len); + text.push_str(&indent); + + // calculate new selection ranges + let pos = offs + line_end_index + line_end_offset_width; + ranges.push(Range::point((pos + indent_len).saturating_sub(1))); + + offs += text.chars().count(); + (line_end_index, line_end_index, Some(text.into())) + } else { + // move cursor to the first non-whitespace character of the current line + let first_non_ws = line_content + .chars() + .enumerate() + .find_map(|(i, c)| if !c.is_whitespace() { Some(i) } else { None }) + .unwrap_or_default(); + + let pos = offs + text.line_to_char(cursor_line) + first_non_ws; + ranges.push(Range::point(pos)); + (pos, pos, None) + } + }); + + transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); + doc.apply(&transaction, view.id); + + // goto_first_nonwhitespace(cx); + // enter_insert_mode(cx); } // A inserts at the end of each line with a selection