diff options
Diffstat (limited to 'src/nvim/diff.c')
-rw-r--r-- | src/nvim/diff.c | 168 |
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 |