@@ -795,42 +795,50 @@ fn extend_to_line_start(cx: &mut Context) {
797fn kill_to_line_start(cx: &mut Context) {
797fn kill_to_line_start(cx: &mut Context) {
798− delete_by_selection_insert_mode(cx, move |text, range| {
798+ delete_by_selection_insert_mode(
800+ move |text, range| {
799− let line = range.cursor_line(text);
801+ let line = range.cursor_line(text);
800− let first_char = text.line_to_char(line);
802+ let first_char = text.line_to_char(line);
801− let anchor = range.cursor(text);
803+ let anchor = range.cursor(text);
802− let head = if anchor == first_char && line != 0 {
804+ let head = if anchor == first_char && line != 0 {
803− // select until previous line
805+ // select until previous line
804− line_end_char_index(&text, line - 1)
806+ line_end_char_index(&text, line - 1)
805− } else if let Some(pos) = find_first_non_whitespace_char(text.line(line)) {
807+ } else if let Some(pos) = find_first_non_whitespace_char(text.line(line)) {
806− if first_char + pos < anchor {
808+ if first_char + pos < anchor {
807− // select until first non-blank in line if cursor is after it
809+ // select until first non-blank in line if cursor is after it
808− first_char + pos
810+ first_char + pos
812+ // select until start of line
810 // select until start of line
816 // select until start of line
811 first_char
817 first_char
814− // select until start of line
817− (head, anchor)
819+ (head, anchor)
821+ Direction::Backward,
821fn kill_to_line_end(cx: &mut Context) {
825fn kill_to_line_end(cx: &mut Context) {
822− delete_by_selection_insert_mode(cx, |text, range| {
826+ delete_by_selection_insert_mode(
823− let line = range.cursor_line(text);
829+ let line = range.cursor_line(text);
824− let line_end_pos = line_end_char_index(&text, line);
830+ let line_end_pos = line_end_char_index(&text, line);
825− let pos = range.cursor(text);
831+ let pos = range.cursor(text);
827− // if the cursor is on the newline char delete that
833+ // if the cursor is on the newline char delete that
828− if pos == line_end_pos {
834+ if pos == line_end_pos {
829− (pos, text.line_to_char(line + 1))
835+ (pos, text.line_to_char(line + 1))
830− } else {
836+ } else {
831− (pos, line_end_pos)
837+ (pos, line_end_pos)
836fn goto_first_nonwhitespace(cx: &mut Context) {
844fn goto_first_nonwhitespace(cx: &mut Context) {
@@ -2322,13 +2330,44 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) {
2322fn delete_by_selection_insert_mode(
2330fn delete_by_selection_insert_mode(
2323 cx: &mut Context,
2331 cx: &mut Context,
2324 mut f: impl FnMut(RopeSlice, &Range) -> Deletion,
2332 mut f: impl FnMut(RopeSlice, &Range) -> Deletion,
2333+ direction: Direction,
2326 let (view, doc) = current!(cx.editor);
2335 let (view, doc) = current!(cx.editor);
2327 let text = doc.text().slice(..);
2336 let text = doc.text().slice(..);
2337+ let mut selection = SmallVec::new();
2338+ let mut insert_newline = false;
2339+ let text_len = text.len_chars();
2328− let transaction =
2340+ let mut transaction =
2329 Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| {
2341 Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| {
2330− f(text, range)
2342+ let (start, end) = f(text, range);
2343+ if direction == Direction::Forward {
2344+ let mut range = *range;
2345+ if range.head > range.anchor {
2346+ insert_newline |= end == text_len;
2347+ // move the cursor to the right so that the selection
2348+ // doesn't shrink when deleting forward (so the text appears to
2350+ // += 1 is enough here as the range is normalized to grapheme boundaries
2354+ selection.push(range);
2359+ // in case we delete the last character and the cursor would be moved to the EOF char
2360+ // insert a newline, just like when entering append mode
2361+ if insert_newline {
2362+ transaction = transaction.insert_at_eof(doc.line_ending.as_str().into());
2365+ if direction == Direction::Forward {
2368+ Selection::new(selection, doc.selection(view.id).primary_index()),
2332 doc.apply(&transaction, view.id);
2371 doc.apply(&transaction, view.id);
2333 lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic);
2372 lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic);
@@ -3490,28 +3529,40 @@ pub mod insert {
3491 pub fn delete_char_forward(cx: &mut Context) {
3530 pub fn delete_char_forward(cx: &mut Context) {
3492 let count = cx.count();
3531 let count = cx.count();
3493− delete_by_selection_insert_mode(cx, |text, range| {
3532+ delete_by_selection_insert_mode(
3494− let pos = range.cursor(text);
3535+ let pos = range.cursor(text);
3495− (pos, graphemes::nth_next_grapheme_boundary(text, pos, count))
3536+ (pos, graphemes::nth_next_grapheme_boundary(text, pos, count))
3538+ Direction::Forward,
3499 pub fn delete_word_backward(cx: &mut Context) {
3542 pub fn delete_word_backward(cx: &mut Context) {
3500 let count = cx.count();
3543 let count = cx.count();
3501− delete_by_selection_insert_mode(cx, |text, range| {
3544+ delete_by_selection_insert_mode(
3502− let anchor = movement::move_prev_word_start(text, *range, count).from();
3547+ let anchor = movement::move_prev_word_start(text, *range, count).from();
3503− let next = Range::new(anchor, range.cursor(text));
3548+ let next = Range::new(anchor, range.cursor(text));
3504− let range = exclude_cursor(text, next, *range);
3549+ let range = exclude_cursor(text, next, *range);
3505− (range.from(), range.to())
3550+ (range.from(), range.to())
3552+ Direction::Backward,
3509 pub fn delete_word_forward(cx: &mut Context) {
3556 pub fn delete_word_forward(cx: &mut Context) {
3510 let count = cx.count();
3557 let count = cx.count();
3511− delete_by_selection_insert_mode(cx, |text, range| {
3558+ delete_by_selection_insert_mode(
3512− let head = movement::move_next_word_end(text, *range, count).to();
3561+ let head = movement::move_next_word_end(text, *range, count).to();
3513− (range.cursor(text), head)
3562+ (range.cursor(text), head)
3564+ Direction::Forward,