/* vim:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * diff.c: code for diff'ing two or three buffers. */ #include "vim.h" #if defined(FEAT_DIFF) || defined(PROTO) static int diff_busy = FALSE; /* ex_diffgetput() is busy */ /* flags obtained from the 'diffopt' option */#define DIFF_FILLER 1 /* display filler lines */#define DIFF_ICASE 2 /* ignore case */#define DIFF_IWHITE 4 /* ignore change in white space */#define DIFF_HORIZONTAL 8 /* horizontal splits */#define DIFF_VERTICAL 16 /* vertical splits */static int diff_flags = DIFF_FILLER; #define LBUFLEN 50 /* length of line in diff file */ static int diff_a_works = MAYBE; /* TRUE when "diff -a" works, FALSE when it doesn't work, MAYBE when not checked yet */#if defined(MSWIN) || defined(MSDOS)static int diff_bin_works = MAYBE; /* TRUE when "diff --binary" works, FALSE when it doesn't work, MAYBE when not checked yet */#endif static int diff_buf_idx __ARGS((buf_T *buf));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));static int diff_equal_entry __ARGS((diff_T *dp, int idx1, int idx2));static int diff_cmp __ARGS((char_u *s1, char_u *s2));#ifdef FEAT_FOLDINGstatic void diff_fold_update __ARGS((diff_T *dp, int skip_idx));#endifstatic 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((tabpage_T *tp, diff_T *dprev, diff_T *dp)); #ifndef USE_CR# define tag_fgets vim_fgets#endif /* * Called when deleting or unloading a buffer: No longer make a diff with it. */ voiddiff_buf_delete(buf) buf_T *buf;{ int i; tabpage_T *tp; for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { i = diff_buf_idx_tp(buf, tp); if (i != DB_COUNT) { tp->tp_diffbuf[i] = NULL; tp->tp_diff_invalid = TRUE; } }} /* * Check if the current buffer should be added to or removed from the list of * diff buffers. */ voiddiff_buf_adjust(win) win_T *win;{ win_T *wp; int i; if (!win->w_p_diff) { /* When there is no window showing a diff for this buffer, remove * it from the diffs. */ for (wp = firstwin; wp != NULL; wp = wp->w_next) if (wp->w_buffer == win->w_buffer && wp->w_p_diff) break; if (wp == NULL) { 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);} /* * 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. */ voiddiff_buf_add(buf) buf_T *buf;{ int i; if (diff_buf_idx(buf) != DB_COUNT) return; /* It's already there. */ for (i = 0; i < DB_COUNT; ++i) if (curtab->tp_diffbuf[i] == NULL) { curtab->tp_diffbuf[i] = buf; curtab->tp_diff_invalid = TRUE; return; } EMSGN(_("E96: Can not diff more than %ld buffers"), DB_COUNT);} /* * Find buffer "buf" in the list of diff buffers for the current tab page. * Return its index or DB_COUNT if not found. */ static intdiff_buf_idx(buf) buf_T *buf;{ int idx; for (idx = 0; idx < DB_COUNT; ++idx) 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 intdiff_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 involving buffer "buf" as invalid, it will be updated * when info is requested. */ voiddiff_invalidate(buf) buf_T *buf;{ tabpage_T *tp; int i; for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { 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 in "curbuf". */ voiddiff_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. */ static voiddiff_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 i; int inserted, deleted; int n, off; linenr_T last; linenr_T lnum_deleted = line1; /* lnum of remaining deletion */ int check_unchanged; if (line2 == MAXLNUM) { /* mark_adjust(99, MAXLNUM, 9, 0): insert lines */ inserted = amount; deleted = 0; } else if (amount_after > 0) { /* mark_adjust(99, 98, MAXLNUM, 9): a change that inserts lines*/ inserted = amount_after; deleted = 0; } else { /* mark_adjust(98, 99, MAXLNUM, -2): delete lines */ inserted = 0; deleted = -amount_after; } dprev = NULL; dp = tp->tp_first_diff; for (;;) { /* If the change is after the previous diff block and before the next * diff block, thus not touching an existing change, create a new diff * block. Don't do this when ex_diffgetput() is busy. */ if ((dp == NULL || dp->df_lnum[idx] - 1 > line2 || (line2 == MAXLNUM && dp->df_lnum[idx] > line1)) && (dprev == NULL || dprev->df_lnum[idx] + dprev->df_count[idx] < line1) && !diff_busy) { 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 (tp->tp_diffbuf[i] != NULL && i != idx) { if (dprev == NULL) dnext->df_lnum[i] = line1; else dnext->df_lnum[i] = line1 + (dprev->df_lnum[i] + dprev->df_count[i]) - (dprev->df_lnum[idx] + dprev->df_count[idx]); dnext->df_count[i] = deleted; } } /* if at end of the list, quit */ if (dp == NULL) break; /* * Check for these situations: * 1 2 3 * 1 2 3 * line1 2 3 4 5 * 2 3 4 5 * 2 3 4 5 * line2 2 3 4 5 * 3 5 6 * 3 5 6 */ /* compute last line of this change */ last = dp->df_lnum[idx] + dp->df_count[idx] - 1; /* 1. change completely above line1: nothing to do */ if (last >= line1 - 1) { /* 6. change below line2: only adjust for amount_after; also when * "deleted" became zero when deleted all lines between two diffs */ if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2) { if (amount_after == 0) break; /* nothing left to change */ dp->df_lnum[idx] += amount_after; } else { check_unchanged = FALSE; /* 2. 3. 4. 5.: inserted/deleted lines touching this diff. */ if (deleted > 0) { if (dp->df_lnum[idx] >= line1) { off = dp->df_lnum[idx] - lnum_deleted; if (last <= line2) { /* 4. delete all lines of diff */ if (dp->df_next != NULL && dp->df_next->df_lnum[idx] - 1 <= line2) { /* delete continues in next diff, only do * lines until that one */ n = dp->df_next->df_lnum[idx] - lnum_deleted; deleted -= n; n -= dp->df_count[idx]; lnum_deleted = dp->df_next->df_lnum[idx]; } else n = deleted - dp->df_count[idx]; dp->df_count[idx] = 0; } else { /* 5. delete lines at or just before top of diff */ n = off; dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1; check_unchanged = TRUE; } dp->df_lnum[idx] = line1; } else { off = 0; if (last < line2) { /* 2. delete at end of of diff */ dp->df_count[idx] -= last - lnum_deleted + 1; if (dp->df_next != NULL && dp->df_next->df_lnum[idx] - 1 <= line2) { /* delete continues in next diff, only do * lines until that one */ n = dp->df_next->df_lnum[idx] - 1 - last; deleted -= dp->df_next->df_lnum[idx] - lnum_deleted; lnum_deleted = dp->df_next->df_lnum[idx]; } else n = line2 - last; check_unchanged = TRUE; } else { /* 3. delete lines inside the diff */ n = 0; dp->df_count[idx] -= deleted; } } for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL && i != idx) { dp->df_lnum[i] -= off; dp->df_count[i] += n; } } else { if (dp->df_lnum[idx] <= line1) { /* inserted lines somewhere in this diff */ dp->df_count[idx] += inserted; check_unchanged = TRUE; } else /* inserted lines somewhere above this diff */ dp->df_lnum[idx] += inserted; } if (check_unchanged) /* 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(tp, dp); } } /* check if this block touches the previous one, may merge them. */ if (dprev != NULL && dprev->df_lnum[idx] + dprev->df_count[idx] == dp->df_lnum[idx]) { for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL) dprev->df_count[i] += dp->df_count[i]; dprev->df_next = dp->df_next; vim_free(dp); dp = dprev->df_next; } else { /* Advance to next entry. */ dprev = dp; dp = dp->df_next; } } dprev = NULL; dp = tp->tp_first_diff; while (dp != NULL) { /* All counts are zero, remove this entry. */ for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0) break; if (i == DB_COUNT) { dnext = dp->df_next; vim_free(dp); dp = dnext; if (dprev == NULL) tp->tp_first_diff = dnext; else dprev->df_next = dnext; } else { /* Advance to next entry. */ dprev = dp; dp = dp->df_next; } } 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(tp, dprev, dp) tabpage_T *tp; diff_T *dprev; diff_T *dp;{ diff_T *dnew; dnew = (diff_T *)alloc((unsigned)sizeof(diff_T)); if (dnew != NULL) { dnew->df_next = dp; if (dprev == NULL) tp->tp_first_diff = dnew; else dprev->df_next = dnew; } return dnew;} /* * Check if the diff block "dp" can be made smaller for lines at the start and * end that are equal. Called after inserting lines. * This may result in a change where all buffers have zero lines, the callerLines 1–500 of 2458. Load more
/* vim:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * diff.c: code for diff'ing two or three buffers. */ #include "vim.h" #if defined(FEAT_DIFF) || defined(PROTO) static int diff_busy = FALSE; /* ex_diffgetput() is busy */ /* flags obtained from the 'diffopt' option */ #define DIFF_FILLER 1 /* display filler lines */ #define DIFF_ICASE 2 /* ignore case */ #define DIFF_IWHITE 4 /* ignore change in white space */ #define DIFF_HORIZONTAL 8 /* horizontal splits */ #define DIFF_VERTICAL 16 /* vertical splits */ static int diff_flags = DIFF_FILLER; #define LBUFLEN 50 /* length of line in diff file */ static int diff_a_works = MAYBE; /* TRUE when "diff -a" works, FALSE when it doesn't work, MAYBE when not checked yet */ #if defined(MSWIN) || defined(MSDOS) static int diff_bin_works = MAYBE; /* TRUE when "diff --binary" works, FALSE when it doesn't work, MAYBE when not checked yet */ #endif static int diff_buf_idx __ARGS((buf_T *buf)); 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)); static int diff_equal_entry __ARGS((diff_T *dp, int idx1, int idx2)); static int diff_cmp __ARGS((char_u *s1, char_u *s2)); #ifdef FEAT_FOLDING 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((tabpage_T *tp, diff_T *dprev, diff_T *dp)); #ifndef USE_CR # define tag_fgets vim_fgets #endif /* * Called when deleting or unloading a buffer: No longer make a diff with it. */ void diff_buf_delete(buf) buf_T *buf; { int i; tabpage_T *tp; for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { i = diff_buf_idx_tp(buf, tp); if (i != DB_COUNT) { tp->tp_diffbuf[i] = NULL; tp->tp_diff_invalid = TRUE; } } } /* * Check if the current buffer should be added to or removed from the list of * diff buffers. */ void diff_buf_adjust(win) win_T *win; { win_T *wp; int i; if (!win->w_p_diff) { /* When there is no window showing a diff for this buffer, remove * it from the diffs. */ for (wp = firstwin; wp != NULL; wp = wp->w_next) if (wp->w_buffer == win->w_buffer && wp->w_p_diff) break; if (wp == NULL) { 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); } /* * 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) buf_T *buf; { int i; if (diff_buf_idx(buf) != DB_COUNT) return; /* It's already there. */ for (i = 0; i < DB_COUNT; ++i) if (curtab->tp_diffbuf[i] == NULL) { curtab->tp_diffbuf[i] = buf; curtab->tp_diff_invalid = TRUE; return; } EMSGN(_("E96: Can not diff more than %ld buffers"), DB_COUNT); } /* * 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 diff_buf_idx(buf) buf_T *buf; { int idx; for (idx = 0; idx < DB_COUNT; ++idx) 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 involving buffer "buf" as invalid, it will be updated * when info is requested. */ void diff_invalidate(buf) buf_T *buf; { tabpage_T *tp; int i; for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { 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 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. */ 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 i; int inserted, deleted; int n, off; linenr_T last; linenr_T lnum_deleted = line1; /* lnum of remaining deletion */ int check_unchanged; if (line2 == MAXLNUM) { /* mark_adjust(99, MAXLNUM, 9, 0): insert lines */ inserted = amount; deleted = 0; } else if (amount_after > 0) { /* mark_adjust(99, 98, MAXLNUM, 9): a change that inserts lines*/ inserted = amount_after; deleted = 0; } else { /* mark_adjust(98, 99, MAXLNUM, -2): delete lines */ inserted = 0; deleted = -amount_after; } dprev = NULL; dp = tp->tp_first_diff; for (;;) { /* If the change is after the previous diff block and before the next * diff block, thus not touching an existing change, create a new diff * block. Don't do this when ex_diffgetput() is busy. */ if ((dp == NULL || dp->df_lnum[idx] - 1 > line2 || (line2 == MAXLNUM && dp->df_lnum[idx] > line1)) && (dprev == NULL || dprev->df_lnum[idx] + dprev->df_count[idx] < line1) && !diff_busy) { 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 (tp->tp_diffbuf[i] != NULL && i != idx) { if (dprev == NULL) dnext->df_lnum[i] = line1; else dnext->df_lnum[i] = line1 + (dprev->df_lnum[i] + dprev->df_count[i]) - (dprev->df_lnum[idx] + dprev->df_count[idx]); dnext->df_count[i] = deleted; } } /* if at end of the list, quit */ if (dp == NULL) break; /* * Check for these situations: * 1 2 3 * 1 2 3 * line1 2 3 4 5 * 2 3 4 5 * 2 3 4 5 * line2 2 3 4 5 * 3 5 6 * 3 5 6 */ /* compute last line of this change */ last = dp->df_lnum[idx] + dp->df_count[idx] - 1; /* 1. change completely above line1: nothing to do */ if (last >= line1 - 1) { /* 6. change below line2: only adjust for amount_after; also when * "deleted" became zero when deleted all lines between two diffs */ if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2) { if (amount_after == 0) break; /* nothing left to change */ dp->df_lnum[idx] += amount_after; } else { check_unchanged = FALSE; /* 2. 3. 4. 5.: inserted/deleted lines touching this diff. */ if (deleted > 0) { if (dp->df_lnum[idx] >= line1) { off = dp->df_lnum[idx] - lnum_deleted; if (last <= line2) { /* 4. delete all lines of diff */ if (dp->df_next != NULL && dp->df_next->df_lnum[idx] - 1 <= line2) { /* delete continues in next diff, only do * lines until that one */ n = dp->df_next->df_lnum[idx] - lnum_deleted; deleted -= n; n -= dp->df_count[idx]; lnum_deleted = dp->df_next->df_lnum[idx]; } else n = deleted - dp->df_count[idx]; dp->df_count[idx] = 0; } else { /* 5. delete lines at or just before top of diff */ n = off; dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1; check_unchanged = TRUE; } dp->df_lnum[idx] = line1; } else { off = 0; if (last < line2) { /* 2. delete at end of of diff */ dp->df_count[idx] -= last - lnum_deleted + 1; if (dp->df_next != NULL && dp->df_next->df_lnum[idx] - 1 <= line2) { /* delete continues in next diff, only do * lines until that one */ n = dp->df_next->df_lnum[idx] - 1 - last; deleted -= dp->df_next->df_lnum[idx] - lnum_deleted; lnum_deleted = dp->df_next->df_lnum[idx]; } else n = line2 - last; check_unchanged = TRUE; } else { /* 3. delete lines inside the diff */ n = 0; dp->df_count[idx] -= deleted; } } for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL && i != idx) { dp->df_lnum[i] -= off; dp->df_count[i] += n; } } else { if (dp->df_lnum[idx] <= line1) { /* inserted lines somewhere in this diff */ dp->df_count[idx] += inserted; check_unchanged = TRUE; } else /* inserted lines somewhere above this diff */ dp->df_lnum[idx] += inserted; } if (check_unchanged) /* 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(tp, dp); } } /* check if this block touches the previous one, may merge them. */ if (dprev != NULL && dprev->df_lnum[idx] + dprev->df_count[idx] == dp->df_lnum[idx]) { for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL) dprev->df_count[i] += dp->df_count[i]; dprev->df_next = dp->df_next; vim_free(dp); dp = dprev->df_next; } else { /* Advance to next entry. */ dprev = dp; dp = dp->df_next; } } dprev = NULL; dp = tp->tp_first_diff; while (dp != NULL) { /* All counts are zero, remove this entry. */ for (i = 0; i < DB_COUNT; ++i) if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0) break; if (i == DB_COUNT) { dnext = dp->df_next; vim_free(dp); dp = dnext; if (dprev == NULL) tp->tp_first_diff = dnext; else dprev->df_next = dnext; } else { /* Advance to next entry. */ dprev = dp; dp = dp->df_next; } } 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(tp, dprev, dp) tabpage_T *tp; diff_T *dprev; diff_T *dp; { diff_T *dnew; dnew = (diff_T *)alloc((unsigned)sizeof(diff_T)); if (dnew != NULL) { dnew->df_next = dp; if (dprev == NULL) tp->tp_first_diff = dnew; else dprev->df_next = dnew; } return dnew; } /* * Check if the diff block "dp" can be made smaller for lines at the start and * end that are equal. Called after inserting lines. * This may result in a change where all buffers have zero lines, the caller