aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/diff.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2022-08-03 00:08:17 -0600
committerJosh Rahm <joshuarahm@gmail.com>2022-08-03 00:08:17 -0600
commit9449e1b8d273ff78eb894c588110ffa0c17d6ee3 (patch)
tree9e4470c33bd4187d9f42f0b2c4aaa995310c5be8 /src/nvim/diff.c
parent308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (diff)
parentb8dcbcc732baf84fc48d6b272c3ade0bcb129b3b (diff)
downloadrneovim-9449e1b8d273ff78eb894c588110ffa0c17d6ee3.tar.gz
rneovim-9449e1b8d273ff78eb894c588110ffa0c17d6ee3.tar.bz2
rneovim-9449e1b8d273ff78eb894c588110ffa0c17d6ee3.zip
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'src/nvim/diff.c')
-rw-r--r--src/nvim/diff.c70
1 files changed, 48 insertions, 22 deletions
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 75021e90d6..849204f789 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -115,7 +115,10 @@ void diff_buf_delete(buf_T *buf)
tp->tp_diff_invalid = true;
if (tp == curtab) {
- diff_redraw(true);
+ // don't redraw right away, more might change or buffer state
+ // is invalid right now
+ need_diff_redraw = true;
+ redraw_later(curwin, VALID);
}
}
}
@@ -369,9 +372,8 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
// 2. 3. 4. 5.: inserted/deleted lines touching this diff.
if (deleted > 0) {
+ off = 0;
if (dp->df_lnum[idx] >= line1) {
- off = dp->df_lnum[idx] - lnum_deleted;
-
if (last <= line2) {
// 4. delete all lines of diff
if ((dp->df_next != NULL)
@@ -388,14 +390,13 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
dp->df_count[idx] = 0;
} else {
// 5. delete lines at or just before top of diff
+ off = dp->df_lnum[idx] - lnum_deleted;
n = off;
dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1;
check_unchanged = true;
}
dp->df_lnum[idx] = line1;
} else {
- off = 0;
-
if (last < line2) {
// 2. delete at end of diff
dp->df_count[idx] -= last - lnum_deleted + 1;
@@ -418,10 +419,13 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
}
}
- int i;
- for (i = 0; i < DB_COUNT; i++) {
+ for (int i = 0; i < DB_COUNT; i++) {
if ((tp->tp_diffbuf[i] != NULL) && (i != idx)) {
- dp->df_lnum[i] -= off;
+ if (dp->df_lnum[i] > off) {
+ dp->df_lnum[i] -= off;
+ } else {
+ dp->df_lnum[i] = 1;
+ }
dp->df_count[i] += n;
}
}
@@ -648,9 +652,11 @@ void diff_redraw(bool dofold)
need_diff_redraw = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (!wp->w_p_diff) {
+ // when closing windows or wiping buffers skip invalid window
+ if (!wp->w_p_diff || !buf_valid(wp->w_buffer)) {
continue;
}
+
redraw_later(wp, SOME_VALID);
if (wp != curwin) {
wp_other = wp;
@@ -659,8 +665,8 @@ void diff_redraw(bool dofold)
foldUpdateAll(wp);
}
- // A change may have made filler lines invalid, need to take care
- // of that for other windows.
+ // A change may have made filler lines invalid, need to take care of
+ // that for other windows.
int n = diff_check(wp, wp->w_topline);
if (((wp != curwin) && (wp->w_topfill > 0)) || (n > 0)) {
@@ -677,6 +683,7 @@ void diff_redraw(bool dofold)
check_topfill(wp, false);
}
}
+
if (wp_other != NULL && curwin->w_p_scb) {
if (used_max_fill_curwin) {
// The current window was set to use the maximum number of filler
@@ -1421,7 +1428,7 @@ void diff_win_options(win_T *wp, int addbuf)
}
wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc);
}
- xfree(wp->w_p_fdc);
+ free_string_option(wp->w_p_fdc);
wp->w_p_fdc = (char_u *)xstrdup("2");
assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9);
snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn);
@@ -2485,6 +2492,17 @@ void nv_diffgetput(bool put, size_t count)
ex_diffgetput(&ea);
}
+/// Return true if "diff" appears in the list of diff blocks of the current tab.
+static bool valid_diff(diff_T *diff)
+{
+ for (diff_T *dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) {
+ if (dp == diff) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// ":diffget" and ":diffput"
///
/// @param eap
@@ -2694,8 +2712,9 @@ void ex_diffgetput(exarg_T *eap)
for (i = 0; i < count; i++) {
// remember deleting the last line of the buffer
buf_empty = curbuf->b_ml.ml_line_count == 1;
- ml_delete(lnum, false);
- added--;
+ if (ml_delete(lnum, false) == OK) {
+ added--;
+ }
}
for (i = 0; i < dp->df_count[idx_from] - start_skip - end_skip; i++) {
@@ -2742,10 +2761,9 @@ void ex_diffgetput(exarg_T *eap)
}
}
- // Adjust marks. This will change the following entries!
if (added != 0) {
- mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added,
- kExtmarkUndo);
+ // Adjust marks. This will change the following entries!
+ mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, added, kExtmarkUndo);
if (curwin->w_cursor.lnum >= lnum) {
// Adjust the cursor position if it's in/after the changed
// lines.
@@ -2762,7 +2780,15 @@ void ex_diffgetput(exarg_T *eap)
// Diff is deleted, update folds in other windows.
diff_fold_update(dfree, idx_to);
xfree(dfree);
- } else {
+ }
+
+ // mark_adjust() may have made "dp" invalid. We don't know where
+ // to continue then, bail out.
+ if (added != 0 && !valid_diff(dp)) {
+ break;
+ }
+
+ if (dfree == NULL) {
// mark_adjust() may have changed the count in a wrong way
dp->df_count[idx_to] = new_count;
}
@@ -3042,8 +3068,8 @@ static int parse_diff_ed(char_u *line, diffhunk_T *hunk)
// change: {first}[,{last}]c{first}[,{last}]
// append: {first}a{first}[,{last}]
// delete: {first}[,{last}]d{first}
- char_u *p = line;
- linenr_T f1 = getdigits_int32((char **)&p, true, 0);
+ char *p = (char *)line;
+ linenr_T f1 = getdigits_int32(&p, true, 0);
if (*p == ',') {
p++;
l1 = getdigits(&p, true, 0);
@@ -3053,7 +3079,7 @@ static int parse_diff_ed(char_u *line, diffhunk_T *hunk)
if (*p != 'a' && *p != 'c' && *p != 'd') {
return FAIL; // invalid diff format
}
- int difftype = *p++;
+ int difftype = (uint8_t)(*p++);
long f2 = getdigits(&p, true, 0);
if (*p == ',') {
p++;
@@ -3090,7 +3116,7 @@ static int parse_diff_unified(char_u *line, diffhunk_T *hunk)
{
// Parse unified diff hunk header:
// @@ -oldline,oldcount +newline,newcount @@
- char_u *p = line;
+ char *p = (char *)line;
if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-') {
long oldcount;
long newline;