]> granicus.if.org Git - vim/commitdiff
updated for version 7.0200
authorBram Moolenaar <Bram@vim.org>
Fri, 17 Feb 2006 21:45:41 +0000 (21:45 +0000)
committerBram Moolenaar <Bram@vim.org>
Fri, 17 Feb 2006 21:45:41 +0000 (21:45 +0000)
src/buffer.c
src/diff.c
src/ex_docmd.c
src/fileio.c
src/proto/diff.pro
src/window.c

index 28ed6b985002d6fe186b1f56f0c991f2beee7604..2b6fe28105fc56f4331e821c57cb89977007c792 100644 (file)
@@ -1353,7 +1353,8 @@ enter_buffer(buf)
     ++curbuf->b_nwindows;
 
 #ifdef FEAT_DIFF
-    diff_new_buffer();
+    if (curwin->w_p_diff)
+       diff_buf_add(curbuf);
 #endif
 
     /* Cursor on first line by default. */
@@ -4175,7 +4176,7 @@ do_arg_all(count, forceit)
 #endif
                }
 #ifdef FEAT_WINDOWS
-               if (firstwin == lastwin)        /* can't close last window */
+               if (firstwin == lastwin)        /* don't close last window */
 #endif
                    use_firstwin = TRUE;
 #ifdef FEAT_WINDOWS
index 7c5bbd34354904c0278edd53d39377f58338d64e..7170835d4b7d767807685e651ae5057635d33481 100644 (file)
 
 #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; /* TRUE when "diff --binary" works, FALSE
 #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((diff_T *dp, int skip_idx));
 #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,33 +146,84 @@ 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.
+ * Called by mark_adjust(): update line numbers in "curbuf".
+ */
+    void
+diff_mark_adjust(line1, line2, amount, amount_after)
+    linenr_T   line1;
+    linenr_T   line2;
+    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.
  */
-    void
-diff_mark_adjust(line1, line2, amount, amount_after)
+    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;
@@ -208,7 +232,6 @@ diff_mark_adjust(line1, line2, amount, 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, amount_after)
     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, amount_after)
     }
 
     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, amount_after)
                    || 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, amount_after)
                    }
 
                    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, amount_after)
                    /* 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, amount_after)
                                                          == 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, amount_after)
     }
 
     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, amount_after)
            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, amount_after)
        }
 
     }
-    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;
+    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;
+    }
 }
 
 /*
  * 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_new)
 }
 
 /*
- * 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;
 
index 195f19d7cf1ecb59aebee6a6b64cbc197eb8a630..495d7397b3b72554236a7145a1654f85825c7c01 100644 (file)
@@ -154,6 +154,7 @@ static void ex_all __ARGS((exarg_T *eap));
 static void    ex_resize __ARGS((exarg_T *eap));
 static void    ex_stag __ARGS((exarg_T *eap));
 static void    ex_tabclose __ARGS((exarg_T *eap));
+static void    ex_tabonly __ARGS((exarg_T *eap));
 static void    ex_tabs __ARGS((exarg_T *eap));
 #else
 # define ex_close              ex_ni
@@ -166,6 +167,7 @@ static void ex_tabs __ARGS((exarg_T *eap));
 # define ex_tab                        ex_ni
 # define ex_tabs               ex_ni
 # define ex_tabclose           ex_ni
+# define ex_tabonly            ex_ni
 #endif
 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
 static void    ex_pclose __ARGS((exarg_T *eap));
@@ -4872,8 +4874,8 @@ check_more(message, forceit)
 {
     int            n = ARGCOUNT - curwin->w_arg_idx - 1;
 
-    if (!forceit && only_one_window() && ARGCOUNT > 1 && !arg_had_last
-                                                  && n >= 0 && quitmore == 0)
+    if (!forceit && only_one_window()
+           && ARGCOUNT > 1 && !arg_had_last && n >= 0 && quitmore == 0)
     {
        if (message)
        {
@@ -6218,6 +6220,7 @@ ex_tabclose(eap)
     exarg_T    *eap;
 {
     tabpage_T  *tp;
+    int                h = tabpageline_height();
 
 # ifdef FEAT_CMDWIN
     if (cmdwin_type != 0)
@@ -6245,6 +6248,52 @@ ex_tabclose(eap)
            if (!text_locked())
                tabpage_close(eap->forceit);
        }
+
+    if (h != tabpageline_height())
+       shell_new_rows();
+}
+
+/*
+ * ":tabonly": close all tab pages except the current one
+ */
+    static void
+ex_tabonly(eap)
+    exarg_T    *eap;
+{
+    tabpage_T  *tp;
+    int                done;
+    int                h = tabpageline_height();
+
+# ifdef FEAT_CMDWIN
+    if (cmdwin_type != 0)
+       cmdwin_result = K_IGNORE;
+    else
+# endif
+       if (first_tabpage->tp_next == NULL)
+           MSG(_("Already only one tab page"));
+       else
+       {
+           /* Repeat this up to a 1000 times, because autocommands may mess
+            * up the lists. */
+           for (done = 0; done < 1000; ++done)
+           {
+               for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+                   if (tp->tp_topframe != topframe)
+                   {
+                       tabpage_close_other(tp, eap->forceit);
+                       /* if we failed to close it quit */
+                       if (valid_tabpage(tp))
+                           done = 1000;
+                       /* start over, "tp" is now invalid */
+                       break;
+                   }
+               if (first_tabpage->tp_next == NULL)
+                   break;
+           }
+       }
+
+    if (h != tabpageline_height())
+       shell_new_rows();
 }
 
 /*
@@ -6274,17 +6323,21 @@ tabpage_close_other(tp, forceit)
     int                forceit;
 {
     int                done = 0;
+    win_T      *wp;
 
     /* Limit to 1000 windows, autocommands may add a window while we close
      * one.  OK, so I'm paranoid... */
     while (++done < 1000)
     {
-       ex_win_close(forceit, tp->tp_firstwin, tp);
+       wp = tp->tp_firstwin;
+       ex_win_close(forceit, wp, tp);
 
-       /* Autocommands may delete the tab page under our fingers. */
-       if (!valid_tabpage(tp))
+       /* Autocommands may delete the tab page under our fingers and we may
+        * fail to close a window with a modified buffer. */
+       if (!valid_tabpage(tp) || tp->tp_firstwin == wp)
            break;
     }
+    redraw_tabline = TRUE;
 }
 
 /*
@@ -7037,7 +7090,9 @@ ex_tabs(eap)
            wp = tp->tp_firstwin;
        for ( ; wp != NULL && !got_int; wp = wp->w_next)
        {
-           msg_puts((char_u *)"\n    ");
+           msg_puts((char_u *)"\n  ");
+           msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' ');
+           msg_putchar(' ');
            if (buf_spname(wp->w_buffer) != NULL)
                STRCPY(IObuff, buf_spname(wp->w_buffer));
            else
index aeb5dc9a2267532e6c707d024bd79b1f77b69613..437a4b670d4a4d9a01e27867b0309a0adbee5f33 100644 (file)
@@ -2166,8 +2166,8 @@ failed:
 #ifdef FEAT_DIFF
        /* After reading the text into the buffer the diff info needs to be
         * updated. */
-       if ((newfile || read_buffer))
-           diff_invalidate();
+       if (newfile || read_buffer)
+           diff_invalidate(curbuf);
 #endif
 #ifndef ALWAYS_USE_GUI
        /*
@@ -5524,6 +5524,7 @@ shorten_fnames(force)
     }
 #ifdef FEAT_WINDOWS
     status_redraw_all();
+    redraw_tabline = TRUE;
 #endif
 }
 
@@ -6497,7 +6498,7 @@ buf_reload(buf, orig_mode)
 
 #ifdef FEAT_DIFF
        /* Invalidate diff info if necessary. */
-       diff_invalidate();
+       diff_invalidate(buf);
 #endif
 
        /* Restore the topline and cursor position and check it (lines may
index b9b33c9e4018244871d7ef407ead6275f9fa55b6..d0f05fb4b33762928e1393d7d0df033765cfe3a4 100644 (file)
@@ -1,9 +1,8 @@
 /* diff.c */
-void diff_new_buffer __ARGS((void));
 void diff_buf_delete __ARGS((buf_T *buf));
 void diff_buf_adjust __ARGS((win_T *win));
 void diff_buf_add __ARGS((buf_T *buf));
-void diff_invalidate __ARGS((void));
+void diff_invalidate __ARGS((buf_T *buf));
 void diff_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, long amount_after));
 void ex_diffupdate __ARGS((exarg_T *eap));
 void ex_diffpatch __ARGS((exarg_T *eap));
@@ -11,7 +10,7 @@ void ex_diffsplit __ARGS((exarg_T *eap));
 void ex_diffthis __ARGS((exarg_T *eap));
 void diff_win_options __ARGS((win_T *wp, int addbuf));
 void ex_diffoff __ARGS((exarg_T *eap));
-void diff_clear __ARGS((void));
+void diff_clear __ARGS((tabpage_T *tp));
 int diff_check __ARGS((win_T *wp, linenr_T lnum));
 int diff_check_fill __ARGS((win_T *wp, linenr_T lnum));
 void diff_set_topline __ARGS((win_T *fromwin, win_T *towin));
index 927c7a15e48b88d92729d3bb5c6ce800d6991bb1..03cc56c7ecf88fc99f050c3de907e83b2b5e8eac 100644 (file)
@@ -25,6 +25,7 @@ static void win_exchange __ARGS((long));
 static void win_rotate __ARGS((int, int));
 static void win_totop __ARGS((int size, int flags));
 static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height));
+static int last_window __ARGS((void));
 static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
 static win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp));
 static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
@@ -43,7 +44,8 @@ static void frame_fix_width __ARGS((win_T *wp));
 #endif
 static int win_alloc_firstwin __ARGS((void));
 #if defined(FEAT_WINDOWS) || defined(PROTO)
-static tabpage_T *current_tabpage __ARGS((void));
+static tabpage_T *alloc_tabpage __ARGS((void));
+static void free_tabpage __ARGS((tabpage_T *tp));
 static void leave_tabpage __ARGS((tabpage_T *tp));
 static void enter_tabpage __ARGS((tabpage_T *tp, buf_T *old_curbuf));
 static void frame_fix_height __ARGS((win_T *wp));
@@ -1824,7 +1826,7 @@ close_windows(buf, keep_curwin)
     for (tp = first_tabpage; tp != NULL; tp = nexttp)
     {
        nexttp = tp->tp_next;
-       if (tp->tp_topframe != topframe)
+       if (tp != curtab)
            for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
                if (wp->w_buffer == buf)
                {
@@ -1845,9 +1847,9 @@ close_windows(buf, keep_curwin)
 
 /*
  * Return TRUE if the current window is the only window that exists.
- * Returns FALSE if there is a window in another tab page.
+ * Returns FALSE if there is a window, possibly in another tab page.
  */
-    int
+    static int
 last_window()
 {
     return (lastwin == firstwin && first_tabpage->tp_next == NULL);
@@ -1935,7 +1937,7 @@ win_close(win, free_buf)
        tabpage_T   *tp;
        tabpage_T   *atp = alt_tabpage();
 
-       for (tp = first_tabpage; tp->tp_topframe != topframe; tp = tp->tp_next)
+       for (tp = first_tabpage; tp != curtab; tp = tp->tp_next)
            ptp = tp;
        if (tp == NULL)
        {
@@ -1946,7 +1948,7 @@ win_close(win, free_buf)
            first_tabpage = tp->tp_next;
        else
            ptp->tp_next = tp->tp_next;
-       vim_free(tp);
+       free_tabpage(tp);
 
        /* We don't do the window resizing stuff, let enter_tabpage() take
         * care of entering a window in another tab page. */
@@ -2053,7 +2055,7 @@ win_close_othertab(win, free_buf, tp)
      * current tab page.  */
     for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
        ;
-    if (ptp == NULL || tp->tp_topframe == topframe)
+    if (ptp == NULL || tp == curtab)
        return;
 
     /* Autocommands may have closed the window already. */
@@ -2278,19 +2280,16 @@ win_altframe(win, tp)
     static tabpage_T *
 alt_tabpage()
 {
-    tabpage_T  *tp = current_tabpage();
+    tabpage_T  *tp;
 
-    if (tp != NULL)
-    {
-       /* Use the next tab page if it exists. */
-       if (tp->tp_next != NULL)
-           return tp->tp_next;
-
-       /* Find the previous tab page. */
-       for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
-           if (tp->tp_next == current_tabpage())
-               return tp;
-    }
+    /* Use the next tab page if it exists. */
+    if (curtab->tp_next != NULL)
+       return curtab->tp_next;
+
+    /* Find the previous tab page. */
+    for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
+       if (tp->tp_next == curtab)
+           return tp;
     return first_tabpage;
 }
 
@@ -2858,11 +2857,11 @@ win_alloc_first()
        return FAIL;
 
 #ifdef FEAT_WINDOWS
-    first_tabpage = (tabpage_T *)alloc((unsigned)sizeof(tabpage_T));
+    first_tabpage = alloc_tabpage();
     if (first_tabpage == NULL)
        return FAIL;
     first_tabpage->tp_topframe = topframe;
-    first_tabpage->tp_next = NULL;
+    curtab = first_tabpage;
 #endif
     return OK;
 }
@@ -2918,6 +2917,36 @@ win_init_size()
 }
 
 #if defined(FEAT_WINDOWS) || defined(PROTO)
+
+/*
+ * Allocate a new tabpage_T and init the values.
+ * Returns NULL when out of memory.
+ */
+    static tabpage_T *
+alloc_tabpage()
+{
+    tabpage_T  *tp;
+
+    tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
+    if (tp != NULL)
+    {
+# ifdef FEAT_DIFF
+       tp->tp_diff_invalid = TRUE;
+# endif
+    }
+    return tp;
+}
+
+    static void
+free_tabpage(tp)
+    tabpage_T  *tp;
+{
+# ifdef FEAT_DIFF
+    diff_clear(tp);
+# endif
+    vim_free(tp);
+}
+
 /*
  * Create a new Tab page with one empty window.
  * Put it just after the current Tab page.
@@ -2926,17 +2955,16 @@ win_init_size()
     int
 win_new_tabpage()
 {
-    tabpage_T  *tp;
+    tabpage_T  *tp = curtab;
     tabpage_T  *newtp;
 
-    newtp = (tabpage_T *)alloc((unsigned)sizeof(tabpage_T));
+    newtp = alloc_tabpage();
     if (newtp == NULL)
        return FAIL;
 
-    tp = current_tabpage();
-
     /* Remember the current windows in this Tab page. */
-    leave_tabpage(tp);
+    leave_tabpage(curtab);
+    curtab = newtp;
 
     /* Create a new empty window. */
     if (win_alloc_firstwin() == OK)
@@ -2962,23 +2990,43 @@ win_new_tabpage()
     prevwin = tp->tp_prevwin;
     firstwin = tp->tp_firstwin;
     lastwin = tp->tp_lastwin;
+    curtab = tp;
     return FAIL;
 }
 
 /*
- * Return a pointer to the current tab page.
+ * Create up to "maxcount" tabpages with empty windows.
+ * Returns the number of resulting tab pages.
  */
-    static tabpage_T *
-current_tabpage()
+    int
+make_tabpages(maxcount)
+    int                maxcount;
 {
-    tabpage_T  *tp;
+    int                count = maxcount;
+    int                todo;
 
-    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
-       if (tp->tp_topframe == topframe)
+    /* Limit to 10 tabs. */
+    if (count > 10)
+       count = 10;
+
+#ifdef FEAT_AUTOCMD
+    /*
+     * Don't execute autocommands while creating the tab pages.  Must do that
+     * when putting the buffers in the windows.
+     */
+    ++autocmd_block;
+#endif
+
+    for (todo = count - 1; todo > 0; --todo)
+       if (win_new_tabpage() == FAIL)
            break;
-    if (tp == NULL)
-       EMSG2(_(e_intern2), "current_tabpage()");
-    return tp;
+
+#ifdef FEAT_AUTOCMD
+    --autocmd_block;
+#endif
+
+    /* return actual number of tab pages */
+    return (count - todo);
 }
 
 /*
@@ -3044,6 +3092,7 @@ enter_tabpage(tp, old_curbuf)
 {
     int                old_off = tp->tp_firstwin->w_winrow;
 
+    curtab = tp;
     firstwin = tp->tp_firstwin;
     lastwin = tp->tp_lastwin;
     topframe = tp->tp_topframe;
@@ -3057,6 +3106,10 @@ enter_tabpage(tp, old_curbuf)
 
     last_status(FALSE);                /* status line may appear or disappear */
     (void)win_comp_pos();      /* recompute w_winrow for all windows */
+    must_redraw = CLEAR;       /* need to redraw everything */
+#ifdef FEAT_DIFF
+    diff_need_scrollbind = TRUE;
+#endif
 
     /* The tabpage line may have appeared or disappeared, may need to resize
      * the frames for that.  When the Vim window was resized need to update
@@ -3064,7 +3117,7 @@ enter_tabpage(tp, old_curbuf)
     if (tp->tp_old_Rows != Rows || old_off != firstwin->w_winrow)
        shell_new_rows();
 #ifdef FEAT_VERTSPLIT
-    if (tp->tp_old_Columns != Columns)
+    if (tp->tp_old_Columns != Columns && starting == 0)
        shell_new_columns();    /* update window widths */
 #endif
 
@@ -3090,7 +3143,7 @@ enter_tabpage(tp, old_curbuf)
 goto_tabpage(n)
     int            n;
 {
-    tabpage_T  *otp = current_tabpage();
+    tabpage_T  *otp = curtab;
     tabpage_T  *tp;
     int                i;
 
@@ -3410,7 +3463,7 @@ win_enter_ext(wp, undo_sync, curwin_invalid)
     maketitle();
 #endif
     curwin->w_redr_status = TRUE;
-    redraw_tabpage = TRUE;
+    redraw_tabline = TRUE;
     if (restart_edit)
        redraw_later(VALID);    /* causes status line redraw */
 
@@ -5272,8 +5325,8 @@ min_rows()
 }
 
 /*
- * Return TRUE if there is only one window, not counting a help or preview
- * window, unless it is the current window.
+ * Return TRUE if there is only one window (in the current tab page), not
+ * counting a help or preview window, unless it is the current window.
  */
     int
 only_one_window()