diff src/diff.c @ 672:db58b9066b21

updated for version 7.0200
author vimboss
date Fri, 17 Feb 2006 21:45:41 +0000
parents 83a006f81bac
children 9364d114ed8d
line wrap: on
line diff
--- a/src/diff.c
+++ b/src/diff.c
@@ -15,36 +15,6 @@
 
 #if defined(FEAT_DIFF) || defined(PROTO)
 
-#define DB_COUNT 4	/* up to four buffers can be diff'ed */
-
-/*
- * Each diffblock defines where a block of lines starts in each of the buffers
- * and how many lines it occupies in that buffer.  When the lines are missing
- * in the buffer the df_count[] is zero.  This is all counted in
- * buffer lines.
- * There is always at least one unchanged line in between the diffs.
- * Otherwise it would have been included in the diff above or below it.
- * df_lnum[] + df_count[] is the lnum below the change.  When in one buffer
- * lines have been inserted, in the other buffer df_lnum[] is the line below
- * the insertion and df_count[] is zero.  When appending lines at the end of
- * the buffer, df_lnum[] is one beyond the end!
- * This is using a linked list, because the number of differences is expected
- * to be reasonable small.  The list is sorted on lnum.
- */
-typedef struct diffblock diff_T;
-struct diffblock
-{
-    diff_T	*df_next;
-    linenr_T	df_lnum[DB_COUNT];	/* line number in buffer */
-    linenr_T	df_count[DB_COUNT];	/* nr of inserted/changed lines */
-};
-
-static diff_T	*first_diff = NULL;
-
-static buf_T	*(diffbuf[DB_COUNT]);
-
-static int	diff_invalid = TRUE;	/* list of diffs is outdated */
-
 static int	diff_busy = FALSE;	/* ex_diffgetput() is busy */
 
 /* flags obtained from the 'diffopt' option */
@@ -64,8 +34,10 @@ static int diff_bin_works = MAYBE; /* TR
 #endif
 
 static int diff_buf_idx __ARGS((buf_T *buf));
-static void diff_check_unchanged __ARGS((diff_T *dp));
-static int diff_check_sanity __ARGS((diff_T *dp));
+static int diff_buf_idx_tp __ARGS((buf_T *buf, tabpage_T *tp));
+static void diff_mark_adjust_tp __ARGS((tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount, long amount_after));
+static void diff_check_unchanged __ARGS((tabpage_T *tp, diff_T *dp));
+static int diff_check_sanity __ARGS((tabpage_T *tp, diff_T *dp));
 static void diff_redraw __ARGS((int dofold));
 static int diff_write __ARGS((buf_T *buf, char_u *fname));
 static void diff_file __ARGS((char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff));
@@ -76,42 +48,30 @@ static void diff_fold_update __ARGS((dif
 #endif
 static void diff_read __ARGS((int idx_orig, int idx_new, char_u *fname));
 static void diff_copy_entry __ARGS((diff_T *dprev, diff_T *dp, int idx_orig, int idx_new));
-static diff_T *diff_alloc_new __ARGS((diff_T *dprev, diff_T *dp));
+static diff_T *diff_alloc_new __ARGS((tabpage_T *tp, diff_T *dprev, diff_T *dp));
 
 #ifndef USE_CR
 # define tag_fgets vim_fgets
 #endif
 
 /*
- * Call this when a new buffer is being edited in the current window.  curbuf
- * must already have been set.
- * Marks the current buffer as being part of the diff and requireing updating.
- * This must be done before any autocmd, because a command the uses info
- * about the screen contents.
- */
-    void
-diff_new_buffer()
-{
-    if (curwin->w_p_diff)
-	diff_buf_add(curbuf);
-}
-
-/*
  * Called when deleting or unloading a buffer: No longer make a diff with it.
- * Also called when 'diff' is reset in the last window showing a diff for a
- * buffer.
  */
     void
 diff_buf_delete(buf)
     buf_T	*buf;
 {
     int		i;
+    tabpage_T	*tp;
 
-    i = diff_buf_idx(buf);
-    if (i != DB_COUNT)
+    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
     {
-	diffbuf[i] = NULL;
-	diff_invalid = TRUE;
+	i = diff_buf_idx_tp(buf, tp);
+	if (i != DB_COUNT)
+	{
+	    tp->tp_diffbuf[i] = NULL;
+	    tp->tp_diff_invalid = TRUE;
+	}
     }
 }
 
@@ -124,6 +84,7 @@ diff_buf_adjust(win)
     win_T	*win;
 {
     win_T	*wp;
+    int		i;
 
     if (!win->w_p_diff)
     {
@@ -133,7 +94,14 @@ diff_buf_adjust(win)
 	    if (wp->w_buffer == win->w_buffer && wp->w_p_diff)
 		break;
 	if (wp == NULL)
-	    diff_buf_delete(win->w_buffer);
+	{
+	    i = diff_buf_idx(win->w_buffer);
+	    if (i != DB_COUNT)
+	    {
+		curtab->tp_diffbuf[i] = NULL;
+		curtab->tp_diff_invalid = TRUE;
+	    }
+	}
     }
     else
 	diff_buf_add(win->w_buffer);
@@ -141,6 +109,11 @@ diff_buf_adjust(win)
 
 /*
  * Add a buffer to make diffs for.
+ * Call this when a new buffer is being edited in the current window where
+ * 'diff' is set.
+ * Marks the current buffer as being part of the diff and requireing updating.
+ * This must be done before any autocmd, because a command may use info
+ * about the screen contents.
  */
     void
 diff_buf_add(buf)
@@ -152,10 +125,10 @@ diff_buf_add(buf)
 	return;		/* It's already there. */
 
     for (i = 0; i < DB_COUNT; ++i)
-	if (diffbuf[i] == NULL)
+	if (curtab->tp_diffbuf[i] == NULL)
 	{
-	    diffbuf[i] = buf;
-	    diff_invalid = TRUE;
+	    curtab->tp_diffbuf[i] = buf;
+	    curtab->tp_diff_invalid = TRUE;
 	    return;
 	}
 
@@ -163,7 +136,7 @@ diff_buf_add(buf)
 }
 
 /*
- * Find buffer "buf" in the list of diff buffers.
+ * Find buffer "buf" in the list of diff buffers for the current tab page.
  * Return its index or DB_COUNT if not found.
  */
     static int
@@ -173,30 +146,53 @@ diff_buf_idx(buf)
     int		idx;
 
     for (idx = 0; idx < DB_COUNT; ++idx)
-	if (diffbuf[idx] == buf)
+	if (curtab->tp_diffbuf[idx] == buf)
+	    break;
+    return idx;
+}
+
+/*
+ * Find buffer "buf" in the list of diff buffers for tab page "tp".
+ * Return its index or DB_COUNT if not found.
+ */
+    static int
+diff_buf_idx_tp(buf, tp)
+    buf_T	*buf;
+    tabpage_T	*tp;
+{
+    int		idx;
+
+    for (idx = 0; idx < DB_COUNT; ++idx)
+	if (tp->tp_diffbuf[idx] == buf)
 	    break;
     return idx;
 }
 
 /*
- * Mark the diff info as invalid, it will be updated when info is requested.
+ * Mark the diff info involving buffer "buf" as invalid, it will be updated
+ * when info is requested.
  */
     void
-diff_invalidate()
+diff_invalidate(buf)
+    buf_T	*buf;
 {
-    if (curwin->w_p_diff)
+    tabpage_T	*tp;
+    int		i;
+
+    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
     {
-	diff_invalid = TRUE;
-	diff_redraw(TRUE);
+	i = diff_buf_idx_tp(buf, tp);
+	if (i != DB_COUNT)
+	{
+	    tp->tp_diff_invalid = TRUE;
+	    if (tp == curtab)
+		diff_redraw(TRUE);
+	}
     }
 }
 
 /*
- * Called by mark_adjust(): update line numbers.
- * This attempts to update the changes as much as possible:
- * When inserting/deleting lines outside of existing change blocks, create a
- * new change block and update the line numbers in following blocks.
- * When inserting/deleting lines in existing change blocks, update them.
+ * Called by mark_adjust(): update line numbers in "curbuf".
  */
     void
 diff_mark_adjust(line1, line2, amount, amount_after)
@@ -205,10 +201,37 @@ diff_mark_adjust(line1, line2, amount, a
     long	amount;
     long	amount_after;
 {
+    int		idx;
+    tabpage_T	*tp;
+
+    /* Handle all tab pages that use the current buffer in a diff. */
+    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+    {
+	idx = diff_buf_idx_tp(curbuf, tp);
+	if (idx != DB_COUNT)
+	    diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after);
+    }
+}
+
+/*
+ * Update line numbers in tab page "tp" for "curbuf" with index "idx".
+ * This attempts to update the changes as much as possible:
+ * When inserting/deleting lines outside of existing change blocks, create a
+ * new change block and update the line numbers in following blocks.
+ * When inserting/deleting lines in existing change blocks, update them.
+ */
+    static void
+diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after)
+    tabpage_T	*tp;
+    int		idx;
+    linenr_T	line1;
+    linenr_T	line2;
+    long	amount;
+    long	amount_after;
+{
     diff_T	*dp;
     diff_T	*dprev;
     diff_T	*dnext;
-    int		idx;
     int		i;
     int		inserted, deleted;
     int		n, off;
@@ -216,11 +239,6 @@ diff_mark_adjust(line1, line2, amount, a
     linenr_T	lnum_deleted = line1;	/* lnum of remaining deletion */
     int		check_unchanged;
 
-    /* Find the index for the current buffer. */
-    idx = diff_buf_idx(curbuf);
-    if (idx == DB_COUNT)
-	return;		/* This buffer doesn't have diffs. */
-
     if (line2 == MAXLNUM)
     {
 	/* mark_adjust(99, MAXLNUM, 9, 0): insert lines */
@@ -241,7 +259,7 @@ diff_mark_adjust(line1, line2, amount, a
     }
 
     dprev = NULL;
-    dp = first_diff;
+    dp = tp->tp_first_diff;
     for (;;)
     {
 	/* If the change is after the previous diff block and before the next
@@ -253,14 +271,14 @@ diff_mark_adjust(line1, line2, amount, a
 		    || dprev->df_lnum[idx] + dprev->df_count[idx] < line1)
 		&& !diff_busy)
 	{
-	    dnext = diff_alloc_new(dprev, dp);
+	    dnext = diff_alloc_new(tp, dprev, dp);
 	    if (dnext == NULL)
 		return;
 
 	    dnext->df_lnum[idx] = line1;
 	    dnext->df_count[idx] = inserted;
 	    for (i = 0; i < DB_COUNT; ++i)
-		if (diffbuf[i] != NULL && i != idx)
+		if (tp->tp_diffbuf[i] != NULL && i != idx)
 		{
 		    if (dprev == NULL)
 			dnext->df_lnum[i] = line1;
@@ -367,7 +385,7 @@ diff_mark_adjust(line1, line2, amount, a
 		    }
 
 		    for (i = 0; i < DB_COUNT; ++i)
-			if (diffbuf[i] != NULL && i != idx)
+			if (tp->tp_diffbuf[i] != NULL && i != idx)
 			{
 			    dp->df_lnum[i] -= off;
 			    dp->df_count[i] += n;
@@ -390,7 +408,7 @@ diff_mark_adjust(line1, line2, amount, a
 		    /* Check if inserted lines are equal, may reduce the
 		     * size of the diff.  TODO: also check for equal lines
 		     * in the middle and perhaps split the block. */
-		    diff_check_unchanged(dp);
+		    diff_check_unchanged(tp, dp);
 	    }
 	}
 
@@ -399,7 +417,7 @@ diff_mark_adjust(line1, line2, amount, a
 							  == dp->df_lnum[idx])
 	{
 	    for (i = 0; i < DB_COUNT; ++i)
-		if (diffbuf[i] != NULL)
+		if (tp->tp_diffbuf[i] != NULL)
 		    dprev->df_count[i] += dp->df_count[i];
 	    dprev->df_next = dp->df_next;
 	    vim_free(dp);
@@ -414,12 +432,12 @@ diff_mark_adjust(line1, line2, amount, a
     }
 
     dprev = NULL;
-    dp = first_diff;
+    dp = tp->tp_first_diff;
     while (dp != NULL)
     {
 	/* All counts are zero, remove this entry. */
 	for (i = 0; i < DB_COUNT; ++i)
-	    if (diffbuf[i] != NULL && dp->df_count[i] != 0)
+	    if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0)
 		break;
 	if (i == DB_COUNT)
 	{
@@ -427,7 +445,7 @@ diff_mark_adjust(line1, line2, amount, a
 	    vim_free(dp);
 	    dp = dnext;
 	    if (dprev == NULL)
-		first_diff = dnext;
+		tp->tp_first_diff = dnext;
 	    else
 		dprev->df_next = dnext;
 	}
@@ -439,19 +457,24 @@ diff_mark_adjust(line1, line2, amount, a
 	}
 
     }
-    diff_redraw(TRUE);
+
+    if (tp == curtab)
+    {
+	diff_redraw(TRUE);
 
-    /* Need to recompute the scroll binding, may remove or add filler lines
-     * (e.g., when adding lines above w_topline). But it's slow when making
-     * many changes, postpone until redrawing. */
-    diff_need_scrollbind = TRUE;
+	/* Need to recompute the scroll binding, may remove or add filler
+	 * lines (e.g., when adding lines above w_topline). But it's slow when
+	 * making many changes, postpone until redrawing. */
+	diff_need_scrollbind = TRUE;
+    }
 }
 
 /*
  * Allocate a new diff block and link it between "dprev" and "dp".
  */
     static diff_T *
-diff_alloc_new(dprev, dp)
+diff_alloc_new(tp, dprev, dp)
+    tabpage_T	*tp;
     diff_T	*dprev;
     diff_T	*dp;
 {
@@ -462,7 +485,7 @@ diff_alloc_new(dprev, dp)
     {
 	dnew->df_next = dp;
 	if (dprev == NULL)
-	    first_diff = dnew;
+	    tp->tp_first_diff = dnew;
 	else
 	    dprev->df_next = dnew;
     }
@@ -476,7 +499,8 @@ diff_alloc_new(dprev, dp)
  * must take care of removing it.
  */
     static void
-diff_check_unchanged(dp)
+diff_check_unchanged(tp, dp)
+    tabpage_T	*tp;
     diff_T	*dp;
 {
     int		i_org;
@@ -488,12 +512,12 @@ diff_check_unchanged(dp)
     /* Find the first buffers, use it as the original, compare the other
      * buffer lines against this one. */
     for (i_org = 0; i_org < DB_COUNT; ++i_org)
-	if (diffbuf[i_org] != NULL)
+	if (tp->tp_diffbuf[i_org] != NULL)
 	    break;
     if (i_org == DB_COUNT)	/* safety check */
 	return;
 
-    if (diff_check_sanity(dp) == FAIL)
+    if (diff_check_sanity(tp, dp) == FAIL)
 	return;
 
     /* First check lines at the top, then at the bottom. */
@@ -508,20 +532,20 @@ diff_check_unchanged(dp)
 	    /* Copy the line, the next ml_get() will invalidate it.  */
 	    if (dir == BACKWARD)
 		off_org = dp->df_count[i_org] - 1;
-	    line_org = vim_strsave(ml_get_buf(diffbuf[i_org],
+	    line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org],
 					dp->df_lnum[i_org] + off_org, FALSE));
 	    if (line_org == NULL)
 		return;
 	    for (i_new = i_org + 1; i_new < DB_COUNT; ++i_new)
 	    {
-		if (diffbuf[i_new] == NULL)
+		if (tp->tp_diffbuf[i_new] == NULL)
 		    continue;
 		if (dir == BACKWARD)
 		    off_new = dp->df_count[i_new] - 1;
 		/* if other buffer doesn't have this line, it was inserted */
 		if (off_new < 0 || off_new >= dp->df_count[i_new])
 		    break;
-		if (diff_cmp(line_org, ml_get_buf(diffbuf[i_new],
+		if (diff_cmp(line_org, ml_get_buf(tp->tp_diffbuf[i_new],
 				   dp->df_lnum[i_new] + off_new, FALSE)) != 0)
 		    break;
 	    }
@@ -533,7 +557,7 @@ diff_check_unchanged(dp)
 
 	    /* Line matched in all buffers, remove it from the diff. */
 	    for (i_new = i_org; i_new < DB_COUNT; ++i_new)
-		if (diffbuf[i_new] != NULL)
+		if (tp->tp_diffbuf[i_new] != NULL)
 		{
 		    if (dir == FORWARD)
 			++dp->df_lnum[i_new];
@@ -551,21 +575,22 @@ diff_check_unchanged(dp)
  * This can happen when the diff program returns invalid results.
  */
     static int
-diff_check_sanity(dp)
+diff_check_sanity(tp, dp)
+    tabpage_T	*tp;
     diff_T	*dp;
 {
     int		i;
 
     for (i = 0; i < DB_COUNT; ++i)
-	if (diffbuf[i] != NULL)
+	if (tp->tp_diffbuf[i] != NULL)
 	    if (dp->df_lnum[i] + dp->df_count[i] - 1
-					     > diffbuf[i]->b_ml.ml_line_count)
+				      > tp->tp_diffbuf[i]->b_ml.ml_line_count)
 		return FAIL;
     return OK;
 }
 
 /*
- * Mark all diff buffers for redraw.
+ * Mark all diff buffers in the current tab page for redraw.
  */
     static void
 diff_redraw(dofold)
@@ -624,7 +649,7 @@ diff_write(buf, fname)
 /*ARGSUSED*/
     void
 ex_diffupdate(eap)
-    exarg_T	*eap;
+    exarg_T	*eap;	    /* can be NULL, it's not used */
 {
     buf_T	*buf;
     int		idx_orig;
@@ -636,19 +661,19 @@ ex_diffupdate(eap)
     int		ok;
 
     /* Delete all diffblocks. */
-    diff_clear();
-    diff_invalid = FALSE;
+    diff_clear(curtab);
+    curtab->tp_diff_invalid = FALSE;
 
     /* Use the first buffer as the original text. */
     for (idx_orig = 0; idx_orig < DB_COUNT; ++idx_orig)
-	if (diffbuf[idx_orig] != NULL)
+	if (curtab->tp_diffbuf[idx_orig] != NULL)
 	    break;
     if (idx_orig == DB_COUNT)
 	return;
 
     /* Only need to do something when there is another buffer. */
     for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
-	if (diffbuf[idx_new] != NULL)
+	if (curtab->tp_diffbuf[idx_new] != NULL)
 	    break;
     if (idx_new == DB_COUNT)
 	return;
@@ -743,14 +768,14 @@ ex_diffupdate(eap)
     }
 
     /* Write the first buffer to a tempfile. */
-    buf = diffbuf[idx_orig];
+    buf = curtab->tp_diffbuf[idx_orig];
     if (diff_write(buf, tmp_orig) == FAIL)
 	goto theend;
 
     /* Make a difference between the first buffer and every other. */
     for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
     {
-	buf = diffbuf[idx_new];
+	buf = curtab->tp_diffbuf[idx_new];
 	if (buf == NULL)
 	    continue;
 	if (diff_write(buf, tmp_new) == FAIL)
@@ -1134,7 +1159,7 @@ diff_read(idx_orig, idx_new, fname)
 {
     FILE	*fd;
     diff_T	*dprev = NULL;
-    diff_T	*dp = first_diff;
+    diff_T	*dp = curtab->tp_first_diff;
     diff_T	*dn, *dpl;
     long	f1, l1, f2, l2;
     char_u	linebuf[LBUFLEN];   /* only need to hold the diff line */
@@ -1237,7 +1262,7 @@ diff_read(idx_orig, idx_new, fname)
 	    if (off > 0)
 	    {
 		for (i = idx_orig; i < idx_new; ++i)
-		    if (diffbuf[i] != NULL)
+		    if (curtab->tp_diffbuf[i] != NULL)
 			dp->df_lnum[i] -= off;
 		dp->df_lnum[idx_new] = lnum_new;
 		dp->df_count[idx_new] = count_new;
@@ -1265,7 +1290,7 @@ diff_read(idx_orig, idx_new, fname)
 		off = 0;
 	    }
 	    for (i = idx_orig; i < idx_new + !notset; ++i)
-		if (diffbuf[i] != NULL)
+		if (curtab->tp_diffbuf[i] != NULL)
 		    dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i]
 						       - dp->df_lnum[i] + off;
 
@@ -1282,7 +1307,7 @@ diff_read(idx_orig, idx_new, fname)
 	else
 	{
 	    /* Allocate a new diffblock. */
-	    dp = diff_alloc_new(dprev, dp);
+	    dp = diff_alloc_new(curtab, dprev, dp);
 	    if (dp == NULL)
 		return;
 
@@ -1295,7 +1320,7 @@ diff_read(idx_orig, idx_new, fname)
 	     * original buffer, otherwise there would have been a change
 	     * already. */
 	    for (i = idx_orig + 1; i < idx_new; ++i)
-		if (diffbuf[i] != NULL)
+		if (curtab->tp_diffbuf[i] != NULL)
 		    diff_copy_entry(dprev, dp, idx_orig, i);
 	}
 	notset = FALSE;		/* "*dp" has been set */
@@ -1336,19 +1361,20 @@ diff_copy_entry(dprev, dp, idx_orig, idx
 }
 
 /*
- * Clear the list of diffblocks.
+ * Clear the list of diffblocks for tab page "tp".
  */
     void
-diff_clear()
+diff_clear(tp)
+    tabpage_T	*tp;
 {
     diff_T	*p, *next_p;
 
-    for (p = first_diff; p != NULL; p = next_p)
+    for (p = tp->tp_first_diff; p != NULL; p = next_p)
     {
 	next_p = p->df_next;
 	vim_free(p);
     }
-    first_diff = NULL;
+    tp->tp_first_diff = NULL;
 }
 
 /*
@@ -1365,17 +1391,17 @@ diff_check(wp, lnum)
     win_T	*wp;
     linenr_T	lnum;
 {
-    int		idx;		/* index in diffbuf[] for this buffer */
+    int		idx;		/* index in tp_diffbuf[] for this buffer */
     diff_T	*dp;
     int		maxcount;
     int		i;
     buf_T	*buf = wp->w_buffer;
     int		cmp;
 
-    if (diff_invalid)
+    if (curtab->tp_diff_invalid)
 	ex_diffupdate(NULL);		/* update after a big change */
 
-    if (first_diff == NULL || !wp->w_p_diff)	/* no diffs at all */
+    if (curtab->tp_first_diff == NULL || !wp->w_p_diff)	/* no diffs at all */
 	return 0;
 
     /* safety check: "lnum" must be a buffer line */
@@ -1393,7 +1419,7 @@ diff_check(wp, lnum)
 #endif
 
     /* search for a change that includes "lnum" in the list of diffblocks. */
-    for (dp = first_diff; dp != NULL; dp = dp->df_next)
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
 	    break;
     if (dp == NULL || lnum < dp->df_lnum[idx])
@@ -1408,7 +1434,7 @@ diff_check(wp, lnum)
 	 * count, check if the lines are identical. */
 	cmp = FALSE;
 	for (i = 0; i < DB_COUNT; ++i)
-	    if (i != idx && diffbuf[i] != NULL)
+	    if (i != idx && curtab->tp_diffbuf[i] != NULL)
 	    {
 		if (dp->df_count[i] == 0)
 		    zero = TRUE;
@@ -1424,7 +1450,7 @@ diff_check(wp, lnum)
 	    /* Compare all lines.  If they are equal the lines were inserted
 	     * in some buffers, deleted in others, but not changed. */
 	    for (i = 0; i < DB_COUNT; ++i)
-		if (i != idx && diffbuf[i] != NULL && dp->df_count[i] != 0)
+		if (i != idx && curtab->tp_diffbuf[i] != NULL && dp->df_count[i] != 0)
 		    if (!diff_equal_entry(dp, idx, i))
 			return -1;
 	}
@@ -1446,7 +1472,7 @@ diff_check(wp, lnum)
      * 0 when this buf had the max count. */
     maxcount = 0;
     for (i = 0; i < DB_COUNT; ++i)
-	if (diffbuf[i] != NULL && dp->df_count[i] > maxcount)
+	if (curtab->tp_diffbuf[i] != NULL && dp->df_count[i] > maxcount)
 	    maxcount = dp->df_count[i];
     return maxcount - dp->df_count[idx];
 }
@@ -1466,15 +1492,15 @@ diff_equal_entry(dp, idx1, idx2)
 
     if (dp->df_count[idx1] != dp->df_count[idx2])
 	return FALSE;
-    if (diff_check_sanity(dp) == FAIL)
+    if (diff_check_sanity(curtab, dp) == FAIL)
 	return FALSE;
     for (i = 0; i < dp->df_count[idx1]; ++i)
     {
-	line = vim_strsave(ml_get_buf(diffbuf[idx1],
+	line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1],
 					       dp->df_lnum[idx1] + i, FALSE));
 	if (line == NULL)
 	    return FALSE;
-	cmp = diff_cmp(line, ml_get_buf(diffbuf[idx2],
+	cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2],
 					       dp->df_lnum[idx2] + i, FALSE));
 	vim_free(line);
 	if (cmp != 0)
@@ -1587,13 +1613,13 @@ diff_set_topline(fromwin, towin)
     if (idx == DB_COUNT)
 	return;		/* safety check */
 
-    if (diff_invalid)
+    if (curtab->tp_diff_invalid)
 	ex_diffupdate(NULL);		/* update after a big change */
 
     towin->w_topfill = 0;
 
     /* search for a change that includes "lnum" in the list of diffblocks. */
-    for (dp = first_diff; dp != NULL; dp = dp->df_next)
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
 	    break;
     if (dp == NULL)
@@ -1668,6 +1694,7 @@ diffopt_changed()
     char_u	*p;
     int		diff_context_new = 6;
     int		diff_flags_new = 0;
+    tabpage_T	*tp;
 
     p = p_dip;
     while (*p != NUL)
@@ -1700,7 +1727,8 @@ diffopt_changed()
 
     /* If "icase" or "iwhite" was added or removed, need to update the diff. */
     if (diff_flags != diff_flags_new)
-	diff_invalid = TRUE;
+	for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+	    tp->tp_diff_invalid = TRUE;
 
     diff_flags = diff_flags_new;
     diff_context = diff_context_new;
@@ -1744,22 +1772,22 @@ diff_find_change(wp, lnum, startp, endp)
 	return FALSE;
 
     /* search for a change that includes "lnum" in the list of diffblocks. */
-    for (dp = first_diff; dp != NULL; dp = dp->df_next)
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
 	    break;
-    if (dp == NULL || diff_check_sanity(dp) == FAIL)
+    if (dp == NULL || diff_check_sanity(curtab, dp) == FAIL)
 	return FALSE;
 
     off = lnum - dp->df_lnum[idx];
 
     for (i = 0; i < DB_COUNT; ++i)
-	if (diffbuf[i] != NULL && i != idx)
+	if (curtab->tp_diffbuf[i] != NULL && i != idx)
 	{
 	    /* Skip lines that are not in the other change (filler lines). */
 	    if (off >= dp->df_count[i])
 		continue;
 	    added = FALSE;
-	    line_new = ml_get_buf(diffbuf[i], dp->df_lnum[i] + off, FALSE);
+	    line_new = ml_get_buf(curtab->tp_diffbuf[i], dp->df_lnum[i] + off, FALSE);
 
 	    /* Search for start of difference */
 	    for (si = 0; line_org[si] != NUL && line_org[si] == line_new[si]; )
@@ -1819,9 +1847,9 @@ diff_infold(wp, lnum)
 
     for (i = 0; i < DB_COUNT; ++i)
     {
-	if (diffbuf[i] == wp->w_buffer)
+	if (curtab->tp_diffbuf[i] == wp->w_buffer)
 	    idx = i;
-	else if (diffbuf[i] != NULL)
+	else if (curtab->tp_diffbuf[i] != NULL)
 	    other = TRUE;
     }
 
@@ -1829,14 +1857,14 @@ diff_infold(wp, lnum)
     if (idx == -1 || !other)
 	return FALSE;
 
-    if (diff_invalid)
+    if (curtab->tp_diff_invalid)
 	ex_diffupdate(NULL);		/* update after a big change */
 
     /* Return if there are no diff blocks.  All lines will be folded. */
-    if (first_diff == NULL)
+    if (curtab->tp_first_diff == NULL)
 	return TRUE;
 
-    for (dp = first_diff; dp != NULL; dp = dp->df_next)
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
     {
 	/* If this change is below the line there can't be any further match. */
 	if (dp->df_lnum[idx] - diff_context > lnum)
@@ -1908,10 +1936,10 @@ ex_diffgetput(eap)
     {
 	/* No argument: Find the other buffer in the list of diff buffers. */
 	for (idx_other = 0; idx_other < DB_COUNT; ++idx_other)
-	    if (diffbuf[idx_other] != curbuf
-		    && diffbuf[idx_other] != NULL
+	    if (curtab->tp_diffbuf[idx_other] != curbuf
+		    && curtab->tp_diffbuf[idx_other] != NULL
 		    && (eap->cmdidx != CMD_diffput
-					       || diffbuf[idx_other]->b_p_ma))
+					       || curtab->tp_diffbuf[idx_other]->b_p_ma))
 		break;
 	if (idx_other == DB_COUNT)
 	{
@@ -1921,9 +1949,9 @@ ex_diffgetput(eap)
 
 	/* Check that there isn't a third buffer in the list */
 	for (i = idx_other + 1; i < DB_COUNT; ++i)
-	    if (diffbuf[i] != curbuf
-		    && diffbuf[i] != NULL
-		    && (eap->cmdidx != CMD_diffput || diffbuf[i]->b_p_ma))
+	    if (curtab->tp_diffbuf[i] != curbuf
+		    && curtab->tp_diffbuf[i] != NULL
+		    && (eap->cmdidx != CMD_diffput || curtab->tp_diffbuf[i]->b_p_ma))
 	    {
 		EMSG(_("E101: More than two buffers in diff mode, don't know which one to use"));
 		return;
@@ -1987,11 +2015,11 @@ ex_diffgetput(eap)
 	/* Need to make the other buffer the current buffer to be able to make
 	 * changes in it. */
 	/* set curwin/curbuf to buf and save a few things */
-	aucmd_prepbuf(&aco, diffbuf[idx_other]);
+	aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]);
     }
 
     dprev = NULL;
-    for (dp = first_diff; dp != NULL; )
+    for (dp = curtab->tp_first_diff; dp != NULL; )
     {
 	if (dp->df_lnum[idx_cur] > eap->line2 + off)
 	    break;	/* past the range that was specified */
@@ -2063,9 +2091,9 @@ ex_diffgetput(eap)
 		linenr_T nr;
 
 		nr = dp->df_lnum[idx_from] + start_skip + i;
-		if (nr > diffbuf[idx_from]->b_ml.ml_line_count)
+		if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count)
 		    break;
-		p = vim_strsave(ml_get_buf(diffbuf[idx_from], nr, FALSE));
+		p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from], nr, FALSE));
 		if (p != NULL)
 		{
 		    ml_append(lnum + i - 1, p, 0, FALSE);
@@ -2088,7 +2116,7 @@ ex_diffgetput(eap)
 		/* Check if there are any other buffers and if the diff is
 		 * equal in them. */
 		for (i = 0; i < DB_COUNT; ++i)
-		    if (diffbuf[i] != NULL && i != idx_from && i != idx_to
+		    if (curtab->tp_diffbuf[i] != NULL && i != idx_from && i != idx_to
 			    && !diff_equal_entry(dp, idx_from, i))
 			break;
 		if (i == DB_COUNT)
@@ -2097,7 +2125,7 @@ ex_diffgetput(eap)
 		    dfree = dp;
 		    dp = dp->df_next;
 		    if (dprev == NULL)
-			first_diff = dp;
+			curtab->tp_first_diff = dp;
 		    else
 			dprev->df_next = dp;
 		}
@@ -2182,7 +2210,7 @@ diff_fold_update(dp, skip_idx)
 
     for (wp = firstwin; wp != NULL; wp = wp->w_next)
 	for (i = 0; i < DB_COUNT; ++i)
-	    if (diffbuf[i] == wp->w_buffer && i != skip_idx)
+	    if (curtab->tp_diffbuf[i] == wp->w_buffer && i != skip_idx)
 		foldUpdate(wp, dp->df_lnum[i],
 					    dp->df_lnum[i] + dp->df_count[i]);
 }
@@ -2195,7 +2223,12 @@ diff_fold_update(dp, skip_idx)
 diff_mode_buf(buf)
     buf_T	*buf;
 {
-    return diff_buf_idx(buf) != DB_COUNT;
+    tabpage_T	*tp;
+
+    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+	if (diff_buf_idx_tp(buf, tp) != DB_COUNT)
+	    return TRUE;
+    return FALSE;
 }
 
 /*
@@ -2212,22 +2245,22 @@ diff_move_to(dir, count)
     diff_T	*dp;
 
     idx = diff_buf_idx(curbuf);
-    if (idx == DB_COUNT || first_diff == NULL)
+    if (idx == DB_COUNT || curtab->tp_first_diff == NULL)
 	return FAIL;
 
-    if (diff_invalid)
+    if (curtab->tp_diff_invalid)
 	ex_diffupdate(NULL);		/* update after a big change */
 
-    if (first_diff == NULL)		/* no diffs today */
+    if (curtab->tp_first_diff == NULL)		/* no diffs today */
 	return FAIL;
 
     while (--count >= 0)
     {
 	/* Check if already before first diff. */
-	if (dir == BACKWARD && lnum <= first_diff->df_lnum[idx])
+	if (dir == BACKWARD && lnum <= curtab->tp_first_diff->df_lnum[idx])
 	    break;
 
-	for (dp = first_diff; ; dp = dp->df_next)
+	for (dp = curtab->tp_first_diff; ; dp = dp->df_next)
 	{
 	    if (dp == NULL)
 		break;
@@ -2276,11 +2309,11 @@ diff_lnum_win(lnum, wp)
     if (idx == DB_COUNT)		/* safety check */
 	return (linenr_T)0;
 
-    if (diff_invalid)
+    if (curtab->tp_diff_invalid)
 	ex_diffupdate(NULL);		/* update after a big change */
 
     /* search for a change that includes "lnum" in the list of diffblocks. */
-    for (dp = first_diff; dp != NULL; dp = dp->df_next)
+    for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
 	    break;