To: vim-dev@vim.org Subject: Patch 6.2.298 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.2.298 Problem: A change always sets the '. mark and an insert always sets the '^ mark, even when this is not wanted. Cannot go back to the position of older changes without undoing those changes. Solution: Add the ":keepjumps" command modifier. Add the "g," and "g;" commands. Files: runtime/doc/motion.txt, src/ex_cmds.h, src/ex_docmd.c, src/edit.c, src/mark.c, src/misc1.c, src/normal.c, src/proto/mark.pro, src/structs.h, src/undo.c *** ../vim-6.2.297/runtime/doc/motion.txt Sun Jan 18 21:12:26 2004 --- runtime/doc/motion.txt Sun Feb 29 20:37:53 2004 *************** *** 1,4 **** ! *motion.txt* For Vim version 6.2. Last change: 2004 Jan 17 VIM REFERENCE MANUAL by Bram Moolenaar --- 1,4 ---- ! *motion.txt* For Vim version 6.2. Last change: 2004 Feb 29 VIM REFERENCE MANUAL by Bram Moolenaar *************** *** 857,862 **** --- 865,879 ---- When the 'R' flag is missing from 'cpoptions' this has the same effect as using ":keepmarks". + *:keepj* *:keepjumps* + :keepj[umps] {command} + Do not change the |''|, |'.| and |'^| marks, the + |jumplist| or the |changelist|. Useful when making a + change or inserting text automatically and the user + doesn't want to go to this position. E.g., when + updating a "Last change" timestamp: > + autocmd BufWritePre,FileWritePre *.abc keepjumps call SetLastChange() + ============================================================================== 8. Jumps *jump-motions* *************** *** 929,934 **** --- 946,954 ---- The result is that when repeating CTRL-O you will get back to old positions only once. + When the |:keepjumps| command modifier is used, jumps are not stored in the + jumplist. + After the CTRL-O command that got you into line 1154 you could give another jump command (e.g., "G"). The jump list would then become: *************** *** 947,952 **** --- 967,1003 ---- If you have included the ' item in the 'viminfo' option the jumplist will be stored in the viminfo file and restored when starting Vim. + + CHANGE LIST JUMPS *changelist* *change-list-jumps* + + For changes the cursor position is remembered. One position is remembered for + every change that can be undone. Two commands can be used to jump to + positions of changes, also those that have been undone. + + *g;* + g; Go to [count] older cursor position in change list + (not a motion command). + {not in Vi} + {not available without the +jumplist feature} + + *g,* + g, Go to [count] newer cursor position in change list + (not a motion command). + {not in Vi} + {not available without the +jumplist feature} + + When you already are at the end or start of the change list you will get an + error message. When using a count you jump as far back or forward as + possible. Thus you can use "999g;" to go to the first change for which the + position is still remembered. The number of entries in the change list is + fixed and is the same as for the |jumplist|. + + Note that when text has been inserted or deleted the cursor position might be + a bit different from the position of the change. + + When the |:keepjumps| command modifier is used the position of a change is not + remembered. + ============================================================================== 9. Various motions *various-motions* *** ../vim-6.2.297/src/ex_cmds.h Tue Feb 17 20:41:09 2004 --- src/ex_cmds.h Sun Feb 29 18:12:43 2004 *************** *** 206,211 **** --- 206,213 ---- TRLBAR|FILE1|BANG), EX(CMD_chdir, "chdir", ex_cd, FILE1|TRLBAR|CMDWIN), + EX(CMD_changes, "changes", ex_changes, + TRLBAR|CMDWIN), EX(CMD_checkpath, "checkpath", ex_checkpath, TRLBAR|BANG|CMDWIN), EX(CMD_checktime, "checktime", ex_checktime, *************** *** 445,450 **** --- 447,454 ---- EX(CMD_k, "k", ex_mark, RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN), EX(CMD_keepmarks, "keepmarks", ex_wrongmodifier, + NEEDARG|EXTRA|NOTRLCOM), + EX(CMD_keepjumps, "keepjumps", ex_wrongmodifier, NEEDARG|EXTRA|NOTRLCOM), EX(CMD_list, "list", ex_print, RANGE|WHOLEFOLD|COUNT|TRLBAR|CMDWIN), *** ../vim-6.2.297/src/ex_docmd.c Thu Feb 19 15:23:11 2004 --- src/ex_docmd.c Sun Feb 29 18:13:29 2004 *************** *** 409,414 **** --- 409,415 ---- #endif #ifndef FEAT_JUMPLIST # define ex_jumps ex_ni + # define ex_changes ex_ni #endif /* *************** *** 1657,1665 **** #endif continue; ! case 'k': if (!checkforcmd(&ea.cmd, "keepmarks", 3)) break; ! cmdmod.keepmarks = TRUE; continue; /* ":hide" and ":hide | cmd" are not modifiers */ --- 1658,1671 ---- #endif continue; ! case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3)) ! { ! cmdmod.keepmarks = TRUE; ! continue; ! } ! if (!checkforcmd(&ea.cmd, "keepjumps", 5)) break; ! cmdmod.keepjumps = TRUE; continue; /* ":hide" and ":hide | cmd" are not modifiers */ *************** *** 2352,2357 **** --- 2356,2362 ---- case CMD_ilist: case CMD_isearch: case CMD_isplit: + case CMD_keepjumps: case CMD_keepmarks: case CMD_leftabove: case CMD_let: *************** *** 2747,2752 **** --- 2752,2758 ---- {"browse", 3}, {"confirm", 4}, {"hide", 3}, + {"keepjumps", 5}, {"keepmarks", 3}, {"leftabove", 5}, {"lockmarks", 3}, *************** *** 2848,2854 **** * Isolate the command and search for it in the command table. * Exceptions: * - the 'k' command can directly be followed by any character, but ! * do accept "keepmarks". * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' */ if (*cmd == 'k' && cmd[1] != 'e') --- 2854,2860 ---- * Isolate the command and search for it in the command table. * Exceptions: * - the 'k' command can directly be followed by any character, but ! * do accept "keepmarks" and "keepjumps". * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' */ if (*cmd == 'k' && cmd[1] != 'e') *************** *** 3188,3193 **** --- 3194,3200 ---- case CMD_folddoclosed: case CMD_folddoopen: case CMD_hide: + case CMD_keepjumps: case CMD_keepmarks: case CMD_leftabove: case CMD_lockmarks: *** ../vim-6.2.297/src/edit.c Sun Jan 18 21:22:26 2004 --- src/edit.c Sun Feb 29 15:07:20 2004 *************** *** 6090,6096 **** curwin->w_set_curswant = TRUE; /* Remember the last Insert position in the '^ mark. */ ! curbuf->b_last_insert = curwin->w_cursor; /* * The cursor should end up on the last inserted character. --- 6089,6096 ---- curwin->w_set_curswant = TRUE; /* Remember the last Insert position in the '^ mark. */ ! if (!cmdmod.keepjumps) ! curbuf->b_last_insert = curwin->w_cursor; /* * The cursor should end up on the last inserted character. *** ../vim-6.2.297/src/mark.c Sun Jan 18 21:12:26 2004 --- src/mark.c Sun Feb 29 20:19:17 2004 *************** *** 99,105 **** #endif /* for :global the mark is set only once */ ! if (global_busy || listcmd_busy) return; curwin->w_prev_pcmark = curwin->w_pcmark; --- 99,105 ---- #endif /* for :global the mark is set only once */ ! if (global_busy || listcmd_busy || cmdmod.keepjumps) return; curwin->w_prev_pcmark = curwin->w_pcmark; *************** *** 219,224 **** --- 219,255 ---- return pos; } } + + /* + * Move "count" positions in the changelist (count may be negative). + */ + pos_T * + movechangelist(count) + int count; + { + int n; + + if (curbuf->b_changelistlen == 0) /* nothing to jump to */ + return (pos_T *)NULL; + + n = curwin->w_changelistidx; + if (n + count < 0) + { + if (n == 0) + return (pos_T *)NULL; + n = 0; + } + else if (n + count >= curbuf->b_changelistlen) + { + if (n == curbuf->b_changelistlen - 1) + return (pos_T *)NULL; + n = curbuf->b_changelistlen - 1; + } + else + n += count; + curwin->w_changelistidx = n; + return curbuf->b_changelist + n; + } #endif /* *************** *** 547,552 **** --- 578,586 ---- #endif buf->b_last_insert.lnum = 0; /* '^ mark cleared */ buf->b_last_change.lnum = 0; /* '. mark cleared */ + #ifdef FEAT_JUMPLIST + buf->b_changelistlen = 0; + #endif } /* *************** *** 742,747 **** --- 776,822 ---- if (curwin->w_jumplistidx == curwin->w_jumplistlen) MSG_PUTS("\n>"); } + + /* + * print the changelist + */ + /*ARGSUSED*/ + void + ex_changes(eap) + exarg_T *eap; + { + int i; + char_u *name; + + /* Highlight title */ + MSG_PUTS_TITLE(_("\nchange line col text")); + + for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i) + { + if (curbuf->b_changelist[i].lnum != 0) + { + msg_putchar('\n'); + if (got_int) + break; + sprintf((char *)IObuff, "%c %3d %5ld %4d ", + i == curwin->w_changelistidx ? '>' : ' ', + i > curwin->w_changelistidx ? i - curwin->w_changelistidx + : curwin->w_changelistidx - i, + (long)curbuf->b_changelist[i].lnum, + curbuf->b_changelist[i].col); + msg_outtrans(IObuff); + name = mark_line(&curbuf->b_changelist[i], 17); + if (name == NULL) + break; + msg_outtrans_attr(name, hl_attr(HLF_D)); + vim_free(name); + ui_breakcheck(); + } + out_flush(); + } + if (curwin->w_changelistidx == curbuf->b_changelistlen) + MSG_PUTS("\n>"); + } #endif #define one_adjust(add) \ *************** *** 799,807 **** if (line2 < line1 && amount_after == 0L) /* nothing to do */ return; - /* named marks, lower case and upper case */ if (!cmdmod.lockmarks) { for (i = 0; i < NMARKS; i++) { one_adjust(&(curbuf->b_namedm[i].lnum)); --- 874,882 ---- if (line2 < line1 && amount_after == 0L) /* nothing to do */ return; if (!cmdmod.lockmarks) { + /* named marks, lower case and upper case */ for (i = 0; i < NMARKS; i++) { one_adjust(&(curbuf->b_namedm[i].lnum)); *************** *** 820,825 **** --- 895,906 ---- /* last change position */ one_adjust(&(curbuf->b_last_change.lnum)); + #ifdef FEAT_JUMPLIST + /* list of change positions */ + for (i = 0; i < curbuf->b_changelistlen; ++i) + one_adjust(&(curbuf->b_changelist[i].lnum)); + #endif + #ifdef FEAT_VISUAL /* Visual area */ one_adjust_nodel(&(curbuf->b_visual_start.lnum)); *************** *** 1242,1247 **** --- 1323,1333 ---- write_one_mark(fp_out, '"', &buf->b_last_cursor); write_one_mark(fp_out, '^', &buf->b_last_insert); write_one_mark(fp_out, '.', &buf->b_last_change); + #ifdef FEAT_JUMPLIST + /* changelist positions are stored oldest first */ + for (i = 0; i < buf->b_changelistlen; ++i) + write_one_mark(fp_out, '+', &buf->b_changelist[i]); + #endif for (i = 0; i < NMARKS; i++) write_one_mark(fp_out, 'a' + i, &buf->b_namedm[i]); count++; *************** *** 1287,1292 **** --- 1373,1379 ---- if ((name_buf = alloc(LSIZE)) == NULL) return; + *name_buf = NUL; num_marked_files = get_viminfo_parameter('\''); while (!eof && (count < num_marked_files || fp_out == NULL)) { *************** *** 1326,1332 **** { if (curbuf->b_ffname != NULL) { ! home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE); if (fnamecmp(str, name_buf) == 0) load_marks = TRUE; } --- 1413,1420 ---- { if (curbuf->b_ffname != NULL) { ! if (*name_buf == NUL) /* only need to do this once */ ! home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE); if (fnamecmp(str, name_buf) == 0) load_marks = TRUE; } *************** *** 1370,1375 **** --- 1458,1478 ---- case '"': curbuf->b_last_cursor = pos; break; case '^': curbuf->b_last_insert = pos; break; case '.': curbuf->b_last_change = pos; break; + case '+': + #ifdef FEAT_JUMPLIST + /* changelist positions are stored oldest + * first */ + if (curbuf->b_changelistlen == JUMPLISTSIZE) + /* list is full, remove oldest entry */ + mch_memmove(curbuf->b_changelist, + curbuf->b_changelist + 1, + sizeof(pos_T) * (JUMPLISTSIZE - 1)); + else + ++curbuf->b_changelistlen; + curbuf->b_changelist[ + curbuf->b_changelistlen] = pos; + #endif + break; default: if ((i = line[1] - 'a') >= 0 && i < NMARKS) curbuf->b_namedm[i] = pos; } *************** *** 1379,1385 **** --- 1482,1499 ---- fputs((char *)line, fp_out); } if (load_marks) + { + #ifdef FEAT_JUMPLIST + win_T *wp; + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_buffer == curbuf) + wp->w_changelistidx = curbuf->b_changelistlen; + } + #endif break; + } } vim_free(name_buf); } *** ../vim-6.2.297/src/misc1.c Sun Feb 29 14:45:49 2004 --- src/misc1.c Sun Feb 29 20:18:00 2004 *************** *** 2499,2506 **** changed(); /* set the '. mark */ ! curbuf->b_last_change.lnum = lnum; ! curbuf->b_last_change.col = col; FOR_ALL_WINDOWS(wp) { --- 2508,2556 ---- changed(); /* set the '. mark */ ! if (!cmdmod.keepjumps) ! { ! curbuf->b_last_change.lnum = lnum; ! curbuf->b_last_change.col = col; ! ! #ifdef FEAT_JUMPLIST ! if (curbuf->b_new_change) ! { ! /* This is the first of a new sequence of undo-able changes. ! * Use a new position in the changelist. */ ! curbuf->b_new_change = FALSE; ! ! if (curbuf->b_changelistlen == JUMPLISTSIZE) ! { ! /* changelist is full: remove oldest entry */ ! curbuf->b_changelistlen = JUMPLISTSIZE - 1; ! mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1, ! sizeof(pos_T) * (JUMPLISTSIZE - 1)); ! FOR_ALL_WINDOWS(wp) ! { ! /* Correct position in changelist for other windows on ! * this buffer. */ ! if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) ! --wp->w_changelistidx; ! } ! } ! FOR_ALL_WINDOWS(wp) ! { ! /* For other windows, if the position in the changelist is at ! * the end it stays at the end. */ ! if (wp->w_buffer == curbuf ! && wp->w_changelistidx == curbuf->b_changelistlen) ! ++wp->w_changelistidx; ! } ! ++curbuf->b_changelistlen; ! } ! curbuf->b_changelist[curbuf->b_changelistlen - 1] = ! curbuf->b_last_change; ! /* The current window is always after the last change, so that "g," ! * takes you back to it. */ ! curwin->w_changelistidx = curbuf->b_changelistlen; ! #endif ! } FOR_ALL_WINDOWS(wp) { *** ../vim-6.2.297/src/normal.c Tue Feb 3 16:29:52 2004 --- src/normal.c Sun Feb 29 17:44:08 2004 *************** *** 6578,6584 **** if (!checkclearopq(cap->oap)) { ! pos = movemark((int)cap->count1); if (pos == (pos_T *)-1) /* jump to other file */ { curwin->w_set_curswant = TRUE; --- 6578,6587 ---- if (!checkclearopq(cap->oap)) { ! if (cap->cmdchar == 'g') ! pos = movechangelist((int)cap->count1); ! else ! pos = movemark((int)cap->count1); if (pos == (pos_T *)-1) /* jump to other file */ { curwin->w_set_curswant = TRUE; *************** *** 7343,7348 **** --- 7347,7363 ---- if (!checkclearopq(oap)) do_exmode(TRUE); break; + + #ifdef FEAT_JUMPLIST + case ',': + nv_pcmark(cap); + break; + + case ';': + cap->count1 = -cap->count1; + nv_pcmark(cap); + break; + #endif default: clearopbeep(oap); *** ../vim-6.2.297/src/proto/mark.pro Sun Jun 1 12:26:13 2003 --- src/proto/mark.pro Sun Feb 29 18:13:41 2004 *************** *** 3,8 **** --- 3,9 ---- void setpcmark __ARGS((void)); void checkpcmark __ARGS((void)); pos_T *movemark __ARGS((int count)); + pos_T *movechangelist __ARGS((int count)); pos_T *getmark __ARGS((int c, int changefile)); pos_T *getnextmark __ARGS((pos_T *startpos, int dir, int begin_line)); void fmarks_check_names __ARGS((buf_T *buf)); *************** *** 11,16 **** --- 12,18 ---- char_u *fm_getname __ARGS((fmark_T *fmark, int lead_len)); void do_marks __ARGS((exarg_T *eap)); void ex_jumps __ARGS((exarg_T *eap)); + void ex_changes __ARGS((exarg_T *eap)); void mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, long amount_after)); void copy_jumplist __ARGS((win_T *from, win_T *to)); void free_jumplist __ARGS((win_T *wp)); *** ../vim-6.2.297/src/structs.h Sun Feb 29 14:45:49 2004 --- src/structs.h Sun Feb 29 16:45:20 2004 *************** *** 404,409 **** --- 406,412 ---- int confirm; /* TRUE to invoke yes/no dialog */ # endif int keepmarks; /* TRUE when ":keepmarks" was used */ + int keepjumps; /* TRUE when ":keepjumps" was used */ int lockmarks; /* TRUE when ":lockmarks" was used */ } cmdmod_T; *************** *** 950,955 **** --- 959,973 ---- pos_T b_last_insert; /* where Insert mode was left */ pos_T b_last_change; /* position of last change: '. mark */ + #ifdef FEAT_JUMPLIST + /* + * the changelist contains old change positions + */ + pos_T b_changelist[JUMPLISTSIZE]; + int b_changelistlen; /* number of active entries */ + int b_new_change; /* set by u_savecommon() */ + #endif + /* * Character table, only used in charset.c for 'iskeyword' * 32 bytes of 8 bits: 1 bit per character 0-255. *************** *** 1511,1516 **** --- 1529,1536 ---- xfmark_T w_jumplist[JUMPLISTSIZE]; int w_jumplistlen; /* number of active entries */ int w_jumplistidx; /* current position */ + + int w_changelistidx; /* current position in b_changelist */ #endif #ifdef FEAT_SEARCH_EXTRA *** ../vim-6.2.297/src/undo.c Thu Feb 13 20:20:38 2003 --- src/undo.c Sun Feb 29 16:44:00 2004 *************** *** 209,214 **** --- 209,219 ---- */ if (curbuf->b_u_synced) { + #ifdef FEAT_JUMPLIST + /* Need to create new entry in b_changelist. */ + curbuf->b_new_change = TRUE; + #endif + /* * if we undid more than we redid, free the entry lists before and * including curbuf->b_u_curhead *************** *** 223,229 **** --- 228,237 ---- u_freelist(curbuf->b_u_oldhead); if (p_ul < 0) /* no undo at all */ + { + curbuf->b_u_synced = FALSE; return OK; + } /* * make a new header entry *************** *** 259,264 **** --- 267,275 ---- } else { + if (p_ul < 0) /* no undo at all */ + return OK; + /* * When saving a single line, and it has been saved just before, it * doesn't make sense saving it again. Saves a lot of memory when *************** *** 544,550 **** bot = uep->ue_bot; if (bot == 0) bot = curbuf->b_ml.ml_line_count + 1; ! if (top > curbuf->b_ml.ml_line_count || top >= bot || bot > curbuf->b_ml.ml_line_count + 1) { EMSG(_("E438: u_undo: line numbers wrong")); changed(); /* don't want UNCHANGED now */ --- 555,562 ---- bot = uep->ue_bot; if (bot == 0) bot = curbuf->b_ml.ml_line_count + 1; ! if (top > curbuf->b_ml.ml_line_count || top >= bot ! || bot > curbuf->b_ml.ml_line_count + 1) { EMSG(_("E438: u_undo: line numbers wrong")); changed(); /* don't want UNCHANGED now */ *************** *** 733,740 **** { if (curbuf->b_u_synced) return; /* already synced */ ! u_getbot(); /* compute ue_bot of previous u_save */ ! curbuf->b_u_curhead = NULL; } /* --- 745,757 ---- { if (curbuf->b_u_synced) return; /* already synced */ ! if (p_ul < 0) ! curbuf->b_u_synced = TRUE; /* no entries, nothing to do */ ! else ! { ! u_getbot(); /* compute ue_bot of previous u_save */ ! curbuf->b_u_curhead = NULL; ! } } /* *** ../vim-6.2.297/src/version.c Sun Feb 29 14:54:10 2004 --- src/version.c Sun Feb 29 20:28:44 2004 *************** *** 639,640 **** --- 639,642 ---- { /* Add new patch number below this line */ + /**/ + 298, /**/ -- FIRST GUARD: Ah! Now ... we're not allowed to ... SIR LAUNCELOT runs him through, grabs his spear and stabs the other guard who collapses in a heap. Hiccoughs quietly. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ Project leader for A-A-P -- http://www.A-A-P.org /// \\\ Buy at Amazon and help AIDS victims -- http://ICCF.nl/click1.html ///