# HG changeset patch # User vimboss # Date 1140212741 0 # Node ID db58b9066b21c195741303e15f5559f545ffa0e7 # Parent 83a006f81bac04bf9b975347bf8d6bddc7996eb6 updated for version 7.0200 diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -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 diff --git a/src/diff.c b/src/diff.c --- 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; diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -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); - - /* Autocommands may delete the tab page under our fingers. */ - if (!valid_tabpage(tp)) + wp = tp->tp_firstwin; + ex_win_close(forceit, wp, 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 diff --git a/src/fileio.c b/src/fileio.c --- a/src/fileio.c +++ b/src/fileio.c @@ -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 diff --git a/src/proto/diff.pro b/src/proto/diff.pro --- a/src/proto/diff.pro +++ b/src/proto/diff.pro @@ -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)); diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -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_ #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(); - - 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; - } + tabpage_T *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; - - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) - if (tp->tp_topframe == topframe) + int count = maxcount; + int todo; + + /* 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_inva 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()