diff options
Diffstat (limited to 'src/nvim/edit.c')
-rw-r--r-- | src/nvim/edit.c | 205 |
1 files changed, 107 insertions, 98 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b7b32883c2..220b92d099 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -185,7 +185,7 @@ static void insert_enter(InsertState *s) curwin->w_cursor = save_cursor; State = MODE_INSERT; - check_cursor_col(); + check_cursor_col(curwin); State = save_state; } } @@ -282,7 +282,7 @@ static void insert_enter(InsertState *s) // correct in very rare cases). // Also do this if curswant is greater than the current virtual // column. Eg after "^O$" or "^O80|". - validate_virtcol(); + validate_virtcol(curwin); update_curswant(); if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) || curwin->w_curswant > curwin->w_virtcol) @@ -365,9 +365,10 @@ static void insert_enter(InsertState *s) did_cursorhold = false; // ins_redraw() triggers TextChangedI only when no characters - // are in the typeahead buffer, so only reset curbuf->b_last_changedtick + // are in the typeahead buffer, so reset curbuf->b_last_changedtick // if the TextChangedI was not blocked by char_avail() (e.g. using :norm!) - if (!char_avail()) { + // and the TextChangedI autocommand has been triggered. + if (!char_avail() && curbuf->b_last_changedtick_i == buf_get_changedtick(curbuf)) { curbuf->b_last_changedtick = buf_get_changedtick(curbuf); } } @@ -468,7 +469,7 @@ static int insert_check(VimState *state) && curwin->w_topline == s->old_topline && curwin->w_topfill == s->old_topfill) { s->mincol = curwin->w_wcol; - validate_cursor_col(); + validate_cursor_col(curwin); if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, @@ -478,7 +479,7 @@ static int insert_check(VimState *state) || curwin->w_topfill > 0)) { if (curwin->w_topfill > 0) { curwin->w_topfill--; - } else if (hasFolding(curwin->w_topline, NULL, &s->old_topline)) { + } else if (hasFolding(curwin, curwin->w_topline, NULL, &s->old_topline)) { set_topline(curwin, s->old_topline + 1); } else { set_topline(curwin, curwin->w_topline + 1); @@ -491,7 +492,7 @@ static int insert_check(VimState *state) s->did_backspace = false; - validate_cursor(); // may set must_redraw + validate_cursor(curwin); // may set must_redraw // Redraw the display when no characters are waiting. // Also shows mode, ruler and positions cursor. @@ -743,7 +744,7 @@ static int insert_handle_key(InsertState *s) ins_ctrl_o(); // don't move the cursor left when 'virtualedit' has "onemore". - if (get_ve_flags() & VE_ONEMORE) { + if (get_ve_flags(curwin) & VE_ONEMORE) { ins_at_eol = false; s->nomove = true; } @@ -1451,7 +1452,7 @@ void edit_putchar(int c, bool highlight) int attr; update_topline(curwin); // just in case w_topline isn't valid - validate_cursor(); + validate_cursor(curwin); if (highlight) { attr = HL_ATTR(HLF_8); } else { @@ -1521,7 +1522,7 @@ static void init_prompt(int cmdchar_todo) ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false); } curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt)); } @@ -1536,13 +1537,13 @@ static void init_prompt(int cmdchar_todo) } if (cmdchar_todo == 'A') { - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } if (curwin->w_cursor.col < (colnr_T)strlen(prompt)) { curwin->w_cursor.col = (colnr_T)strlen(prompt); } // Make sure the cursor is in a valid position. - check_cursor(); + check_cursor(curwin); } /// @return true if the cursor is in the editable position of the prompt line. @@ -2394,7 +2395,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) pos_T tpos = curwin->w_cursor; curwin->w_cursor = *end_insert_pos; - check_cursor_col(); // make sure it is not past the line + check_cursor_col(curwin); // make sure it is not past the line while (true) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) { curwin->w_cursor.col--; @@ -2471,7 +2472,7 @@ void free_last_insert(void) void beginline(int flags) { if ((flags & BL_SOL) && !p_sol) { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } else { curwin->w_cursor.col = 0; curwin->w_cursor.coladd = 0; @@ -2497,13 +2498,13 @@ int oneright(void) { char *ptr; - if (virtual_active()) { + if (virtual_active(curwin)) { pos_T prevpos = curwin->w_cursor; // Adjust for multi-wide char (excluding TAB) ptr = get_cursor_pos_ptr(); - coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) - ? ptr2cells(ptr) : 1)); + coladvance(curwin, getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) + ? ptr2cells(ptr) : 1)); curwin->w_set_curswant = true; // Return OK if the cursor moved, FAIL otherwise (at window edge). return (prevpos.col != curwin->w_cursor.col @@ -2519,7 +2520,7 @@ int oneright(void) // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' // contains "onemore". - if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0) { + if (ptr[l] == NUL && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { return FAIL; } curwin->w_cursor.col += l; @@ -2531,7 +2532,7 @@ int oneright(void) int oneleft(void) { - if (virtual_active()) { + if (virtual_active(curwin)) { int v = getviscol(); if (v == 0) { @@ -2541,7 +2542,7 @@ int oneleft(void) // We might get stuck on 'showbreak', skip over it. int width = 1; while (true) { - coladvance(v - width); + coladvance(curwin, v - width); // getviscol() is slow, skip it when 'showbreak' is empty, // 'breakindent' is not set and there are no multi-byte // characters @@ -2590,7 +2591,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Count each sequence of folded lines as one logical line. // go to the start of the current fold - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); while (n--) { // move up one line @@ -2602,7 +2603,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Insert mode or when 'foldopen' contains "all": it will open // in a moment. if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) { - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); } } if (lnum < 1) { @@ -2625,7 +2626,7 @@ int cursor_up(linenr_T n, bool upd_topline) cursor_up_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -2678,7 +2679,7 @@ int cursor_down(int n, bool upd_topline) cursor_down_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -2968,7 +2969,7 @@ static void replace_do_bs(int limit_col) } del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { - orig_len = (int)strlen(get_cursor_pos_ptr()); + orig_len = get_cursor_pos_len(); } replace_push(cc); replace_pop_ins(); @@ -2976,7 +2977,7 @@ static void replace_do_bs(int limit_col) if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the inserted characters char *p = get_cursor_pos_ptr(); - int ins_len = (int)strlen(p) - orig_len; + int ins_len = get_cursor_pos_len() - orig_len; int vcol = start_vcol; for (int i = 0; i < ins_len; i++) { vcol += win_chartabsize(curwin, p + i, vcol); @@ -3274,7 +3275,7 @@ static void ins_reg(void) // Cursor may be moved back a column. curwin->w_cursor = curpos; - check_cursor(); + check_cursor(curwin); } if (regname == NUL || !valid_yank_reg(regname, false)) { vim_beep(BO_REG); @@ -3466,7 +3467,7 @@ static bool ins_esc(int *count, int cmdchar, bool nomove) && (curwin->w_cursor.col != 0 || curwin->w_cursor.coladd > 0) && (restart_edit == NUL || (gchar_cursor() == NUL && !VIsual_active)) && !revins_on) { - if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL) { + if (curwin->w_cursor.coladd > 0 || get_ve_flags(curwin) == VE_ALL) { oneleft(); if (restart_edit != NUL) { curwin->w_cursor.coladd++; @@ -3598,7 +3599,7 @@ static void ins_ctrl_o(void) } else { restart_edit = 'I'; } - if (virtual_active()) { + if (virtual_active(curwin)) { ins_at_eol = false; // cursor always keeps its column } else { ins_at_eol = (gchar_cursor() == NUL); @@ -3673,23 +3674,6 @@ static void ins_del(void) AppendCharToRedobuff(K_DEL); } -// Delete one character for ins_bs(). -static void ins_bs_one(colnr_T *vcolp) -{ - dec_cursor(); - getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); - if (State & REPLACE_FLAG) { - // Don't delete characters before the insert point when in - // Replace mode - if (curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) { - replace_do_bs(-1); - } - } else { - del_char(false); - } -} - /// Handle Backspace, delete-word and delete-line in Insert mode. /// /// @param c character that was typed @@ -3760,7 +3744,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) return false; } Insstart.lnum--; - Insstart.col = (colnr_T)strlen(ml_get(Insstart.lnum)); + Insstart.col = ml_get_len(Insstart.lnum); } // In replace mode: // cc < 0: NL was inserted, delete it @@ -3785,9 +3769,10 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { char *ptr = ml_get_buf_mut(curbuf, curwin->w_cursor.lnum); - int len = (int)strlen(ptr); + int len = get_cursor_line_len(); if (len > 0 && ptr[len - 1] == ' ') { ptr[len - 1] = NUL; + curbuf->b_ml.ml_line_len--; } } @@ -3845,42 +3830,74 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Handle deleting one 'shiftwidth' or 'softtabstop'. if (mode == BACKSPACE_CHAR && ((p_sta && in_indent) - || ((get_sts_value() != 0 - || tabstop_count(curbuf->b_p_vsts_array)) + || ((get_sts_value() != 0 || tabstop_count(curbuf->b_p_vsts_array)) && curwin->w_cursor.col > 0 && (*(get_cursor_pos_ptr() - 1) == TAB || (*(get_cursor_pos_ptr() - 1) == ' ' && (!*inserted_space_p || arrow_used)))))) { - colnr_T vcol; - colnr_T want_vcol; - *inserted_space_p = false; - // Compute the virtual column where we want to be. Since - // 'showbreak' may get in the way, need to get the last column of - // the previous character. - getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); - colnr_T start_vcol = vcol; - dec_cursor(); - getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); - inc_cursor(); + + bool const use_ts = !curwin->w_p_list || curwin->w_p_lcs_chars.tab1; + char *const line = get_cursor_line_ptr(); + char *const cursor_ptr = line + curwin->w_cursor.col; + + colnr_T vcol = 0; + colnr_T space_vcol = 0; + StrCharInfo sci = utf_ptr2StrCharInfo(line); + StrCharInfo space_sci = sci; + bool prev_space = false; + + // Compute virtual column of cursor position, and find the last + // whitespace before cursor that is preceded by non-whitespace. + // Use charsize_nowrap() so that virtual text and wrapping are ignored. + while (sci.ptr < cursor_ptr) { + bool cur_space = ascii_iswhite(sci.chr.value); + if (!prev_space && cur_space) { + space_sci = sci; + space_vcol = vcol; + } + vcol += charsize_nowrap(curbuf, use_ts, vcol, sci.chr.value); + sci = utfc_next(sci); + prev_space = cur_space; + } + + // Compute the virtual column where we want to be. + colnr_T want_vcol = vcol > 0 ? vcol - 1 : 0; if (p_sta && in_indent) { - int ts = get_sw_value(curbuf); - want_vcol = (want_vcol / ts) * ts; + want_vcol -= want_vcol % get_sw_value(curbuf); } else { - want_vcol = tabstop_start(want_vcol, - get_sts_value(), - curbuf->b_p_vsts_array); + want_vcol = tabstop_start(want_vcol, get_sts_value(), curbuf->b_p_vsts_array); } - // delete characters until we are at or before want_vcol - while (vcol > want_vcol && curwin->w_cursor.col > 0 - && (cc = (uint8_t)(*(get_cursor_pos_ptr() - 1)), ascii_iswhite(cc))) { - ins_bs_one(&vcol); + // Find the position to stop backspacing. + // Use charsize_nowrap() so that virtual text and wrapping are ignored. + while (true) { + int size = charsize_nowrap(curbuf, use_ts, space_vcol, space_sci.chr.value); + if (space_vcol + size > want_vcol) { + break; + } + space_vcol += size; + space_sci = utfc_next(space_sci); + } + colnr_T const want_col = (int)(space_sci.ptr - line); + + // Delete characters until we are at or before want_col. + while (curwin->w_cursor.col > want_col) { + dec_cursor(); + if (State & REPLACE_FLAG) { + // Don't delete characters before the insert point when in Replace mode. + if (curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) { + replace_do_bs(-1); + } + } else { + del_char(false); + } } - // insert extra spaces until we are at want_vcol - while (vcol < want_vcol) { - // Remember the first char we inserted + // Insert extra spaces until we are at want_vcol. + for (; space_vcol < want_vcol; space_vcol++) { + // Remember the first char we inserted. if (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col < Insstart_orig.col) { Insstart_orig.col = curwin->w_cursor.col; @@ -3894,13 +3911,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) replace_push(NUL); } } - getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); - } - - // If we are now back where we started delete one character. Can - // happen when using 'sts' and 'linebreak'. - if (vcol >= start_vcol) { - ins_bs_one(&vcol); } } else { // Delete up to starting point, start of line or previous word. @@ -4027,7 +4037,7 @@ static void ins_left(void) // always break undo when moving upwards/downwards, else undo may break start_arrow(&tpos); curwin->w_cursor.lnum--; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_set_curswant = true; // so we stay at the end } else { vim_beep(BO_CRSR); @@ -4061,7 +4071,7 @@ static void ins_end(int c) if (c == K_C_END) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; } - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_curswant = MAXCOL; start_arrow(&tpos); @@ -4095,13 +4105,13 @@ static void ins_right(void) foldOpenCursor(); } undisplay_dollar(); - if (gchar_cursor() != NUL || virtual_active()) { + if (gchar_cursor() != NUL || virtual_active(curwin)) { start_arrow_with_change(&curwin->w_cursor, end_change); if (!end_change) { AppendCharToRedobuff(K_RIGHT); } curwin->w_set_curswant = true; - if (virtual_active()) { + if (virtual_active(curwin)) { oneright(); } else { curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); @@ -4156,7 +4166,7 @@ static void ins_up(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_up(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4183,7 +4193,7 @@ static void ins_pageup(void) } pos_T tpos = curwin->w_cursor; - if (onepage(BACKWARD, 1) == OK) { + if (pagescroll(BACKWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { @@ -4201,7 +4211,7 @@ static void ins_down(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_down(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4228,7 +4238,7 @@ static void ins_pagedown(void) } pos_T tpos = curwin->w_cursor; - if (onepage(FORWARD, 1) == OK) { + if (pagescroll(FORWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { @@ -4330,7 +4340,7 @@ static bool ins_tab(void) if (State & VREPLACE_FLAG) { pos = curwin->w_cursor; cursor = &pos; - saved_line = xstrdup(get_cursor_line_ptr()); + saved_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); ptr = saved_line + pos.col; } else { ptr = get_cursor_pos_ptr(); @@ -4411,13 +4421,13 @@ static bool ins_tab(void) if (i > 0) { STRMOVE(ptr, ptr + i); // correct replace stack. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } if (!(State & VREPLACE_FLAG)) { + curbuf->b_ml.ml_line_len -= i; inserted_bytes(fpos.lnum, change_col, cursor->col - change_col, fpos.col - change_col); } @@ -4462,8 +4472,7 @@ bool ins_eol(int c) // Strange Vi behaviour: In Replace mode, typing a NL will not delete the // character under the cursor. Only push a NUL on the replace stack, // nothing to put back when the NL is deleted. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { replace_push(NUL); } @@ -4474,13 +4483,13 @@ bool ins_eol(int c) // Put cursor on NUL if on the last char and coladd is 1 (happens after // CTRL-O). - if (virtual_active() && curwin->w_cursor.coladd > 0) { - coladvance(getviscol()); + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { + coladvance(curwin, getviscol()); } // NL in reverse insert will always start in the end of current line. if (revins_on) { - curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); + curwin->w_cursor.col += get_cursor_pos_len(); } AppendToRedobuff(NL_STR); @@ -4574,7 +4583,7 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - validate_virtcol(); + validate_virtcol(curwin); int const end_vcol = curwin->w_virtcol; char *line = ml_get(lnum); @@ -4720,7 +4729,7 @@ colnr_T get_nolist_virtcol(void) if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) { return getvcol_nolist(&curwin->w_cursor); } - validate_virtcol(); + validate_virtcol(curwin); return curwin->w_virtcol; } |