diff options
Diffstat (limited to 'src/nvim/diff.c')
| -rw-r--r-- | src/nvim/diff.c | 179 |
1 files changed, 101 insertions, 78 deletions
diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ff76abc01f..f9e40ed06f 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + /// @file diff.c /// /// Code for diff'ing two, three or four buffers. @@ -132,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. @@ -838,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 + char *fullname = NULL; +#endif + // We need two temp file names. // Name of original temp file. char_u *tmp_orig = vim_tempname(); @@ -863,21 +881,17 @@ 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 - -#ifdef UNIX - size_t buflen = STRLEN(tmp_orig) - + (fullname != NULL ? STRLEN(fullname) : STRLEN(eap->arg)) - + STRLEN(tmp_new) + 16; + fullname = FullName_save((char *)eap->arg, false); + esc_name = vim_strsave_shellescape( + (fullname != NULL ? (char_u *)fullname : eap->arg), true, true); #else - size_t buflen = STRLEN(tmp_orig) + (STRLEN(eap->arg)) + STRLEN(tmp_new) + 16; -#endif // ifdef UNIX - + esc_name = vim_strsave_shellescape(eap->arg, true, true); +#endif + size_t buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16; buf = xmalloc(buflen); #ifdef UNIX - + char_u dirbuf[MAXPATHL]; // 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 @@ -894,26 +908,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, + (fullname != NULL ? fullname : (char *)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(); @@ -926,10 +935,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); @@ -995,7 +1001,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. @@ -1030,10 +1037,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 @@ -1050,6 +1054,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. @@ -1076,8 +1094,8 @@ void diff_win_options(win_T *wp, int addbuf) if (!wp->w_p_diff) { wp->w_p_wrap_save = wp->w_p_wrap; } - wp->w_p_wrap = FALSE; - curwin = wp; + wp->w_p_wrap = false; + curwin = wp; // -V519 curbuf = curwin->w_buffer; if (!wp->w_p_diff) { @@ -1107,10 +1125,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); @@ -1131,7 +1149,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) { @@ -1147,7 +1165,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; } @@ -1175,6 +1195,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"); @@ -2252,7 +2277,7 @@ void ex_diffgetput(exarg_T *eap) } } - buf_empty = bufempty(); + buf_empty = BUFEMPTY(); added = 0; for (i = 0; i < count; ++i) { @@ -2308,7 +2333,7 @@ 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, (long)added); + mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added, false); if (curwin->w_cursor.lnum >= lnum) { // Adjust the cursor position if it's in/after the changed // lines. @@ -2460,25 +2485,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) @@ -2498,15 +2515,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]; @@ -2515,30 +2526,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 |
