aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/change.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/change.c')
-rw-r--r--src/nvim/change.c240
1 files changed, 129 insertions, 111 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 81a55b92ee..1c7724f010 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -8,6 +8,7 @@
#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
#include "nvim/buffer_updates.h"
@@ -20,18 +21,23 @@
#include "nvim/eval.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/extmark.h"
+#include "nvim/extmark_defs.h"
#include "nvim/fold.h"
-#include "nvim/func_attr.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_defs.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/insexpand.h"
#include "nvim/macros_defs.h"
#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
+#include "nvim/marktree_defs.h"
#include "nvim/mbyte.h"
+#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
+#include "nvim/memline_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/move.h"
@@ -43,8 +49,10 @@
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h"
+#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/textformat.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim_defs.h"
@@ -86,7 +94,7 @@ void change_warning(buf_T *buf, int col)
msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
msg_clr_eos();
- (void)msg_end();
+ msg_end();
if (msg_silent == 0 && !silent_mode && ui_active()) {
ui_flush();
os_delay(1002, true); // give the user time to think about it
@@ -155,6 +163,71 @@ void changed_internal(buf_T *buf)
need_maketitle = true; // set window title later
}
+/// Invalidate a window's w_valid flags and w_lines[] entries after changing lines.
+static void changed_lines_invalidate_win(win_T *wp, linenr_T lnum, colnr_T col, linenr_T lnume,
+ linenr_T xtra)
+{
+ // If the changed line is in a range of previously folded lines,
+ // compare with the first line in that range.
+ if (wp->w_cursor.lnum <= lnum) {
+ int i = find_wl_entry(wp, lnum);
+ if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) {
+ changed_line_abv_curs_win(wp);
+ }
+ }
+
+ if (wp->w_cursor.lnum > lnum) {
+ changed_line_abv_curs_win(wp);
+ } else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) {
+ changed_cline_bef_curs(wp);
+ }
+ if (wp->w_botline >= lnum) {
+ // Assume that botline doesn't change (inserted lines make
+ // other lines scroll down below botline).
+ approximate_botline_win(wp);
+ }
+
+ // Check if any w_lines[] entries have become invalid.
+ // For entries below the change: Correct the lnums for inserted/deleted lines.
+ // Makes it possible to stop displaying after the change.
+ for (int i = 0; i < wp->w_lines_valid; i++) {
+ if (wp->w_lines[i].wl_valid) {
+ if (wp->w_lines[i].wl_lnum >= lnum) {
+ // Do not change wl_lnum at index zero, it is used to compare with w_topline.
+ // Invalidate it instead.
+ // If lines haven been inserted/deleted and the buffer has virt_lines,
+ // invalidate the line after the changed lines as some virt_lines may
+ // now be drawn above a different line.
+ if (i == 0 || wp->w_lines[i].wl_lnum < lnume
+ || (xtra != 0 && wp->w_lines[i].wl_lnum == lnume
+ && buf_meta_total(wp->w_buffer, kMTMetaLines) > 0)) {
+ // line included in change
+ wp->w_lines[i].wl_valid = false;
+ } else if (xtra != 0) {
+ // line below change
+ wp->w_lines[i].wl_lnum += xtra;
+ wp->w_lines[i].wl_lastlnum += xtra;
+ }
+ } else if (wp->w_lines[i].wl_lastlnum >= lnum) {
+ // change somewhere inside this range of folded lines,
+ // may need to be redrawn
+ wp->w_lines[i].wl_valid = false;
+ }
+ }
+ }
+}
+
+/// Line changed_lines_invalidate_win(), but for all windows displaying a buffer.
+void changed_lines_invalidate_buf(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume,
+ linenr_T xtra)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer == buf) {
+ changed_lines_invalidate_win(wp, lnum, col, lnume, xtra);
+ }
+ }
+}
+
/// Common code for when a change was made.
/// See changed_lines() for the arguments.
/// Careful: may trigger autocommands that reload the buffer.
@@ -185,7 +258,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
// Create a new entry if a new undo-able change was started or we
// don't have an entry yet.
if (buf->b_new_change || buf->b_changelistlen == 0) {
- int add;
+ bool add;
if (buf->b_changelistlen == 0) {
add = true;
} else {
@@ -249,10 +322,17 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
// Mark this window to be redrawn later.
- if (wp->w_redr_type < UPD_VALID) {
+ if (!redraw_not_allowed && wp->w_redr_type < UPD_VALID) {
wp->w_redr_type = UPD_VALID;
}
+ // When inserting/deleting lines and the window has specific lines
+ // to be redrawn, w_redraw_top and w_redraw_bot may now be invalid,
+ // so just redraw everything.
+ if (xtra != 0 && wp->w_redraw_top != 0) {
+ redraw_later(wp, UPD_NOT_VALID);
+ }
+
linenr_T last = lnume + xtra - 1; // last line after the change
// Reset "w_skipcol" if the topline length has become smaller to
@@ -288,55 +368,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
wp->w_cline_folded = folded;
}
- // If the changed line is in a range of previously folded lines,
- // compare with the first line in that range.
- if (wp->w_cursor.lnum <= lnum) {
- int i = find_wl_entry(wp, lnum);
- if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) {
- changed_line_abv_curs_win(wp);
- }
- }
-
- if (wp->w_cursor.lnum > lnum) {
- changed_line_abv_curs_win(wp);
- } else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) {
- changed_cline_bef_curs(wp);
- }
- if (wp->w_botline >= lnum) {
- // Assume that botline doesn't change (inserted lines make
- // other lines scroll down below botline).
- approximate_botline_win(wp);
- }
-
- // Check if any w_lines[] entries have become invalid.
- // For entries below the change: Correct the lnums for
- // inserted/deleted lines. Makes it possible to stop displaying
- // after the change.
- for (int i = 0; i < wp->w_lines_valid; i++) {
- if (wp->w_lines[i].wl_valid) {
- if (wp->w_lines[i].wl_lnum >= lnum) {
- // Do not change wl_lnum at index zero, it is used to
- // compare with w_topline. Invalidate it instead.
- // If the buffer has virt_lines, invalidate the line
- // after the changed lines as the virt_lines for a
- // changed line may become invalid.
- if (i == 0 || wp->w_lines[i].wl_lnum < lnume
- || (wp->w_lines[i].wl_lnum == lnume
- && wp->w_buffer->b_virt_line_blocks > 0)) {
- // line included in change
- wp->w_lines[i].wl_valid = false;
- } else if (xtra != 0) {
- // line below change
- wp->w_lines[i].wl_lnum += xtra;
- wp->w_lines[i].wl_lastlnum += xtra;
- }
- } else if (wp->w_lines[i].wl_lastlnum >= lnum) {
- // change somewhere inside this range of folded lines,
- // may need to be redrawn
- wp->w_lines[i].wl_valid = false;
- }
- }
- }
+ changed_lines_invalidate_win(wp, lnum, col, lnume, xtra);
// Take care of side effects for setting w_topline when folds have
// changed. Esp. when the buffer was changed in another window.
@@ -345,20 +377,19 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
}
// If lines have been added or removed, relative numbering always
- // requires a redraw.
+ // requires an update even if cursor didn't move.
if (wp->w_p_rnu && xtra != 0) {
wp->w_last_cursor_lnum_rnu = 0;
- redraw_later(wp, UPD_VALID);
}
- // Cursor line highlighting probably need to be updated with
- // "UPD_VALID" if it's below the change.
- // If the cursor line is inside the change we need to redraw more.
- if (wp->w_p_cul) {
- if (xtra == 0) {
- redraw_later(wp, UPD_VALID);
- } else if (lnum <= wp->w_last_cursorline) {
- redraw_later(wp, UPD_SOME_VALID);
+ if (wp->w_p_cul && wp->w_last_cursorline >= lnum) {
+ if (wp->w_last_cursorline < lnume) {
+ // If 'cursorline' was inside the change, it has already
+ // been invalidated in w_lines[] by the loop above.
+ wp->w_last_cursorline = 0;
+ } else {
+ // If 'cursorline' was below the change, adjust its lnum.
+ wp->w_last_cursorline += xtra;
}
}
}
@@ -366,9 +397,7 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum
// Call update_screen() later, which checks out what needs to be redrawn,
// since it notices b_mod_set and then uses b_mod_*.
- if (must_redraw < UPD_VALID) {
- must_redraw = UPD_VALID;
- }
+ set_must_redraw(UPD_VALID);
// when the cursor line is changed always trigger CursorMoved
if (last_cursormoved_win == curwin && curwin->w_buffer == buf
@@ -481,13 +510,13 @@ void deleted_lines_mark(linenr_T lnum, int count)
}
/// Marks the area to be redrawn after a change.
-/// Consider also calling changed_line_display_buf().
+/// Consider also calling changed_lines_invalidate_buf().
///
/// @param buf the buffer where lines were changed
/// @param lnum first line with change
/// @param lnume line below last changed line
/// @param xtra number of extra lines (negative when deleting)
-void buf_redraw_changed_lines_later(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
+void changed_lines_redraw_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
{
if (buf->b_mod_set) {
// find the maximum area that must be redisplayed
@@ -535,7 +564,7 @@ void buf_redraw_changed_lines_later(buf_T *buf, linenr_T lnum, linenr_T lnume, l
void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra,
bool do_buf_event)
{
- buf_redraw_changed_lines_later(buf, lnum, lnume, xtra);
+ changed_lines_redraw_buf(buf, lnum, lnume, xtra);
if (xtra == 0 && curwin->w_p_diff && curwin->w_buffer == buf && !diff_internal()) {
// When the number of lines doesn't change then mark_adjust() isn't
@@ -548,8 +577,7 @@ void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linen
redraw_later(wp, UPD_VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0) {
- buf_redraw_changed_lines_later(wp->w_buffer, wlnum,
- lnume - lnum + wlnum, 0);
+ changed_lines_redraw_buf(wp->w_buffer, wlnum, lnume - lnum + wlnum, 0);
}
}
}
@@ -568,7 +596,7 @@ void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linen
/// When `ff` is true also reset 'fileformat'.
/// When `always_inc_changedtick` is true b:changedtick is incremented even
/// when the changed flag was off.
-void unchanged(buf_T *buf, int ff, bool always_inc_changedtick)
+void unchanged(buf_T *buf, bool ff, bool always_inc_changedtick)
{
if (buf->b_changed || (ff && file_ff_differs(buf, false))) {
buf->b_changed = false;
@@ -923,8 +951,9 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
/// Copy the indent from ptr to the current line (and fill to size).
/// Leaves the cursor on the first non-blank in the line.
+///
/// @return true if the line was changed.
-int copy_indent(int size, char *src)
+bool copy_indent(int size, char *src)
{
char *p = NULL;
char *line = NULL;
@@ -1054,7 +1083,7 @@ int copy_indent(int size, char *src)
/// @param dir FORWARD or BACKWARD
///
/// @return true on success, false on failure
-int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
+bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
{
char *next_line = NULL; // copy of the next line
char *p_extra = NULL; // what goes to next line
@@ -1075,7 +1104,6 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
char saved_char = NUL; // init for GCC
pos_T *pos;
bool do_si = may_do_si();
- bool do_cindent;
bool no_si = false; // reset did_si afterwards
int first_char = NUL; // init for GCC
int vreplace_mode;
@@ -1142,9 +1170,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// indent to use for the new line.
if (curbuf->b_p_ai || do_si) {
// count white space on current line
- newindent = get_indent_str_vtab(saved_line,
- curbuf->b_p_ts,
- curbuf->b_p_vts_array, false);
+ newindent = indent_size_ts(saved_line, curbuf->b_p_ts, curbuf->b_p_vts_array);
if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) {
newindent = second_line_indent; // for ^^D command in insert mode
}
@@ -1156,10 +1182,8 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// "if (condition) {"
if (!trunc_line && do_si && *saved_line != NUL
&& (p_extra == NULL || first_char != '{')) {
- char *ptr;
-
old_cursor = curwin->w_cursor;
- ptr = saved_line;
+ char *ptr = saved_line;
if (flags & OPENLINE_DO_COM) {
lead_len = get_leader_len(ptr, NULL, false, true);
} else {
@@ -1289,9 +1313,9 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// May do indenting after opening a new line.
- do_cindent = !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL)
- && in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW : KEY_OPEN_BACK,
- ' ', linewhite(curwin->w_cursor.lnum));
+ bool do_cindent = !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL)
+ && in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW : KEY_OPEN_BACK,
+ ' ', linewhite(curwin->w_cursor.lnum));
// Find out if the current line starts with a comment leader.
// This may then be inserted in front of the new line.
@@ -1322,8 +1346,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
char lead_end[COM_MAX_LEN]; // end-comment string
char *comment_end = NULL; // where lead_end has been found
int extra_space = false; // append extra space
- int current_flag;
- int require_blank = false; // requires blank after middle
+ bool require_blank = false; // requires blank after middle
char *p2;
// If the comment leader has the start, middle or end flag, it may not
@@ -1334,7 +1357,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
continue;
}
if (*p == COM_START || *p == COM_MIDDLE) {
- current_flag = (unsigned char)(*p);
+ int current_flag = (unsigned char)(*p);
if (*p == COM_START) {
// Doing "O" on a start of comment does not insert leader.
if (dir == BACKWARD) {
@@ -1343,7 +1366,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// find start of middle part
- (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+ copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
require_blank = false;
}
@@ -1354,7 +1377,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
p++;
}
- (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+ copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
while (*p && p[-1] != ':') { // find end of end flags
// Check whether we allow automatic ending of comments
@@ -1499,13 +1522,12 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
int repl_size = vim_strnsize(lead_repl, lead_repl_len);
int old_size = 0;
char *endp = p;
- int l;
while (old_size < repl_size && p > leader) {
MB_PTR_BACK(leader, p);
old_size += ptr2cells(p);
}
- l = lead_repl_len - (int)(endp - p);
+ int l = lead_repl_len - (int)(endp - p);
if (l != 0) {
memmove(endp + l, endp,
(size_t)((leader + lead_len) - endp));
@@ -1590,9 +1612,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
// Recompute the indent, it may have changed.
if (curbuf->b_p_ai || do_si) {
- newindent = get_indent_str_vtab(leader,
- curbuf->b_p_ts,
- curbuf->b_p_vts_array, false);
+ newindent = indent_size_ts(leader, curbuf->b_p_ts, curbuf->b_p_vts_array);
}
// Add the indent offset
@@ -1732,7 +1752,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed) {
// In case we NL to a new line, BS to the previous one, and NL
// again, we don't want to save the new line for undo twice.
- (void)u_save_cursor(); // errors are ignored!
+ u_save_cursor(); // errors are ignored!
vr_lines_changed++;
}
ml_replace(curwin->w_cursor.lnum, p_extra, true);
@@ -1755,14 +1775,14 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
}
// Copy the indent
if (curbuf->b_p_ci) {
- (void)copy_indent(newindent, saved_line);
+ copy_indent(newindent, saved_line);
// Set the 'preserveindent' option so that any further screwing
// with the line doesn't entirely destroy our efforts to preserve
// it. It gets restored at the function end.
curbuf->b_p_pi = true;
} else {
- (void)set_indent(newindent, SIN_INSERT|SIN_NOMARK);
+ set_indent(newindent, SIN_INSERT|SIN_NOMARK);
}
less_cols -= curwin->w_cursor.col;
@@ -1840,11 +1860,11 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
curwin->w_cursor.lnum = old_cursor.lnum + 1;
}
if (did_append) {
- changed_lines(curbuf, curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1, true);
// bail out and just get the final length of the line we just manipulated
bcount_t extra = (bcount_t)strlen(ml_get(curwin->w_cursor.lnum));
extmark_splice(curbuf, (int)curwin->w_cursor.lnum - 1, 0,
0, 0, 0, 1, 0, 1 + extra, kExtmarkUndo);
+ changed_lines(curbuf, curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1, true);
}
curbuf_splice_pending--;
@@ -1980,7 +2000,7 @@ void del_lines(linenr_T nlines, bool undo)
int get_leader_len(char *line, char **flags, bool backward, bool include_space)
{
int j;
- int got_com = false;
+ bool got_com = false;
char part_buf[COM_MAX_LEN]; // buffer for one option part
char *string; // pointer to comment string
int middle_match_len = 0;
@@ -1995,7 +2015,7 @@ int get_leader_len(char *line, char **flags, bool backward, bool include_space)
// Repeat to match several nested comment strings.
while (line[i] != NUL) {
// scan through the 'comments' option for a match
- int found_one = false;
+ bool found_one = false;
for (char *list = curbuf->b_p_com; *list;) {
// Get one option part into part_buf[]. Advance "list" to next
// one. Put "string" at start of string.
@@ -2003,7 +2023,7 @@ int get_leader_len(char *line, char **flags, bool backward, bool include_space)
*flags = list; // remember where flags started
}
char *prev_list = list;
- (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
string = vim_strchr(part_buf, ':');
if (string == NULL) { // missing ':', ignore this part
continue;
@@ -2122,24 +2142,22 @@ int get_last_leader_offset(char *line, char **flags)
int result = -1;
int j;
int lower_check_bound = 0;
- char *string;
char *com_leader;
char *com_flags;
- char *list;
char part_buf[COM_MAX_LEN]; // buffer for one option part
// Repeat to match several nested comment strings.
int i = (int)strlen(line);
while (--i >= lower_check_bound) {
// scan through the 'comments' option for a match
- int found_one = false;
- for (list = curbuf->b_p_com; *list;) {
+ bool found_one = false;
+ for (char *list = curbuf->b_p_com; *list;) {
char *flags_save = list;
// Get one option part into part_buf[]. Advance list to next one.
// put string at start of string.
- (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
- string = vim_strchr(part_buf, ':');
+ copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ char *string = vim_strchr(part_buf, ':');
if (string == NULL) { // If everything is fine, this cannot actually
// happen.
continue;
@@ -2217,14 +2235,14 @@ int get_last_leader_offset(char *line, char **flags)
}
int len1 = (int)strlen(com_leader);
- for (list = curbuf->b_p_com; *list;) {
+ for (char *list = curbuf->b_p_com; *list;) {
char *flags_save = list;
- (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
+ copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
if (flags_save == com_flags) {
continue;
}
- string = vim_strchr(part_buf2, ':');
+ char *string = vim_strchr(part_buf2, ':');
string++;
while (ascii_iswhite(*string)) {
string++;