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 | 
