aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/diff.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /src/nvim/diff.c
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'src/nvim/diff.c')
-rw-r--r--src/nvim/diff.c1449
1 files changed, 893 insertions, 556 deletions
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 5485d528f7..032de561b3 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -10,9 +10,15 @@
/// - Use the compiled-in xdiff library.
/// - Let 'diffexpr' do the work, using files.
+#include <assert.h>
+#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "auto/config.h"
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
@@ -23,9 +29,15 @@
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
+#include "nvim/extmark_defs.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/linematch.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -35,10 +47,13 @@
#include "nvim/normal.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
+#include "nvim/os/fs_defs.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
+#include "nvim/pos.h"
#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
@@ -61,10 +76,12 @@ static bool diff_need_update = false; // ex_diffupdate needs to be called
#define DIFF_INTERNAL 0x200 // use internal xdiff algorithm
#define DIFF_CLOSE_OFF 0x400 // diffoff when closing window
#define DIFF_FOLLOWWRAP 0x800 // follow the wrap option
+#define DIFF_LINEMATCH 0x1000 // match most similar lines within diff
#define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL)
static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF;
static long diff_algorithm = 0;
+static int linematch_lines = 0;
#define LBUFLEN 50 // length of line in diff file
@@ -74,13 +91,13 @@ static TriState diff_a_works = kNone;
// used for diff input
typedef struct {
- char_u *din_fname; // used for external diff
+ char *din_fname; // used for external diff
mmfile_t din_mmfile; // used for internal diff
} diffin_T;
// used for diff result
typedef struct {
- char_u *dout_fname; // used for external diff
+ char *dout_fname; // used for external diff
garray_T dout_ga; // used for internal diff
} diffout_T;
@@ -100,6 +117,12 @@ typedef struct {
int dio_internal; // using internal diff
} diffio_T;
+typedef enum {
+ DIFF_ED,
+ DIFF_UNIFIED,
+ DIFF_NONE,
+} diffstyle_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "diff.c.generated.h"
#endif
@@ -120,7 +143,7 @@ void diff_buf_delete(buf_T *buf)
// don't redraw right away, more might change or buffer state
// is invalid right now
need_diff_redraw = true;
- redraw_later(curwin, VALID);
+ redraw_later(curwin, UPD_VALID);
}
}
}
@@ -204,13 +227,7 @@ static void diff_buf_clear(void)
/// @return Its index or DB_COUNT if not found.
static int diff_buf_idx(buf_T *buf)
{
- int idx;
- for (idx = 0; idx < DB_COUNT; idx++) {
- if (curtab->tp_diffbuf[idx] == buf) {
- break;
- }
- }
- return idx;
+ return diff_buf_idx_tp(buf, curtab);
}
/// Find buffer "buf" in the list of diff buffers for tab page "tp".
@@ -309,8 +326,6 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
diff_T *dp = tp->tp_first_diff;
linenr_T lnum_deleted = line1; // lnum of remaining deletion
- linenr_T n;
- linenr_T off;
for (;;) {
// If the change is after the previous diff block and before the next
// diff block, thus not touching an existing change, create a new diff
@@ -363,7 +378,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
if (last >= line1 - 1) {
// 6. change below line2: only adjust for amount_after; also when
// "deleted" became zero when deleted all lines between two diffs.
- if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2) {
+ if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2 - dp->is_linematched) {
if (amount_after == 0) {
// nothing left to change
break;
@@ -374,7 +389,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;
+ linenr_T n;
+ linenr_T off = 0;
if (dp->df_lnum[idx] >= line1) {
if (last <= line2) {
// 4. delete all lines of diff
@@ -454,7 +470,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
}
// check if this block touches the previous one, may merge them.
- if ((dprev != NULL)
+ if ((dprev != NULL) && !dp->is_linematched
&& (dprev->df_lnum[idx] + dprev->df_count[idx] == dp->df_lnum[idx])) {
int i;
for (i = 0; i < DB_COUNT; i++) {
@@ -462,9 +478,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
dprev->df_count[i] += dp->df_count[i];
}
}
- dprev->df_next = dp->df_next;
- xfree(dp);
- dp = dprev->df_next;
+ dp = diff_free(tp, dprev, dp);
} else {
// Advance to next entry.
dprev = dp;
@@ -485,15 +499,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
}
if (i == DB_COUNT) {
- diff_T *dnext = dp->df_next;
- xfree(dp);
- dp = dnext;
-
- if (dprev == NULL) {
- tp->tp_first_diff = dnext;
- } else {
- dprev->df_next = dnext;
- }
+ dp = diff_free(tp, dprev, dp);
} else {
// Advance to next entry.
dprev = dp;
@@ -523,6 +529,7 @@ static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
{
diff_T *dnew = xmalloc(sizeof(*dnew));
+ dnew->is_linematched = false;
dnew->df_next = dp;
if (dprev == NULL) {
tp->tp_first_diff = dnew;
@@ -533,6 +540,20 @@ static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
return dnew;
}
+static diff_T *diff_free(tabpage_T *tp, diff_T *dprev, diff_T *dp)
+{
+ diff_T *ret = dp->df_next;
+ xfree(dp);
+
+ if (dprev == NULL) {
+ tp->tp_first_diff = ret;
+ } else {
+ dprev->df_next = ret;
+ }
+
+ return ret;
+}
+
/// Check if the diff block "dp" can be made smaller for lines at the start and
/// end that are equal. Called after inserting lines.
///
@@ -573,9 +594,9 @@ static void diff_check_unchanged(tabpage_T *tp, diff_T *dp)
if (dir == BACKWARD) {
off_org = dp->df_count[i_org] - 1;
}
- char_u *line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org],
- dp->df_lnum[i_org] + off_org,
- false));
+ char *line_org = xstrdup(ml_get_buf(tp->tp_diffbuf[i_org],
+ dp->df_lnum[i_org] + off_org,
+ false));
int i_new;
for (i_new = i_org + 1; i_new < DB_COUNT; i_new++) {
@@ -659,7 +680,7 @@ void diff_redraw(bool dofold)
continue;
}
- redraw_later(wp, SOME_VALID);
+ redraw_later(wp, UPD_SOME_VALID);
if (wp != curwin) {
wp_other = wp;
}
@@ -704,16 +725,16 @@ static void clear_diffin(diffin_T *din)
if (din->din_fname == NULL) {
XFREE_CLEAR(din->din_mmfile.ptr);
} else {
- os_remove((char *)din->din_fname);
+ os_remove(din->din_fname);
}
}
static void clear_diffout(diffout_T *dout)
{
if (dout->dout_fname == NULL) {
- ga_clear_strings(&dout->dout_ga);
+ ga_clear(&dout->dout_ga);
} else {
- os_remove((char *)dout->dout_fname);
+ os_remove(dout->dout_fname);
}
}
@@ -723,15 +744,19 @@ static void clear_diffout(diffout_T *dout)
/// @param din
///
/// @return FAIL for failure.
-static int diff_write_buffer(buf_T *buf, diffin_T *din)
+static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T end)
{
- long len = 0;
+ size_t len = 0;
+
+ if (end < 0) {
+ end = buf->b_ml.ml_line_count;
+ }
// xdiff requires one big block of memory with all the text.
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
- len += (long)STRLEN(ml_get_buf(buf, lnum, false)) + 1;
+ for (linenr_T lnum = start; lnum <= end; lnum++) {
+ len += strlen(ml_get_buf(buf, lnum, false)) + 1;
}
- char_u *ptr = try_malloc((size_t)len);
+ char *ptr = try_malloc(len);
if (ptr == NULL) {
// Allocating memory failed. This can happen, because we try to read
// the whole buffer text into memory. Set the failed flag, the diff
@@ -745,37 +770,32 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
}
return FAIL;
}
- din->din_mmfile.ptr = (char *)ptr;
- din->din_mmfile.size = len;
+ m->ptr = ptr;
+ m->size = (long)len;
len = 0;
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
- for (char_u *s = ml_get_buf(buf, lnum, false); *s != NUL;) {
- if (diff_flags & DIFF_ICASE) {
- int c;
+ for (linenr_T lnum = start; lnum <= end; lnum++) {
+ char *s = ml_get_buf(buf, lnum, false);
+ if (diff_flags & DIFF_ICASE) {
+ while (*s != NUL) {
char cbuf[MB_MAXBYTES + 1];
- if (*s == NL) {
- c = NUL;
- } else {
- // xdiff doesn't support ignoring case, fold-case the text.
- c = utf_ptr2char((char *)s);
- c = utf_fold(c);
- }
- const int orig_len = utfc_ptr2len((char *)s);
- if (utf_char2bytes(c, (char *)cbuf) != orig_len) {
- // TODO(Bram): handle byte length difference
- memmove(ptr + len, s, (size_t)orig_len);
- } else {
- memmove(ptr + len, cbuf, (size_t)orig_len);
- }
+ // xdiff doesn't support ignoring case, fold-case the text.
+ int c = *s == NL ? NUL : utf_fold(utf_ptr2char(s));
+ const int orig_len = utfc_ptr2len(s);
+ // TODO(Bram): handle byte length difference
+ char *s1 = (utf_char2bytes(c, cbuf) != orig_len) ? s : cbuf;
+ memmove(ptr + len, s1, (size_t)orig_len);
s += orig_len;
- len += orig_len;
- } else {
- ptr[len++] = *s == NL ? NUL : *s;
- s++;
+ len += (size_t)orig_len;
}
+ } else {
+ size_t slen = strlen(s);
+ memmove(ptr + len, s, slen);
+ // NUL is represented as NL; convert
+ memchrsub(ptr + len, NL, NUL, slen);
+ len += slen;
}
ptr[len++] = NL;
}
@@ -793,17 +813,17 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
static int diff_write(buf_T *buf, diffin_T *din)
{
if (din->din_fname == NULL) {
- return diff_write_buffer(buf, din);
+ return diff_write_buffer(buf, &din->din_mmfile, 1, -1);
}
// Always use 'fileformat' set to "unix".
- char_u *save_ff = buf->b_p_ff;
- buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
+ char *save_ff = buf->b_p_ff;
+ buf->b_p_ff = xstrdup(FF_UNIX);
const bool save_cmod_flags = cmdmod.cmod_flags;
// Writing the buffer is an implementation detail of performing the diff,
// so it shouldn't update the '[ and '] marks.
cmdmod.cmod_flags |= CMOD_LOCKMARKS;
- int r = buf_write(buf, (char *)din->din_fname, NULL,
+ int r = buf_write(buf, din->din_fname, NULL,
(linenr_T)1, buf->b_ml.ml_line_count,
NULL, false, false, false, true);
cmdmod.cmod_flags = save_cmod_flags;
@@ -821,7 +841,7 @@ static int diff_write(buf_T *buf, diffin_T *din)
static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap)
{
if (dio->dio_internal) {
- ga_init(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
+ ga_init(&dio->dio_diff.dout_ga, sizeof(diffhunk_T), 100);
} else {
// We need three temp file names.
dio->dio_orig.din_fname = vim_tempname();
@@ -992,7 +1012,7 @@ static int check_external_diff(diffio_T *diffio)
TriState ok = kFalse;
for (;;) {
ok = kFalse;
- FILE *fd = os_fopen((char *)diffio->dio_orig.din_fname, "w");
+ FILE *fd = os_fopen(diffio->dio_orig.din_fname, "w");
if (fd == NULL) {
io_error = true;
@@ -1001,7 +1021,7 @@ static int check_external_diff(diffio_T *diffio)
io_error = true;
}
fclose(fd);
- fd = os_fopen((char *)diffio->dio_new.din_fname, "w");
+ fd = os_fopen(diffio->dio_new.din_fname, "w");
if (fd == NULL) {
io_error = true;
@@ -1012,13 +1032,13 @@ static int check_external_diff(diffio_T *diffio)
fclose(fd);
fd = NULL;
if (diff_file(diffio) == OK) {
- fd = os_fopen((char *)diffio->dio_diff.dout_fname, "r");
+ fd = os_fopen(diffio->dio_diff.dout_fname, "r");
}
if (fd == NULL) {
io_error = true;
} else {
- char_u linebuf[LBUFLEN];
+ char linebuf[LBUFLEN];
for (;;) {
// For normal diff there must be a line that contains
@@ -1027,17 +1047,17 @@ static int check_external_diff(diffio_T *diffio)
break;
}
- if (STRNCMP(linebuf, "1c1", 3) == 0
- || STRNCMP(linebuf, "@@ -1 +1 @@", 11) == 0) {
+ if (strncmp(linebuf, "1c1", 3) == 0
+ || strncmp(linebuf, "@@ -1 +1 @@", 11) == 0) {
ok = kTrue;
}
}
fclose(fd);
}
- os_remove((char *)diffio->dio_diff.dout_fname);
- os_remove((char *)diffio->dio_new.din_fname);
+ os_remove(diffio->dio_diff.dout_fname);
+ os_remove(diffio->dio_new.din_fname);
}
- os_remove((char *)diffio->dio_orig.din_fname);
+ os_remove(diffio->dio_orig.din_fname);
}
// When using 'diffexpr' break here.
@@ -1115,9 +1135,9 @@ static int diff_file_internal(diffio_T *diffio)
/// @return OK or FAIL
static int diff_file(diffio_T *dio)
{
- char *tmp_orig = (char *)dio->dio_orig.din_fname;
- char *tmp_new = (char *)dio->dio_new.din_fname;
- char *tmp_diff = (char *)dio->dio_diff.dout_fname;
+ char *tmp_orig = dio->dio_orig.din_fname;
+ char *tmp_new = dio->dio_new.din_fname;
+ char *tmp_diff = dio->dio_diff.dout_fname;
if (*p_dex != NUL) {
// Use 'diffexpr' to generate the diff file.
eval_diff(tmp_orig, tmp_new, tmp_diff);
@@ -1126,37 +1146,37 @@ static int diff_file(diffio_T *dio)
// Use xdiff for generating the diff.
if (dio->dio_internal) {
return diff_file_internal(dio);
- } else {
- const size_t len = (strlen(tmp_orig) + strlen(tmp_new) + strlen(tmp_diff)
- + STRLEN(p_srr) + 27);
- char *const cmd = xmalloc(len);
-
- // We don't want $DIFF_OPTIONS to get in the way.
- if (os_getenv("DIFF_OPTIONS")) {
- os_unsetenv("DIFF_OPTIONS");
- }
-
- // Build the diff command and execute it. Always use -a, binary
- // differences are of no use. Ignore errors, diff returns
- // non-zero when differences have been found.
- vim_snprintf(cmd, len, "diff %s%s%s%s%s%s%s%s %s",
- diff_a_works == kFalse ? "" : "-a ",
- "",
- (diff_flags & DIFF_IWHITE) ? "-b " : "",
- (diff_flags & DIFF_IWHITEALL) ? "-w " : "",
- (diff_flags & DIFF_IWHITEEOL) ? "-Z " : "",
- (diff_flags & DIFF_IBLANK) ? "-B " : "",
- (diff_flags & DIFF_ICASE) ? "-i " : "",
- tmp_orig, tmp_new);
- append_redir(cmd, len, (char *)p_srr, tmp_diff);
- block_autocmds(); // Avoid ShellCmdPost stuff
- (void)call_shell((char_u *)cmd,
- kShellOptFilter | kShellOptSilent | kShellOptDoOut,
- NULL);
- unblock_autocmds();
- xfree(cmd);
- return OK;
}
+
+ const size_t len = (strlen(tmp_orig) + strlen(tmp_new) + strlen(tmp_diff)
+ + strlen(p_srr) + 27);
+ char *const cmd = xmalloc(len);
+
+ // We don't want $DIFF_OPTIONS to get in the way.
+ if (os_getenv("DIFF_OPTIONS")) {
+ os_unsetenv("DIFF_OPTIONS");
+ }
+
+ // Build the diff command and execute it. Always use -a, binary
+ // differences are of no use. Ignore errors, diff returns
+ // non-zero when differences have been found.
+ vim_snprintf(cmd, len, "diff %s%s%s%s%s%s%s%s %s",
+ diff_a_works == kFalse ? "" : "-a ",
+ "",
+ (diff_flags & DIFF_IWHITE) ? "-b " : "",
+ (diff_flags & DIFF_IWHITEALL) ? "-w " : "",
+ (diff_flags & DIFF_IWHITEEOL) ? "-Z " : "",
+ (diff_flags & DIFF_IBLANK) ? "-B " : "",
+ (diff_flags & DIFF_ICASE) ? "-i " : "",
+ tmp_orig, tmp_new);
+ append_redir(cmd, len, p_srr, tmp_diff);
+ block_autocmds(); // Avoid ShellCmdPost stuff
+ (void)call_shell(cmd,
+ kShellOptFilter | kShellOptSilent | kShellOptDoOut,
+ NULL);
+ unblock_autocmds();
+ xfree(cmd);
+ return OK;
}
/// Create a new version of a file from the current buffer and a diff file.
@@ -1167,10 +1187,10 @@ static int diff_file(diffio_T *dio)
/// @param eap
void ex_diffpatch(exarg_T *eap)
{
- char_u *buf = NULL;
+ char *buf = NULL;
win_T *old_curwin = curwin;
char *newname = NULL; // name of patched file buffer
- char_u *esc_name = NULL;
+ char *esc_name = NULL;
#ifdef UNIX
char *fullname = NULL;
@@ -1178,16 +1198,16 @@ void ex_diffpatch(exarg_T *eap)
// We need two temp file names.
// Name of original temp file.
- char_u *tmp_orig = vim_tempname();
+ char *tmp_orig = vim_tempname();
// Name of patched temp file.
- char_u *tmp_new = vim_tempname();
+ char *tmp_new = vim_tempname();
if ((tmp_orig == NULL) || (tmp_new == NULL)) {
goto theend;
}
// Write the current buffer to "tmp_orig".
- if (buf_write(curbuf, (char *)tmp_orig, NULL,
+ if (buf_write(curbuf, tmp_orig, NULL,
(linenr_T)1, curbuf->b_ml.ml_line_count,
NULL, false, false, false, true) == FAIL) {
goto theend;
@@ -1196,23 +1216,22 @@ void ex_diffpatch(exarg_T *eap)
#ifdef UNIX
// Get the absolute path of the patchfile, changing directory below.
fullname = FullName_save(eap->arg, false);
- esc_name =
- vim_strsave_shellescape((char_u *)(fullname != NULL ? fullname : eap->arg), true, true);
+ esc_name = vim_strsave_shellescape(fullname != NULL ? fullname : eap->arg, true, true);
#else
esc_name = vim_strsave_shellescape(eap->arg, true, true);
#endif
- size_t buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16;
+ size_t buflen = strlen(tmp_orig) + strlen(esc_name) + strlen(tmp_new) + 16;
buf = xmalloc(buflen);
#ifdef UNIX
- char_u dirbuf[MAXPATHL];
+ char 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
// exit (any .rej files created). Don't change directory if we can't
// return to the current.
if ((os_dirname(dirbuf, MAXPATHL) != OK)
- || (os_chdir((char *)dirbuf) != 0)) {
+ || (os_chdir(dirbuf) != 0)) {
dirbuf[0] = NUL;
} else {
char *tempdir = vim_gettempdir();
@@ -1227,15 +1246,13 @@ void ex_diffpatch(exarg_T *eap)
if (*p_pex != NUL) {
// Use 'patchexpr' to generate the new file.
#ifdef UNIX
- eval_patch((char *)tmp_orig,
- (fullname != NULL ? fullname : eap->arg),
- (char *)tmp_new);
+ eval_patch(tmp_orig, (fullname != NULL ? fullname : eap->arg), tmp_new);
#else
- eval_patch((char *)tmp_orig, (char *)eap->arg, (char *)tmp_new);
+ eval_patch(tmp_orig, eap->arg, tmp_new);
#endif
} else {
// Build the patch command and execute it. Ignore errors.
- vim_snprintf((char *)buf, buflen, "patch -o %s %s < %s",
+ vim_snprintf(buf, buflen, "patch -o %s %s < %s",
tmp_new, tmp_orig, esc_name);
block_autocmds(); // Avoid ShellCmdPost stuff
(void)call_shell(buf, kShellOptFilter, NULL);
@@ -1244,7 +1261,7 @@ void ex_diffpatch(exarg_T *eap)
#ifdef UNIX
if (dirbuf[0] != NUL) {
- if (os_chdir((char *)dirbuf) != 0) {
+ if (os_chdir(dirbuf) != 0) {
emsg(_(e_prev_dir));
}
shorten_fnames(true);
@@ -1254,20 +1271,20 @@ void ex_diffpatch(exarg_T *eap)
// Delete any .orig or .rej file created.
STRCPY(buf, tmp_new);
STRCAT(buf, ".orig");
- os_remove((char *)buf);
+ os_remove(buf);
STRCPY(buf, tmp_new);
STRCAT(buf, ".rej");
- os_remove((char *)buf);
+ os_remove(buf);
// Only continue if the output file was created.
FileInfo file_info;
- bool info_ok = os_fileinfo((char *)tmp_new, &file_info);
+ bool info_ok = os_fileinfo(tmp_new, &file_info);
uint64_t filesize = os_fileinfo_size(&file_info);
if (!info_ok || filesize == 0) {
emsg(_("E816: Cannot read patch output"));
} else {
if (curbuf->b_fname != NULL) {
- newname = xstrnsave(curbuf->b_fname, STRLEN(curbuf->b_fname) + 4);
+ newname = xstrnsave(curbuf->b_fname, strlen(curbuf->b_fname) + 4);
STRCAT(newname, ".new");
}
@@ -1277,7 +1294,7 @@ void ex_diffpatch(exarg_T *eap)
if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL) {
// Pretend it was a ":split fname" command
eap->cmdidx = CMD_split;
- eap->arg = (char *)tmp_new;
+ eap->arg = tmp_new;
do_exedit(eap, old_curwin);
// check that split worked and editing tmp_new
@@ -1302,12 +1319,12 @@ void ex_diffpatch(exarg_T *eap)
theend:
if (tmp_orig != NULL) {
- os_remove((char *)tmp_orig);
+ os_remove(tmp_orig);
}
xfree(tmp_orig);
if (tmp_new != NULL) {
- os_remove((char *)tmp_new);
+ os_remove(tmp_new);
}
xfree(tmp_new);
xfree(newname);
@@ -1334,30 +1351,33 @@ void ex_diffsplit(exarg_T *eap)
// don't use a new tab page, each tab page has its own diffs
cmdmod.cmod_tab = 0;
- if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL) {
- // Pretend it was a ":split fname" command
- eap->cmdidx = CMD_split;
- curwin->w_p_diff = true;
- do_exedit(eap, old_curwin);
-
- // split must have worked
- if (curwin != old_curwin) {
- // Set 'diff', 'scrollbind' on and 'wrap' off.
- diff_win_options(curwin, true);
- if (win_valid(old_curwin)) {
- diff_win_options(old_curwin, true);
+ if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) == FAIL) {
+ return;
+ }
- 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);
- }
- }
- // Now that lines are folded scroll to show the cursor at the same
- // relative position.
- scroll_to_fraction(curwin, curwin->w_height);
+ // Pretend it was a ":split fname" command
+ eap->cmdidx = CMD_split;
+ curwin->w_p_diff = true;
+ do_exedit(eap, old_curwin);
+
+ if (curwin == old_curwin) { // split didn't work
+ return;
+ }
+
+ // Set 'diff', 'scrollbind' on and 'wrap' off.
+ diff_win_options(curwin, true);
+ if (win_valid(old_curwin)) {
+ diff_win_options(old_curwin, true);
+
+ 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);
}
}
+ // Now that lines are folded scroll to show the cursor at the same
+ // relative position.
+ scroll_to_fraction(curwin, curwin->w_height);
}
// Set options to show diffs for the current window.
@@ -1374,7 +1394,7 @@ static void set_diff_option(win_T *wp, int value)
curwin = wp;
curbuf = curwin->w_buffer;
curbuf->b_ro_locked++;
- set_option_value("diff", (long)value, NULL, OPT_LOCAL);
+ set_option_value_give_err("diff", (long)value, NULL, OPT_LOCAL);
curbuf->b_ro_locked--;
curwin = old_curwin;
curbuf = curwin->w_buffer;
@@ -1413,7 +1433,7 @@ void diff_win_options(win_T *wp, int addbuf)
if (wp->w_p_diff_saved) {
free_string_option(wp->w_p_fdm_save);
}
- wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm);
+ wp->w_p_fdm_save = xstrdup(wp->w_p_fdm);
}
set_string_option_direct_in_win(wp, "fdm", -1, "diff", OPT_LOCAL | OPT_FREE, 0);
@@ -1424,12 +1444,12 @@ void diff_win_options(win_T *wp, int addbuf)
if (wp->w_p_diff_saved) {
free_string_option(wp->w_p_fdc_save);
}
- wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc);
+ wp->w_p_fdc_save = xstrdup(wp->w_p_fdc);
}
free_string_option(wp->w_p_fdc);
- wp->w_p_fdc = (char_u *)xstrdup("2");
+ wp->w_p_fdc = xstrdup("2");
assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9);
- snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn);
+ snprintf(wp->w_p_fdc, strlen(wp->w_p_fdc) + 1, "%d", diff_foldcolumn);
wp->w_p_fen = true;
wp->w_p_fdl = 0;
foldUpdateAll(wp);
@@ -1448,7 +1468,7 @@ void diff_win_options(win_T *wp, int addbuf)
if (addbuf) {
diff_buf_add(wp->w_buffer);
}
- redraw_later(wp, NOT_VALID);
+ redraw_later(wp, UPD_NOT_VALID);
}
/// Set options not to show diffs. For the current window or all windows.
@@ -1480,11 +1500,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_save
- : (char_u *)"manual");
+ wp->w_p_fdm = xstrdup(*wp->w_p_fdm_save ? wp->w_p_fdm_save : "manual");
free_string_option(wp->w_p_fdc);
- wp->w_p_fdc = vim_strsave(wp->w_p_fdc_save);
+ wp->w_p_fdc = xstrdup(*wp->w_p_fdc_save ? wp->w_p_fdc_save : "0");
if (wp->w_p_fdl == 0) {
wp->w_p_fdl = wp->w_p_fdl_save;
@@ -1528,210 +1546,219 @@ void ex_diffoff(exarg_T *eap)
}
}
-/// Read the diff output and add each entry to the diff list.
-///
-/// @param idx_orig idx of original file
-/// @param idx_new idx of new file
-/// @dout diff output
-static void diff_read(int idx_orig, int idx_new, diffio_T *dio)
+static bool extract_hunk_internal(diffout_T *dout, diffhunk_T *hunk, int *line_idx)
{
- FILE *fd = NULL;
- int line_idx = 0;
- diff_T *dprev = NULL;
- diff_T *dp = curtab->tp_first_diff;
- diff_T *dn, *dpl;
- diffout_T *dout = &dio->dio_diff;
- char_u linebuf[LBUFLEN]; // only need to hold the diff line
- char_u *line;
- linenr_T off;
- int i;
- int notset = true; // block "*dp" not set yet
- diffhunk_T *hunk = NULL; // init to avoid gcc warning
- enum {
- DIFF_ED,
- DIFF_UNIFIED,
- DIFF_NONE,
- } diffstyle = DIFF_NONE;
-
- if (dout->dout_fname == NULL) {
- diffstyle = DIFF_UNIFIED;
- } else {
- fd = os_fopen((char *)dout->dout_fname, "r");
- if (fd == NULL) {
- emsg(_("E98: Cannot read diff output"));
- return;
- }
- }
-
- if (!dio->dio_internal) {
- hunk = xmalloc(sizeof(*hunk));
+ bool eof = *line_idx >= dout->dout_ga.ga_len;
+ if (!eof) {
+ *hunk = ((diffhunk_T *)dout->dout_ga.ga_data)[(*line_idx)++];
}
+ return eof;
+}
+// Extract hunk by parsing the diff output from file and calculate the diffstyle.
+static bool extract_hunk(FILE *fd, diffhunk_T *hunk, diffstyle_T *diffstyle)
+{
for (;;) {
- if (dio->dio_internal) {
- if (line_idx >= dout->dout_ga.ga_len) {
- break; // did last line
- }
- hunk = ((diffhunk_T **)dout->dout_ga.ga_data)[line_idx++];
- } else {
- if (fd == NULL) {
- if (line_idx >= dout->dout_ga.ga_len) {
- break; // did last line
- }
- line = ((char_u **)dout->dout_ga.ga_data)[line_idx++];
+ char line[LBUFLEN]; // only need to hold the diff line
+ if (vim_fgets(line, LBUFLEN, fd)) {
+ return true; // end of file
+ }
+
+ if (*diffstyle == DIFF_NONE) {
+ // Determine diff style.
+ // ed like diff looks like this:
+ // {first}[,{last}]c{first}[,{last}]
+ // {first}a{first}[,{last}]
+ // {first}[,{last}]d{first}
+ //
+ // unified diff looks like this:
+ // --- file1 2018-03-20 13:23:35.783153140 +0100
+ // +++ file2 2018-03-20 13:23:41.183156066 +0100
+ // @@ -1,3 +1,5 @@
+ if (isdigit((uint8_t)(*line))) {
+ *diffstyle = DIFF_ED;
+ } else if ((strncmp(line, "@@ ", 3) == 0)) {
+ *diffstyle = DIFF_UNIFIED;
+ } else if ((strncmp(line, "--- ", 4) == 0) // -V501
+ && (vim_fgets(line, LBUFLEN, fd) == 0) // -V501
+ && (strncmp(line, "+++ ", 4) == 0)
+ && (vim_fgets(line, LBUFLEN, fd) == 0) // -V501
+ && (strncmp(line, "@@ ", 3) == 0)) {
+ *diffstyle = DIFF_UNIFIED;
} else {
- if (vim_fgets(linebuf, LBUFLEN, fd)) {
- break; // end of file
- }
- line = linebuf;
- }
-
- if (diffstyle == DIFF_NONE) {
- // Determine diff style.
- // ed like diff looks like this:
- // {first}[,{last}]c{first}[,{last}]
- // {first}a{first}[,{last}]
- // {first}[,{last}]d{first}
- //
- // unified diff looks like this:
- // --- file1 2018-03-20 13:23:35.783153140 +0100
- // +++ file2 2018-03-20 13:23:41.183156066 +0100
- // @@ -1,3 +1,5 @@
- if (isdigit(*line)) {
- diffstyle = DIFF_ED;
- } else if ((STRNCMP(line, "@@ ", 3) == 0)) {
- diffstyle = DIFF_UNIFIED;
- } else if ((STRNCMP(line, "--- ", 4) == 0) // -V501
- && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501
- && (STRNCMP(line, "+++ ", 4) == 0)
- && (vim_fgets(linebuf, LBUFLEN, fd) == 0) // -V501
- && (STRNCMP(line, "@@ ", 3) == 0)) {
- diffstyle = DIFF_UNIFIED;
- } else {
- // Format not recognized yet, skip over this line. Cygwin diff
- // may put a warning at the start of the file.
- continue;
- }
+ // Format not recognized yet, skip over this line. Cygwin diff
+ // may put a warning at the start of the file.
+ continue;
}
+ }
- if (diffstyle == DIFF_ED) {
- if (!isdigit(*line)) {
- continue; // not the start of a diff block
- }
- if (parse_diff_ed(line, hunk) == FAIL) {
- continue;
- }
- } else {
- assert(diffstyle == DIFF_UNIFIED);
- if (STRNCMP(line, "@@ ", 3) != 0) {
- continue; // not the start of a diff block
- }
- if (parse_diff_unified(line, hunk) == FAIL) {
- continue;
- }
+ if (*diffstyle == DIFF_ED) {
+ if (!isdigit((uint8_t)(*line))) {
+ continue; // not the start of a diff block
+ }
+ if (parse_diff_ed(line, hunk) == FAIL) {
+ continue;
+ }
+ } else {
+ assert(*diffstyle == DIFF_UNIFIED);
+ if (strncmp(line, "@@ ", 3) != 0) {
+ continue; // not the start of a diff block
+ }
+ if (parse_diff_unified(line, hunk) == FAIL) {
+ continue;
}
}
- // Go over blocks before the change, for which orig and new are equal.
- // Copy blocks from orig to new.
- while (dp != NULL
- && hunk->lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) {
- if (notset) {
- diff_copy_entry(dprev, dp, idx_orig, idx_new);
- }
- dprev = dp;
- dp = dp->df_next;
- notset = true;
+ // Successfully parsed diff output, can return
+ return false;
+ }
+}
+
+static void process_hunk(diff_T **dpp, diff_T **dprevp, int idx_orig, int idx_new, diffhunk_T *hunk,
+ bool *notsetp)
+{
+ diff_T *dp = *dpp;
+ diff_T *dprev = *dprevp;
+
+ // Go over blocks before the change, for which orig and new are equal.
+ // Copy blocks from orig to new.
+ while (dp != NULL
+ && hunk->lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig]) {
+ if (*notsetp) {
+ diff_copy_entry(dprev, dp, idx_orig, idx_new);
}
+ dprev = dp;
+ dp = dp->df_next;
+ *notsetp = true;
+ }
- if ((dp != NULL)
- && (hunk->lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig])
- && (hunk->lnum_orig + hunk->count_orig >= dp->df_lnum[idx_orig])) {
- // New block overlaps with existing block(s).
- // First find last block that overlaps.
- for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next) {
- if (hunk->lnum_orig + hunk->count_orig < dpl->df_next->df_lnum[idx_orig]) {
- break;
- }
+ if ((dp != NULL)
+ && (hunk->lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig])
+ && (hunk->lnum_orig + hunk->count_orig >= dp->df_lnum[idx_orig])) {
+ // New block overlaps with existing block(s).
+ // First find last block that overlaps.
+ diff_T *dpl;
+ for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next) {
+ if (hunk->lnum_orig + hunk->count_orig < dpl->df_next->df_lnum[idx_orig]) {
+ break;
}
+ }
- // If the newly found block starts before the old one, set the
- // start back a number of lines.
- off = dp->df_lnum[idx_orig] - hunk->lnum_orig;
+ // If the newly found block starts before the old one, set the
+ // start back a number of lines.
+ linenr_T off = dp->df_lnum[idx_orig] - hunk->lnum_orig;
- if (off > 0) {
- for (i = idx_orig; i < idx_new; i++) {
- if (curtab->tp_diffbuf[i] != NULL) {
- dp->df_lnum[i] -= off;
- }
- }
- dp->df_lnum[idx_new] = hunk->lnum_new;
- dp->df_count[idx_new] = (linenr_T)hunk->count_new;
- } else if (notset) {
- // new block inside existing one, adjust new block
- dp->df_lnum[idx_new] = hunk->lnum_new + off;
- dp->df_count[idx_new] = (linenr_T)hunk->count_new - off;
- } else {
- // second overlap of new block with existing block
- dp->df_count[idx_new] += (linenr_T)hunk->count_new - (linenr_T)hunk->count_orig
- + dpl->df_lnum[idx_orig] +
- dpl->df_count[idx_orig]
- - (dp->df_lnum[idx_orig] +
- dp->df_count[idx_orig]);
- }
-
- // Adjust the size of the block to include all the