On Tuesday, May 26, 2015 at 3:50:06 AM UTC+2, Justin M. Keyes wrote:
> In your implementation, you could save the './'^/jumplist/changelist
> and then restore it after the script ends. This would allow plugins to
> use marks et. al. as needed but the user can use :keepjumps! to
> prevent side effects from the plugin.
Ok, I did this, see the attached patch.
Everything seems to work great (and all tests pass etc), and I am quite pleased
with the result.
However, this is now a considerably larger patch, and I really need some
feedback on both the implementation and the interface.
Reagrding the implementation:
The way it works is that there are duplicated entries for all items which need
to be restored at the end of the execution, and more precisely:
1) for buffers: last_cursor, last_insert, last_change, changelist, changelistlen
2) for windows: pcmark, prev_pcmark, jumplist, jumplistsen, changelistidx
There are also additional entries in the structs, to keep track if we're
actively keeping a backup of those.
Then, within functions `mark_adjust`, `mark_col_adjust` and `cleanup_jumplist`,
the backup entries are updated (if the backup tag is active).
This ensures that, if the code called by keepjumps! is making changes, those
are reflected in the jumplist/changelist/etc when those are restored at the end.
I thought about alternative ways to achieve the same effect but I can't see any
simpler way to keep that guarantee (which is essential in my opinion).
This is the major point on which I'd like to have feedback. Is this ok? Did I
miss something? Will this get merged (possibly after some polishing, of course)?
Regarding the interface:
As discussed, I used :keepjumps! for the recursive version.
This has forced me to make some changes to the parser, to account for the
possibility of the trailing bang in the command.
I don't particularly like those changes.
First, they are very slightly breaking, in that before, ":keepjumps! command"
was parsed as "keepjumps" followed by "!command". I don't think this is
important (note: all other commands still parse the same).
Second, ":keepjumps" and ":keepjumps!" behave in a slightly different way in
some cases, besides the fact that :keepjumps! is recursive. Consider this
example:
:keepjumps normal ggdd``
:keepjumps! normal ggdd``
In the first case, the ' mark is not set by the gg jump, and therefore the
cursor is brought back to the *previous* location of the ' mark, if any.
In the second case, the ' mark is set by the gg jump, the cursor is brought
back to the location from where the command was invoked, and the previous '
mark is restored afterwards (if it existed at all).
I have a proposal: instead of introducing keepjumps!, just redefine :keepjumps
to act recursively.
This is slightly breaking for 2 reasons: 1) examples such as the one above, 2)
cases in which :keepjumps would have been a no-op.
I don't know what's the vim policy about these kind of slightly breaking
changes, but I think that the recursive version is what one would want most of
the time.
I also doubt that anyone would be relying on such behaviours as the ones which
would be broken by the change.
Carlo Baldassi
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -993,7 +993,7 @@
the same effect as using ":keepmarks".
*:keepj* *:keepjumps*
-:keepj[umps] {command}
+:keepj[umps][!] {command}
Moving around in {command} does not change the |''|,
|'.| and |'^| marks, the |jumplist| or the
|changelist|.
@@ -1009,9 +1009,13 @@
<
Note that ":keepjumps" must be used for every command.
When invoking a function the commands in that function
- can still change the jumplist. Also, for
- ":keepjumps exe 'command '" the "command" won't keep
- jumps. Instead use: ":exe 'keepjumps command'"
+ can still change the jumplist, unless the [!] is
+ given. When the [!] is given, keepjump makes a backup
+ of the jumplist, the changelist and the |''|, |'.|,
+ |'^| marks, and restores them when finished.
+ Also, for ":keepjumps exe 'command '" the "command"
+ won't keep jumps. Instead use: ":exe 'keepjumps
+ command'" or ":keepjumps! exe 'command '".
==============================================================================
8. Jumps *jump-motions*
diff --git a/runtime/doc/tags b/runtime/doc/tags
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -6733,6 +6733,7 @@
lcs-extends options.txt /*lcs-extends*
lcs-nbsp options.txt /*lcs-nbsp*
lcs-precedes options.txt /*lcs-precedes*
+lcs-space options.txt /*lcs-space*
lcs-tab options.txt /*lcs-tab*
lcs-trail options.txt /*lcs-trail*
left-right-motions motion.txt /*left-right-motions*
diff --git a/src/eval.c b/src/eval.c
--- a/src/eval.c
+++ b/src/eval.c
@@ -22464,7 +22464,7 @@
;
/* Check for "endfunction". */
- if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0)
+ if (checkforcmd(&p, "endfunction", 4, FALSE) && nesting-- == 0)
{
if (line_arg == NULL)
vim_free(theline);
@@ -22482,7 +22482,7 @@
indent += 2;
/* Check for defining a function inside this function. */
- if (checkforcmd(&p, "function", 2))
+ if (checkforcmd(&p, "function", 2, FALSE))
{
if (*p == '!')
p = skipwhite(p + 1);
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -679,7 +679,7 @@
NEEDARG|EXTRA|NOTRLCOM,
ADDR_LINES),
EX(CMD_keepjumps, "keepjumps", ex_wrongmodifier,
- NEEDARG|EXTRA|NOTRLCOM,
+ NEEDARG|BANG|EXTRA|NOTRLCOM,
ADDR_LINES),
EX(CMD_keeppatterns, "keeppatterns", ex_wrongmodifier,
NEEDARG|EXTRA|NOTRLCOM,
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1828,6 +1828,7 @@
int did_sandbox = FALSE;
#endif
cmdmod_T save_cmdmod;
+ int cmdcheck_ret;
int ni; /* set when Not
Implemented */
char_u *cmd;
@@ -1858,6 +1859,9 @@
save_cmdmod = cmdmod;
vim_memset(&cmdmod, 0, sizeof(cmdmod));
+ /* keepjumps! is recursive */
+ cmdmod.keepjumps_bang = save_cmdmod.keepjumps_bang;
+
/* "#!anything" is handled like a comment. */
if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!')
goto doend;
@@ -1902,83 +1906,93 @@
switch (*p)
{
/* When adding an entry, also modify cmd_exists(). */
- case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3))
+ case 'a': if (!checkforcmd(&ea.cmd, "aboveleft", 3, FALSE))
break;
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_ABOVE;
#endif
continue;
- case 'b': if (checkforcmd(&ea.cmd, "belowright", 3))
+ case 'b': if (checkforcmd(&ea.cmd, "belowright", 3, FALSE))
{
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_BELOW;
#endif
continue;
}
- if (checkforcmd(&ea.cmd, "browse", 3))
+ if (checkforcmd(&ea.cmd, "browse", 3, FALSE))
{
#ifdef FEAT_BROWSE_CMD
cmdmod.browse = TRUE;
#endif
continue;
}
- if (!checkforcmd(&ea.cmd, "botright", 2))
+ if (!checkforcmd(&ea.cmd, "botright", 2, FALSE))
break;
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_BOT;
#endif
continue;
- case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4))
+ case 'c': if (!checkforcmd(&ea.cmd, "confirm", 4, FALSE))
break;
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
cmdmod.confirm = TRUE;
#endif
continue;
- case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3))
+ case 'k': if (checkforcmd(&ea.cmd, "keepmarks", 3, FALSE))
{
cmdmod.keepmarks = TRUE;
continue;
}
- if (checkforcmd(&ea.cmd, "keepalt", 5))
+ if (checkforcmd(&ea.cmd, "keepalt", 5, FALSE))
{
cmdmod.keepalt = TRUE;
continue;
}
- if (checkforcmd(&ea.cmd, "keeppatterns", 5))
+ if (checkforcmd(&ea.cmd, "keeppatterns", 5, FALSE))
{
cmdmod.keeppatterns = TRUE;
continue;
}
- if (!checkforcmd(&ea.cmd, "keepjumps", 5))
- break;
- cmdmod.keepjumps = TRUE;
- continue;
+ cmdcheck_ret = checkforcmd(&ea.cmd, "keepjumps", 5,
TRUE);
+ if (cmdcheck_ret == TRUER)
+ {
+ if (!cmdmod.keepjumps_bang)
+ keepjumps_do_backup();
+ cmdmod.keepjumps_bang = TRUE;
+ continue;
+ }
+ else if (cmdcheck_ret == TRUE)
+ {
+ cmdmod.keepjumps = TRUE;
+ continue;
+ }
+ break;
/* ":hide" and ":hide | cmd" are not modifiers */
- case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3)
+ case 'h': if (p != ea.cmd || !checkforcmd(&p, "hide", 3, FALSE)
|| *p == NUL || ends_excmd(*p))
break;
ea.cmd = p;
cmdmod.hide = TRUE;
continue;
- case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3))
+ case 'l': if (checkforcmd(&ea.cmd, "lockmarks", 3, FALSE))
{
cmdmod.lockmarks = TRUE;
continue;
}
- if (!checkforcmd(&ea.cmd, "leftabove", 5))
+ if (!checkforcmd(&ea.cmd, "leftabove", 5, FALSE))
break;
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_ABOVE;
#endif
continue;
- case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3))
+ case 'n': if (checkforcmd(&ea.cmd, "noautocmd", 3, FALSE))
{
#ifdef FEAT_AUTOCMD
if (cmdmod.save_ei == NULL)
@@ -1992,19 +2006,19 @@
#endif
continue;
}
- if (!checkforcmd(&ea.cmd, "noswapfile", 6))
+ if (!checkforcmd(&ea.cmd, "noswapfile", 6, FALSE))
break;
cmdmod.noswapfile = TRUE;
continue;
- case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6))
+ case 'r': if (!checkforcmd(&ea.cmd, "rightbelow", 6, FALSE))
break;
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_BELOW;
#endif
continue;
- case 's': if (checkforcmd(&ea.cmd, "sandbox", 3))
+ case 's': if (checkforcmd(&ea.cmd, "sandbox", 3, FALSE))
{
#ifdef HAVE_SANDBOX
if (!did_sandbox)
@@ -2013,7 +2027,7 @@
#endif
continue;
}
- if (!checkforcmd(&ea.cmd, "silent", 3))
+ if (!checkforcmd(&ea.cmd, "silent", 3, FALSE))
break;
if (save_msg_silent == -1)
save_msg_silent = msg_silent;
@@ -2027,7 +2041,7 @@
}
continue;
- case 't': if (checkforcmd(&p, "tab", 3))
+ case 't': if (checkforcmd(&p, "tab", 3, FALSE))
{
#ifdef FEAT_WINDOWS
if (vim_isdigit(*ea.cmd))
@@ -2038,28 +2052,28 @@
#endif
continue;
}
- if (!checkforcmd(&ea.cmd, "topleft", 2))
+ if (!checkforcmd(&ea.cmd, "topleft", 2, FALSE))
break;
#ifdef FEAT_WINDOWS
cmdmod.split |= WSP_TOP;
#endif
continue;
- case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3))
+ case 'u': if (!checkforcmd(&ea.cmd, "unsilent", 3, FALSE))
break;
if (save_msg_silent == -1)
save_msg_silent = msg_silent;
msg_silent = 0;
continue;
- case 'v': if (checkforcmd(&ea.cmd, "vertical", 4))
+ case 'v': if (checkforcmd(&ea.cmd, "vertical", 4, FALSE))
{
#ifdef FEAT_VERTSPLIT
cmdmod.split |= WSP_VERT;
#endif
continue;
}
- if (!checkforcmd(&p, "verbose", 4))
+ if (!checkforcmd(&p, "verbose", 4, FALSE))
break;
if (verbose_save < 0)
verbose_save = p_verbose;
@@ -2998,6 +3012,9 @@
}
#endif
+ if (cmdmod.keepjumps_bang && !save_cmdmod.keepjumps_bang)
+ keepjumps_do_restore();
+
cmdmod = save_cmdmod;
if (save_msg_silent != -1)
@@ -3039,23 +3056,28 @@
/*
* Check for an Ex command with optional tail.
- * If there is a match advance "pp" to the argument and return TRUE.
+ * If there is a match advance "pp" to the argument and return TRUE
+ * (return TRUER if the command is followed by a '!').
*/
int
-checkforcmd(pp, cmd, len)
+checkforcmd(pp, cmd, len, parse_bang)
char_u **pp; /* start of command */
char *cmd; /* name of command */
int len; /* required length */
-{
- int i;
+ int parse_bang; /* whether ! is part of the command */
+{
+ int i, bang;
for (i = 0; cmd[i] != NUL; ++i)
if (((char_u *)cmd)[i] != (*pp)[i])
break;
if (i >= len && !isalpha((*pp)[i]))
{
+ bang = parse_bang && ((*pp)[i] == '!');
+ if (bang)
+ ++i;
*pp = skipwhite(*pp + i);
- return TRUE;
+ return bang ? TRUER : TRUE;
}
return FALSE;
}
@@ -3328,29 +3350,30 @@
char *name;
int minlen;
int has_count; /* :123verbose :3tab */
+ int has_bang;
} cmdmods[] = {
- {"aboveleft", 3, FALSE},
- {"belowright", 3, FALSE},
- {"botright", 2, FALSE},
- {"browse", 3, FALSE},
- {"confirm", 4, FALSE},
- {"hide", 3, FALSE},
- {"keepalt", 5, FALSE},
- {"keepjumps", 5, FALSE},
- {"keepmarks", 3, FALSE},
- {"keeppatterns", 5, FALSE},
- {"leftabove", 5, FALSE},
- {"lockmarks", 3, FALSE},
- {"noautocmd", 3, FALSE},
- {"noswapfile", 3, FALSE},
- {"rightbelow", 6, FALSE},
- {"sandbox", 3, FALSE},
- {"silent", 3, FALSE},
- {"tab", 3, TRUE},
- {"topleft", 2, FALSE},
- {"unsilent", 3, FALSE},
- {"verbose", 4, TRUE},
- {"vertical", 4, FALSE},
+ {"aboveleft", 3, FALSE, FALSE},
+ {"belowright", 3, FALSE, FALSE},
+ {"botright", 2, FALSE, FALSE},
+ {"browse", 3, FALSE, FALSE},
+ {"confirm", 4, FALSE, FALSE},
+ {"hide", 3, FALSE, FALSE},
+ {"keepalt", 5, FALSE, FALSE},
+ {"keepjumps", 5, FALSE, TRUE},
+ {"keepmarks", 3, FALSE, FALSE},
+ {"keeppatterns", 5, FALSE, FALSE},
+ {"leftabove", 5, FALSE, FALSE},
+ {"lockmarks", 3, FALSE, FALSE},
+ {"noautocmd", 3, FALSE, FALSE},
+ {"noswapfile", 3, FALSE, FALSE},
+ {"rightbelow", 6, FALSE, FALSE},
+ {"sandbox", 3, FALSE, FALSE},
+ {"silent", 3, FALSE, FALSE},
+ {"tab", 3, TRUE, FALSE},
+ {"topleft", 2, FALSE, FALSE},
+ {"unsilent", 3, FALSE, FALSE},
+ {"verbose", 4, TRUE, FALSE},
+ {"vertical", 4, FALSE, FALSE},
};
/*
@@ -3361,7 +3384,7 @@
modifier_len(cmd)
char_u *cmd;
{
- int i, j;
+ int i, j, len;
char_u *p = cmd;
if (VIM_ISDIGIT(*cmd))
@@ -3371,7 +3394,10 @@
for (j = 0; p[j] != NUL; ++j)
if (p[j] != cmdmods[i].name[j])
break;
- if (!ASCII_ISALPHA(p[j]) && j >= cmdmods[i].minlen
+ len = j;
+ if (cmdmods[i].has_bang && p[j] == '!')
+ ++j;
+ if (!ASCII_ISALPHA(p[j]) && len >= cmdmods[i].minlen
&& (p == cmd || cmdmods[i].has_count))
return j + (int)(p - cmd);
}
@@ -3391,6 +3417,7 @@
int full = FALSE;
int i;
int j;
+ int len;
char_u *p;
/* Check command modifiers. */
@@ -3399,7 +3426,10 @@
for (j = 0; name[j] != NUL; ++j)
if (name[j] != cmdmods[i].name[j])
break;
- if (name[j] == NUL && j >= cmdmods[i].minlen)
+ len = j;
+ if (cmdmods[i].has_bang && name[j] == '!')
+ ++j;
+ if (name[j] == NUL && len >= cmdmods[i].minlen)
return (cmdmods[i].name[j] == NUL ? 2 : 1);
}
@@ -5280,7 +5310,7 @@
}
else
eap->force_bin = FORCE_BIN;
- if (!checkforcmd(&arg, "binary", 3))
+ if (!checkforcmd(&arg, "binary", 3, FALSE))
return FAIL;
eap->arg = skipwhite(arg);
return OK;
diff --git a/src/mark.c b/src/mark.c
--- a/src/mark.c
+++ b/src/mark.c
@@ -1068,11 +1068,24 @@
if (!equalpos(curbuf->b_last_cursor, initpos))
one_adjust(&(curbuf->b_last_cursor.lnum));
+ /* same as the above, for the keepjumps! backups */
+ if (cmdmod.keepjumps_bang && curbuf->b_bk_state)
+ {
+ one_adjust(&(curbuf->b_bk_last_insert.lnum));
+ one_adjust(&(curbuf->b_bk_last_change.lnum));
+ if (!equalpos(curbuf->b_bk_last_cursor, initpos))
+ one_adjust(&(curbuf->b_bk_last_cursor.lnum));
+ }
#ifdef FEAT_JUMPLIST
/* list of change positions */
for (i = 0; i < curbuf->b_changelistlen; ++i)
one_adjust_nodel(&(curbuf->b_changelist[i].lnum));
+
+ /* same as the above, for the keepjumps! backups */
+ if (cmdmod.keepjumps_bang && curbuf->b_bk_state)
+ for (i = 0; i < curbuf->b_bk_changelistlen; ++i)
+ one_adjust_nodel(&(curbuf->b_bk_changelist[i].lnum));
#endif
/* Visual area */
@@ -1098,6 +1111,13 @@
/* previous pcmark */
one_adjust(&(curwin->w_prev_pcmark.lnum));
+ /* same as the above, for the keepjumps! backups */
+ if (cmdmod.keepjumps_bang && curwin->w_bk_state)
+ {
+ one_adjust(&(curwin->w_bk_pcmark.lnum));
+ one_adjust(&(curwin->w_bk_prev_pcmark.lnum));
+ }
+
/* saved cursor for formatting */
if (saved_cursor.lnum != 0)
one_adjust_nodel(&(saved_cursor.lnum));
@@ -1109,11 +1129,19 @@
{
#ifdef FEAT_JUMPLIST
if (!cmdmod.lockmarks)
+ {
/* Marks in the jumplist. When deleting lines, this may create
* duplicate marks in the jumplist, they will be removed later. */
for (i = 0; i < win->w_jumplistlen; ++i)
if (win->w_jumplist[i].fmark.fnum == fnum)
one_adjust_nodel(&(win->w_jumplist[i].fmark.mark.lnum));
+
+ if (cmdmod.keepjumps_bang && win->w_bk_state)
+ for (i = 0; i < win->w_bk_jumplistlen; ++i)
+ if (win->w_bk_jumplist[i].fmark.fnum == fnum)
+ one_adjust_nodel(
+ &(win->w_bk_jumplist[i].fmark.mark.lnum));
+ }
#endif
if (win->w_buffer == curbuf)
@@ -1256,6 +1284,13 @@
/* previous pcmark */
col_adjust(&(curwin->w_prev_pcmark));
+ /* same as the above, for the keepjumps! backups */
+ if (cmdmod.keepjumps_bang && curwin->w_bk_state)
+ {
+ col_adjust(&(curwin->w_bk_pcmark));
+ col_adjust(&(curwin->w_bk_prev_pcmark));
+ }
+
/* saved cursor for formatting */
col_adjust(&saved_cursor);
@@ -1269,6 +1304,11 @@
for (i = 0; i < win->w_jumplistlen; ++i)
if (win->w_jumplist[i].fmark.fnum == fnum)
col_adjust(&(win->w_jumplist[i].fmark.mark));
+
+ if (cmdmod.keepjumps_bang && win->w_bk_state)
+ for (i = 0; i < win->w_bk_jumplistlen; ++i)
+ if (win->w_bk_jumplist[i].fmark.fnum == fnum)
+ col_adjust(&(win->w_bk_jumplist[i].fmark.mark));
#endif
if (win->w_buffer == curbuf)
@@ -1290,32 +1330,88 @@
* When deleting lines, this may create duplicate marks in the
* jumplist. They will be removed here for the current window.
*/
+
+ void
+cleanup_jumplist_(jumplist, lenp, idxp)
+ xfmark_T *jumplist;
+ int *lenp;
+ int *idxp;
+{
+ int len, idx;
+ int i;
+ int from, to;
+
+ len = *lenp;
+ idx = *idxp;
+
+ to = 0;
+ for (from = 0; from < len; ++from)
+ {
+ if (idx == from)
+ idx = to;
+ for (i = from + 1; i < len; ++i)
+ if (jumplist[i].fmark.fnum == jumplist[from].fmark.fnum
+ && jumplist[from].fmark.fnum != 0
+ && jumplist[i].fmark.mark.lnum
+ == jumplist[from].fmark.mark.lnum)
+ break;
+ if (i >= len) /* no duplicate */
+ jumplist[to++] = jumplist[from];
+ else
+ vim_free(jumplist[from].fname);
+ }
+ if (idx == len)
+ idx = to;
+ len = to;
+
+ *lenp = len;
+ *idxp = idx;
+}
+
static void
cleanup_jumplist()
{
- int i;
- int from, to;
+ cleanup_jumplist_(curwin->w_jumplist, &curwin->w_jumplistlen,
+ &curwin->w_jumplistidx);
+ if (cmdmod.keepjumps_bang || curwin->w_bk_state)
+ cleanup_jumplist_(curwin->w_bk_jumplist, &curwin->w_bk_jumplistlen,
+ &curwin->w_bk_jumplistidx);
+}
- to = 0;
- for (from = 0; from < curwin->w_jumplistlen; ++from)
+ void
+copy_jumplist(dest, src, len)
+ xfmark_T *src;
+ xfmark_T *dest;
+ int len;
+{
+ int i;
+
+ for (i = 0; i < len; ++i)
{
- if (curwin->w_jumplistidx == from)
- curwin->w_jumplistidx = to;
- for (i = from + 1; i < curwin->w_jumplistlen; ++i)
- if (curwin->w_jumplist[i].fmark.fnum
- == curwin->w_jumplist[from].fmark.fnum
- && curwin->w_jumplist[from].fmark.fnum != 0
- && curwin->w_jumplist[i].fmark.mark.lnum
- == curwin->w_jumplist[from].fmark.mark.lnum)
- break;
- if (i >= curwin->w_jumplistlen) /* no duplicate */
- curwin->w_jumplist[to++] = curwin->w_jumplist[from];
- else
- vim_free(curwin->w_jumplist[from].fname);
+ dest[i] = src[i];
+ if (src[i].fname != NULL)
+ dest[i].fname = vim_strsave(src[i].fname);
}
- if (curwin->w_jumplistidx == curwin->w_jumplistlen)
- curwin->w_jumplistidx = to;
- curwin->w_jumplistlen = to;
+}
+
+ void
+copy_changelist(dest, src, size)
+ pos_T* dest;
+ pos_T* src;
+ int size;
+{
+ mch_memmove(dest, src, size * sizeof(pos_T));
+}
+
+ void
+free_jumplist(jumplist, len)
+ xfmark_T *jumplist;
+ int len;
+{
+ int i;
+
+ for (i = 0; i < len; ++i)
+ vim_free(jumplist[i].fname);
}
# if defined(FEAT_WINDOWS) || defined(PROTO)
@@ -1323,33 +1419,35 @@
* Copy the jumplist from window "from" to window "to".
*/
void
-copy_jumplist(from, to)
+copy_w_jumplist(from, to)
win_T *from;
win_T *to;
{
int i;
- for (i = 0; i < from->w_jumplistlen; ++i)
- {
- to->w_jumplist[i] = from->w_jumplist[i];
- if (from->w_jumplist[i].fname != NULL)
- to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
- }
+ copy_jumplist(to->w_jumplist, from->w_jumplist, from->w_jumplistlen);
to->w_jumplistlen = from->w_jumplistlen;
to->w_jumplistidx = from->w_jumplistidx;
+
+ if (from->w_bk_state)
+ {
+ copy_jumplist(to->w_bk_jumplist, from->w_bk_jumplist,
+ from->w_bk_jumplistlen);
+ to->w_bk_jumplistlen = from->w_bk_jumplistlen;
+ to->w_bk_jumplistidx = from->w_bk_jumplistidx;
+ }
}
/*
* Free items in the jumplist of window "wp".
*/
void
-free_jumplist(wp)
+free_w_jumplist(wp)
win_T *wp;
{
- int i;
-
- for (i = 0; i < wp->w_jumplistlen; ++i)
- vim_free(wp->w_jumplist[i].fname);
+ free_jumplist(wp->w_jumplist, wp->w_jumplistlen);
+ if (wp->w_bk_state)
+ free_jumplist(wp->w_bk_jumplist, wp->w_bk_jumplistlen);
}
# endif
#endif /* FEAT_JUMPLIST */
@@ -1814,3 +1912,81 @@
vim_free(name_buf);
}
#endif /* FEAT_VIMINFO */
+
+ void
+keepjumps_do_backup()
+{
+ win_T *wp;
+ tabpage_T *tp;
+ buf_T *bp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ wp->w_buffer->b_bk_state = FALSE;
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+#ifdef FEAT_JUMPLIST
+ copy_jumplist(wp->w_bk_jumplist,
+ wp->w_jumplist, wp->w_jumplistlen);
+ wp->w_bk_jumplistlen = wp->w_jumplistlen;
+ wp->w_bk_jumplistidx = wp->w_jumplistidx;
+ wp->w_bk_changelistidx = wp->w_changelistidx;
+#endif
+ wp->w_bk_pcmark = wp->w_pcmark;
+ wp->w_bk_prev_pcmark = wp->w_prev_pcmark;
+ wp->w_bk_state = TRUE;
+
+ bp = wp->w_buffer;
+ if (bp->b_bk_state == TRUE)
+ continue;
+
+ bp->b_bk_last_cursor = bp->b_last_cursor;
+ bp->b_bk_last_insert = bp->b_last_insert;
+ bp->b_bk_last_change = bp->b_last_change;
+#ifdef FEAT_JUMPLIST
+ copy_changelist(bp->b_bk_changelist,
+ bp->b_changelist, bp->b_changelistlen);
+ bp->b_bk_changelistlen = bp->b_changelistlen;
+#endif
+ bp->b_bk_state = TRUE;
+ }
+}
+
+ void
+keepjumps_do_restore()
+{
+ win_T *wp;
+ tabpage_T *tp;
+ buf_T *bp;
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ {
+#ifdef FEAT_JUMPLIST
+ free_jumplist(wp->w_jumplist, wp->w_jumplistlen);
+ copy_jumplist(wp->w_jumplist,
+ wp->w_bk_jumplist, wp->w_bk_jumplistlen);
+ wp->w_jumplistlen = wp->w_bk_jumplistlen;
+ wp->w_jumplistidx = wp->w_bk_jumplistidx;
+ wp->w_changelistidx = wp->w_bk_changelistidx;
+ free_jumplist(wp->w_bk_jumplist, wp->w_bk_jumplistlen);
+ wp->w_bk_jumplistlen = 0;
+#endif
+ wp->w_pcmark = wp->w_bk_pcmark;
+ wp->w_prev_pcmark = wp->w_bk_prev_pcmark;
+ wp->w_bk_state = FALSE;
+
+ bp = wp->w_buffer;
+ if (!bp->b_bk_state)
+ continue;
+
+ bp->b_last_cursor = bp->b_bk_last_cursor;
+ bp->b_last_insert = bp->b_bk_last_insert;
+ bp->b_last_change = bp->b_bk_last_change;
+#ifdef FEAT_JUMPLIST
+ copy_changelist(bp->b_changelist,
+ bp->b_bk_changelist, bp->b_bk_changelistlen);
+ bp->b_changelistlen = bp->b_bk_changelistlen;
+ bp->b_bk_changelistlen = 0;
+#endif
+ bp->b_bk_state = FALSE;
+ }
+}
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -4,7 +4,7 @@
int do_cmdline __ARGS((char_u *cmdline, char_u *(*fgetline)(int, void *, int),
void *cookie, int flags));
int getline_equal __ARGS((char_u *(*fgetline)(int, void *, int), void *cookie,
char_u *(*func)(int, void *, int)));
void *getline_cookie __ARGS((char_u *(*fgetline)(int, void *, int), void
*cookie));
-int checkforcmd __ARGS((char_u **pp, char *cmd, int len));
+int checkforcmd __ARGS((char_u **pp, char *cmd, int len, int parse_bang));
int modifier_len __ARGS((char_u *cmd));
int cmd_exists __ARGS((char_u *name));
char_u *set_one_cmd_context __ARGS((expand_T *xp, char_u *buff));
diff --git a/src/proto/mark.pro b/src/proto/mark.pro
--- a/src/proto/mark.pro
+++ b/src/proto/mark.pro
@@ -19,8 +19,11 @@
void ex_changes __ARGS((exarg_T *eap));
void mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, long
amount_after));
void mark_col_adjust __ARGS((linenr_T lnum, colnr_T mincol, long lnum_amount,
long col_amount));
-void copy_jumplist __ARGS((win_T *from, win_T *to));
-void free_jumplist __ARGS((win_T *wp));
+void copy_jumplist __ARGS((xfmark_T *dest, xfmark_T *src, int len));
+void copy_changelist __ARGS((pos_T *dest, pos_T *src, int len));
+void free_jumplist __ARGS((xfmark_T *jumplist, int len));
+void copy_w_jumplist __ARGS((win_T *from, win_T *to));
+void free_w_jumplist __ARGS((win_T *wp));
void set_last_cursor __ARGS((win_T *win));
void free_all_marks __ARGS((void));
int read_viminfo_filemark __ARGS((vir_T *virp, int force));
@@ -28,4 +31,6 @@
int removable __ARGS((char_u *name));
int write_viminfo_marks __ARGS((FILE *fp_out));
void copy_viminfo_marks __ARGS((vir_T *virp, FILE *fp_out, int count, int eof,
int flags));
+void keepjumps_do_backup __ARGS(());
+void keepjumps_do_restore __ARGS(());
/* vim: set ft=c : */
diff --git a/src/structs.h b/src/structs.h
--- a/src/structs.h
+++ b/src/structs.h
@@ -549,6 +549,7 @@
int keepalt; /* TRUE when ":keepalt" was
used */
int keepmarks; /* TRUE when ":keepmarks" was
used */
int keepjumps; /* TRUE when ":keepjumps" was
used */
+ int keepjumps_bang; /* TRUE when ":keepjumps!" was
used */
int lockmarks; /* TRUE when ":lockmarks" was
used */
int keeppatterns; /* TRUE when ":keeppatterns"
was used */
int noswapfile; /* TRUE when ":noswapfile" was
used */
@@ -1456,6 +1457,14 @@
pos_T b_last_insert; /* where Insert mode was left */
pos_T b_last_change; /* position of last change: '. mark */
+ /*
+ * Backups used during keepjumps!
+ */
+ int b_bk_state; /* TRUE while backups are boing kept */
+ pos_T b_bk_last_cursor;
+ pos_T b_bk_last_insert;
+ pos_T b_bk_last_change;
+
#ifdef FEAT_JUMPLIST
/*
* the changelist contains old change positions
@@ -1463,6 +1472,12 @@
pos_T b_changelist[JUMPLISTSIZE];
int b_changelistlen; /* number of active entries */
int b_new_change; /* set by u_savecommon() */
+
+ /*
+ * Backups used during keepjumps!
+ */
+ pos_T b_bk_changelist[JUMPLISTSIZE];
+ int b_bk_changelistlen;
#endif
/*
@@ -2271,6 +2286,13 @@
pos_T w_pcmark; /* previous context mark */
pos_T w_prev_pcmark; /* previous w_pcmark */
+ /*
+ * Backups used during keepjumps!
+ */
+ int w_bk_state; /* TRUE while backups are boing kept */
+ pos_T w_bk_pcmark;
+ pos_T w_bk_prev_pcmark;
+
#ifdef FEAT_JUMPLIST
/*
* the jumplist contains old cursor positions
@@ -2280,6 +2302,14 @@
int w_jumplistidx; /* current position */
int w_changelistidx; /* current position in
b_changelist */
+
+ /*
+ * Backups used during keepjumps!
+ */
+ xfmark_T w_bk_jumplist[JUMPLISTSIZE];
+ int w_bk_jumplistlen;
+ int w_bk_jumplistidx;
+ int w_bk_changelistidx;
#endif
#ifdef FEAT_SEARCH_EXTRA
diff --git a/src/vim.h b/src/vim.h
--- a/src/vim.h
+++ b/src/vim.h
@@ -1411,6 +1411,8 @@
#endif
#define MAYBE 2 /* sometimes used for a variant on TRUE */
+#define TRUER 3 /* sometimes used for a variant on TRUE */
+
#ifndef UINT32_T
typedef UINT32_TYPEDEF UINT32_T;
diff --git a/src/window.c b/src/window.c
--- a/src/window.c
+++ b/src/window.c
@@ -1363,7 +1363,7 @@
newp->w_fraction = oldp->w_fraction;
newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
#ifdef FEAT_JUMPLIST
- copy_jumplist(oldp, newp);
+ copy_w_jumplist(oldp, newp);
#endif
#ifdef FEAT_QUICKFIX
if (flags & WSP_NEWLOC)
@@ -4765,7 +4765,7 @@
#endif
#ifdef FEAT_JUMPLIST
- free_jumplist(wp);
+ free_w_jumplist(wp);
#endif
#ifdef FEAT_QUICKFIX