@@ -2775,24 +2775,87 @@ fn last_picker(cx: &mut Context) {
27752775 }));
27762776}
27772777
2778−// I inserts at the first nonwhitespace character of each line with a selection
2778+/// Fallback position to use for [`insert_with_indent`].
2779+enum IndentFallbackPos {
2780+ LineStart,
2781+ LineEnd,
2782+}
2783+
2784+// `I` inserts at the first nonwhitespace character of each line with a selection.
2785+// If the line is empty, automatically indent.
27792786fn insert_at_line_start(cx: &mut Context) {
2780− goto_first_nonwhitespace(cx);
2781− enter_insert_mode(cx);
2787+ insert_with_indent(cx, IndentFallbackPos::LineStart);
27822788}
27832789
2784−// A inserts at the end of each line with a selection
2790+// `A` inserts at the end of each line with a selection.
2791+// If the line is empty, automatically indent.
27852792fn insert_at_line_end(cx: &mut Context) {
2793+ insert_with_indent(cx, IndentFallbackPos::LineEnd);
2794+}
2795+
2796+// Enter insert mode and auto-indent the current line if it is empty.
2797+// If the line is not empty, move the cursor to the specified fallback position.
2798+fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) {
27862799 enter_insert_mode(cx);
2800+
27872801 let (view, doc) = current!(cx.editor);
27882802
2789− let selection = doc.selection(view.id).clone().transform(|range| {
2790− let text = doc.text().slice(..);
2791− let line = range.cursor_line(text);
2792− let pos = line_end_char_index(&text, line);
2793− Range::new(pos, pos)
2803+ let text = doc.text().slice(..);
2804+ let contents = doc.text();
2805+ let selection = doc.selection(view.id);
2806+
2807+ let language_config = doc.language_config();
2808+ let syntax = doc.syntax();
2809+ let tab_width = doc.tab_width();
2810+
2811+ let mut ranges = SmallVec::with_capacity(selection.len());
2812+ let mut offs = 0;
2813+
2814+ let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
2815+ let cursor_line = range.cursor_line(text);
2816+ let cursor_line_start = text.line_to_char(cursor_line);
2817+
2818+ if line_end_char_index(&text, cursor_line) == cursor_line_start {
2819+ // line is empty => auto indent
2820+ let line_end_index = cursor_line_start;
2821+
2822+ let indent = indent::indent_for_newline(
2823+ language_config,
2824+ syntax,
2825+ &doc.indent_style,
2826+ tab_width,
2827+ text,
2828+ cursor_line,
2829+ line_end_index,
2830+ cursor_line,
2831+ );
2832+
2833+ // calculate new selection ranges
2834+ let pos = offs + cursor_line_start;
2835+ let indent_width = indent.chars().count();
2836+ ranges.push(Range::point(pos + indent_width));
2837+ offs += indent_width;
2838+
2839+ (line_end_index, line_end_index, Some(indent.into()))
2840+ } else {
2841+ // move cursor to the fallback position
2842+ let pos = match cursor_fallback {
2843+ IndentFallbackPos::LineStart => {
2844+ find_first_non_whitespace_char(text.line(cursor_line))
2845+ .map(|ws_offset| ws_offset + cursor_line_start)
2846+ .unwrap_or(cursor_line_start)
2847+ }
2848+ IndentFallbackPos::LineEnd => line_end_char_index(&text, cursor_line),
2849+ };
2850+
2851+ ranges.push(range.put_cursor(text, pos + offs, cx.editor.mode == Mode::Select));
2852+
2853+ (cursor_line_start, cursor_line_start, None)
2854+ }
27942855 });
2795− doc.set_selection(view.id, selection);
2856+
2857+ transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
2858+ doc.apply(&transaction, view.id);
27962859}
27972860
27982861// Creates an LspCallback that waits for formatting changes to be computed. When they're done,