aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/diff.c')
-rw-r--r--src/nvim/diff.c168
1 files changed, 96 insertions, 72 deletions
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 7da6665cb7..0ee1c3815d 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -135,6 +135,20 @@ void diff_buf_add(buf_T *buf)
EMSGN(_("E96: Cannot diff more than %" PRId64 " buffers"), DB_COUNT);
}
+///
+/// Remove all buffers to make diffs for.
+///
+static void diff_buf_clear(void)
+{
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ curtab->tp_diffbuf[i] = NULL;
+ curtab->tp_diff_invalid = true;
+ diff_redraw(true);
+ }
+ }
+}
+
/// Find buffer "buf" in the list of diff buffers for the current tab page.
///
/// @param buf The buffer to find.
@@ -841,12 +855,13 @@ void ex_diffpatch(exarg_T *eap)
{
char_u *buf = NULL;
win_T *old_curwin = curwin;
- char_u *newname = NULL; // name of patched file buffer
+ char_u *newname = NULL; // name of patched file buffer
+ char_u *esc_name = NULL;
#ifdef UNIX
char_u dirbuf[MAXPATHL];
char_u *fullname = NULL;
-#endif // ifdef UNIX
+#endif
// We need two temp file names.
// Name of original temp file.
char_u *tmp_orig = vim_tempname();
@@ -866,21 +881,21 @@ void ex_diffpatch(exarg_T *eap)
#ifdef UNIX
// Get the absolute path of the patchfile, changing directory below.
- fullname = (char_u *)FullName_save((char *)eap->arg, FALSE);
-#endif // ifdef UNIX
+ fullname = (char_u *)FullName_save((char *)eap->arg, false);
+#endif
+ esc_name = vim_strsave_shellescape(
#ifdef UNIX
- size_t buflen = STRLEN(tmp_orig)
- + (fullname != NULL ? STRLEN(fullname) : STRLEN(eap->arg))
- + STRLEN(tmp_new) + 16;
-#else
- size_t buflen = STRLEN(tmp_orig) + (STRLEN(eap->arg)) + STRLEN(tmp_new) + 16;
-#endif // ifdef UNIX
-
+ fullname != NULL ? fullname :
+#endif
+ eap->arg, true, true);
+ if (esc_name == NULL) {
+ goto theend;
+ }
+ size_t buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16;
buf = xmalloc(buflen);
#ifdef UNIX
-
// Temporarily chdir to /tmp, to avoid patching files in the current
// directory when the patch file contains more than one patch. When we
// have our own temp dir use that instead, it will be cleaned up when we
@@ -897,26 +912,21 @@ void ex_diffpatch(exarg_T *eap)
os_chdir(tempdir);
shorten_fnames(TRUE);
}
-#endif // ifdef UNIX
+#endif
if (*p_pex != NUL) {
// Use 'patchexpr' to generate the new file.
#ifdef UNIX
- eval_patch((char *) tmp_orig,
- (char *) (fullname != NULL ? fullname : eap->arg),
- (char *) tmp_new);
+ eval_patch((char *)tmp_orig,
+ (char *)(fullname != NULL ? fullname : eap->arg),
+ (char *)tmp_new);
#else
- eval_patch((char *) tmp_orig, (char *) eap->arg, (char *) tmp_new);
-#endif // ifdef UNIX
+ eval_patch((char *)tmp_orig, (char *)eap->arg, (char *)tmp_new);
+#endif
} else {
// Build the patch command and execute it. Ignore errors.
-#ifdef UNIX
- vim_snprintf((char *)buf, buflen, "patch -o %s %s < \"%s\"",
- tmp_new, tmp_orig, fullname != NULL ? fullname : eap->arg);
-#else
- vim_snprintf((char *)buf, buflen, "patch -o %s %s < \"%s\"",
- tmp_new, tmp_orig, eap->arg);
-#endif // ifdef UNIX
+ vim_snprintf((char *)buf, buflen, "patch -o %s %s < %s",
+ tmp_new, tmp_orig, esc_name);
block_autocmds(); // Avoid ShellCmdPost stuff
(void)call_shell(buf, kShellOptFilter, NULL);
unblock_autocmds();
@@ -929,10 +939,7 @@ void ex_diffpatch(exarg_T *eap)
}
shorten_fnames(TRUE);
}
-#endif // ifdef UNIX
-
- // patch probably has written over the screen
- redraw_later(CLEAR);
+#endif
// Delete any .orig or .rej file created.
STRCPY(buf, tmp_new);
@@ -998,7 +1005,8 @@ theend:
xfree(buf);
#ifdef UNIX
xfree(fullname);
-#endif // ifdef UNIX
+#endif
+ xfree(esc_name);
}
/// Split the window and edit another file, setting options to show the diffs.
@@ -1033,10 +1041,7 @@ void ex_diffsplit(exarg_T *eap)
if (bufref_valid(&old_curbuf)) {
// Move the cursor position to that of the old window.
curwin->w_cursor.lnum = diff_get_corresponding_line(
- old_curbuf.br_buf,
- old_curwin->w_cursor.lnum,
- curbuf,
- curwin->w_cursor.lnum);
+ old_curbuf.br_buf, old_curwin->w_cursor.lnum);
}
}
// Now that lines are folded scroll to show the cursor at the same
@@ -1053,6 +1058,20 @@ void ex_diffthis(exarg_T *eap)
diff_win_options(curwin, TRUE);
}
+static void set_diff_option(win_T *wp, int value)
+{
+ win_T *old_curwin = curwin;
+
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ curbuf_lock++;
+ set_option_value("diff", (long)value, NULL, OPT_LOCAL);
+ curbuf_lock--;
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+}
+
+
/// Set options in window "wp" for diff mode.
///
/// @param addbuf Add buffer to diff.
@@ -1110,10 +1129,10 @@ void diff_win_options(win_T *wp, int addbuf)
do_cmdline_cmd("set sbo+=hor");
}
- // Saved the current values, to be restored in ex_diffoff().
- wp->w_p_diff_saved = TRUE;
+ // Save the current values, to be restored in ex_diffoff().
+ wp->w_p_diff_saved = true;
- wp->w_p_diff = true;
+ set_diff_option(wp, true);
if (addbuf) {
diff_buf_add(wp->w_buffer);
@@ -1134,7 +1153,7 @@ void ex_diffoff(exarg_T *eap)
// Set 'diff' off. If option values were saved in
// diff_win_options(), restore the ones whose settings seem to have
// been left over from diff mode.
- wp->w_p_diff = false;
+ set_diff_option(wp, false);
if (wp->w_p_diff_saved) {
if (wp->w_p_scb) {
@@ -1150,7 +1169,9 @@ void ex_diffoff(exarg_T *eap)
}
free_string_option(wp->w_p_fdm);
- wp->w_p_fdm = vim_strsave(wp->w_p_fdm_save);
+ wp->w_p_fdm = vim_strsave(*wp->w_p_fdm_save
+ ? wp->w_p_fdm_save
+ : (char_u *)"manual");
if (wp->w_p_fdc == diff_foldcolumn) {
wp->w_p_fdc = wp->w_p_fdc_save;
}
@@ -1178,6 +1199,11 @@ void ex_diffoff(exarg_T *eap)
diffwin |= wp->w_p_diff;
}
+ // Also remove hidden buffers from the list.
+ if (eap->forceit) {
+ diff_buf_clear();
+ }
+
// Remove "hor" from from 'scrollopt' if there are no diff windows left.
if (!diffwin && (vim_strchr(p_sbo, 'h') != NULL)) {
do_cmdline_cmd("set sbo-=hor");
@@ -2255,7 +2281,7 @@ void ex_diffgetput(exarg_T *eap)
}
}
- buf_empty = bufempty();
+ buf_empty = BUFEMPTY();
added = 0;
for (i = 0; i < count; ++i) {
@@ -2463,25 +2489,17 @@ int diff_move_to(int dir, long count)
return OK;
}
-/// Finds the corresponding line in a diff.
-///
-/// @param buf1
-/// @param lnum1
-/// @param buf2
-/// @param lnum3
-///
-/// @return The corresponding line.
-linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1, buf_T *buf2,
- linenr_T lnum3)
+/// Return the line number in the current window that is closest to "lnum1" in
+/// "buf1" in diff mode.
+static linenr_T diff_get_corresponding_line_int(buf_T *buf1, linenr_T lnum1)
{
int idx1;
int idx2;
diff_T *dp;
int baseline = 0;
- linenr_T lnum2;
idx1 = diff_buf_idx(buf1);
- idx2 = diff_buf_idx(buf2);
+ idx2 = diff_buf_idx(curbuf);
if ((idx1 == DB_COUNT)
|| (idx2 == DB_COUNT)
@@ -2501,15 +2519,9 @@ linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1, buf_T *buf2,
for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) {
if (dp->df_lnum[idx1] > lnum1) {
- lnum2 = lnum1 - baseline;
-
- // don't end up past the end of the file
- if (lnum2 > buf2->b_ml.ml_line_count) {
- lnum2 = buf2->b_ml.ml_line_count;
- }
-
- return lnum2;
- } else if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) {
+ return lnum1 - baseline;
+ }
+ if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) {
// Inside the diffblock
baseline = lnum1 - dp->df_lnum[idx1];
@@ -2518,30 +2530,42 @@ linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1, buf_T *buf2,
}
return dp->df_lnum[idx2] + baseline;
- } else if ((dp->df_lnum[idx1] == lnum1)
- && (dp->df_count[idx1] == 0)
- && (dp->df_lnum[idx2] <= lnum3)
- && ((dp->df_lnum[idx2] + dp->df_count[idx2]) > lnum3)) {
+ }
+ if ((dp->df_lnum[idx1] == lnum1)
+ && (dp->df_count[idx1] == 0)
+ && (dp->df_lnum[idx2] <= curwin->w_cursor.lnum)
+ && ((dp->df_lnum[idx2] + dp->df_count[idx2])
+ > curwin->w_cursor.lnum)) {
// Special case: if the cursor is just after a zero-count
// block (i.e. all filler) and the target cursor is already
// inside the corresponding block, leave the target cursor
// unmoved. This makes repeated CTRL-W W operations work
// as expected.
- return lnum3;
+ return curwin->w_cursor.lnum;
}
baseline = (dp->df_lnum[idx1] + dp->df_count[idx1])
- - (dp->df_lnum[idx2] + dp->df_count[idx2]);
+ - (dp->df_lnum[idx2] + dp->df_count[idx2]);
}
// If we get here then the cursor is after the last diff
- lnum2 = lnum1 - baseline;
+ return lnum1 - baseline;
+}
+
+/// Finds the corresponding line in a diff.
+///
+/// @param buf1
+/// @param lnum1
+///
+/// @return The corresponding line.
+linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1)
+{
+ linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1);
// don't end up past the end of the file
- if (lnum2 > buf2->b_ml.ml_line_count) {
- lnum2 = buf2->b_ml.ml_line_count;
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ return curbuf->b_ml.ml_line_count;
}
-
- return lnum2;
+ return lnum;
}
/// For line "lnum" in the current window find the equivalent lnum in window