trunc( {expr} Float truncate Float {expr}
type( {name}) Number type of variable {name}
undofile( {name}) String undo file name for {name}
+undotree() List undo file tree
values( {dict}) List values in {dict}
virtcol( {expr}) Number screen column of cursor or mark
visualmode( [expr]) String last visual mode used
choice this is 1.
Note: confirm() is only supported when compiled with dialog
support, see |+dialog_con| and |+dialog_gui|.
+
{msg} is displayed in a |dialog| with {choices} as the
alternatives. When {choices} is missing or empty, "&OK" is
used (and translated).
{msg} is a String, use '\n' to include a newline. Only on
some systems the string is wrapped when it doesn't fit.
+
{choices} is a String, with the individual choices separated
by '\n', e.g. >
confirm("Save changes?", "&Yes\n&No\n&Cancel")
confirm("file has been modified", "&Save\nSave &All")
< For the console, the first letter of each choice is used as
the default shortcut key.
+
The optional {default} argument is the number of the choice
that is made if the user hits <CR>. Use 1 to make the first
choice the default one. Use 0 to not set a default. If
{default} is omitted, 1 is used.
- The optional {type} argument gives the type of dialog. This
- is only used for the icon of the Win32 GUI. It can be one of
- these values: "Error", "Question", "Info", "Warning" or
- "Generic". Only the first character is relevant. When {type}
- is omitted, "Generic" is used.
+
+ The optional {type} argument gives the type of dialog. This
+ is only used for the icon of the GTK, Mac, Motif and Win32
+ GUI. It can be one of these values: "Error", "Question",
+ "Info", "Warning" or "Generic". Only the first character is
+ relevant. When {type} is omitted, "Generic" is used.
+
If the user aborts the dialog by pressing <Esc>, CTRL-C,
or another valid interrupt key, confirm() returns 0.
When compiled without the +persistent_undo option this always
returns an empty string.
+undotree() *undotree()*
+ Return the current state of the undo tree in a dictionary with
+ the following items:
+ "seq_last" The highest undo sequence number used.
+ "seq_cur" The sequence number of the current position in
+ the undo tree. This differs from "seq_last"
+ when some changes were undone.
+ "time_cur" Time last used for |:earlier| and related
+ commands. Use |strftime()| to convert to
+ something readable.
+ "save_last" Number of the last file write. Zero when no
+ write yet.
+ "synced" Non-zero when the last undo block was synced.
+ This happens when waiting from input from the
+ user. See |undo-blocks|.
+ "entries" A list of dictionaries with information about
+ undo blocks.
+
+ The first item in the "entries" list is the oldest undo item.
+ Each List item is a Dictionary with these items:
+ "seq" Undo sequence number. Same as what appears in
+ |:undolist|.
+ "time" Timestamp when the change happened. Use
+ |strftime()| to convert to something readable.
+ "newhead" Only appears in the item that is the last one
+ that was added. This marks the last change
+ and where further changes will be added.
+ "curhead" Only appears in the item that is the last one
+ that was undone. This marks the current
+ position in the undo tree, the block that will
+ be used by a redo command. When nothing was
+ undone after the last change this item will
+ not appear anywhere.
+ "save" Only appears on the last block before a file
+ write. The number is the write count. The
+ first write has number 1, the last one the
+ "save_last" mentioned above.
+ "alt" Alternate entry. This is again a List of undo
+ blocks. Each item may again have an "alt"
+ item.
+
values({dict}) *values()*
Return a |List| with all the values of {dict}. The |List| is
in arbitrary order.
undo.txt undo.txt /*undo.txt*
undo_ftplugin usr_41.txt /*undo_ftplugin*
undofile() eval.txt /*undofile()*
+undotree() eval.txt /*undotree()*
unicode mbyte.txt /*unicode*
unix os_unix.txt /*unix*
unlisted-buffer windows.txt /*unlisted-buffer*
Use register_shell_extension()?
Patch from Geoffrey Reilly, 2010 Jun 22
- Patch for conceal feature from Vince, 2010 June 16.
- Needs some more testing.
-- undofile: keep markers where the file was written/read, so that it's easy to
- go back to a saved version of the file: ":earlier 1f" (f for file)?
+ Needs some more testing, better patch is coming.
+- implement ":earlier 1f" (f for file)?
Also add ":earlier 1d" (d for day).
Something like changenr() to see the "file saved" marker?
- Show "file saved" marker in :undolist
-- Function to get undo tree: undotree(). List of lists. Each entry is a
- dictionary: {'nr': 2, 'time': 1234, 'saved': 1}
+- in August remove UF_VERSION_CRYPT_PREV and UF_VERSION_PREV.
Patches to include:
- Patch for Lisp support with ECL (Mikael Jansson, 2008 Oct 25)
- Gvimext patch to support wide file names. (Szabolcs Horvat 2008 Sep 10)
The "changes" column is the number of changes to this
leaf from the root of the tree.
The "time" column is the time this change was made.
+ For more details use the |undotree()| function.
*g-*
g- Go to older text state. With a count repeat that many
(int)(IOSIZE - (p - buffer)), TRUE);
}
- len = STRLEN(buffer);
- vim_snprintf((char *)buffer + len, IOSIZE - len,
- "\"%s%s%s%s%s%s",
+ vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
curbufIsChanged() ? (shortmess(SHM_MOD)
? " [+]" : _(" [Modified]")) : " ",
(curbuf->b_flags & BF_NOTEDITED)
else
n = (int)(((long)curwin->w_cursor.lnum * 100L) /
(long)curbuf->b_ml.ml_line_count);
- len = STRLEN(buffer);
if (curbuf->b_ml.ml_flags & ML_EMPTY)
{
- vim_snprintf((char *)buffer + len, IOSIZE - len, "%s", _(no_lines_msg));
+ vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
}
#ifdef FEAT_CMDL_INFO
else if (p_ru)
{
/* Current line and column are already on the screen -- webb */
if (curbuf->b_ml.ml_line_count == 1)
- vim_snprintf((char *)buffer + len, IOSIZE - len,
- _("1 line --%d%%--"), n);
+ vim_snprintf_add((char *)buffer, IOSIZE, _("1 line --%d%%--"), n);
else
- vim_snprintf((char *)buffer + len, IOSIZE - len,
- _("%ld lines --%d%%--"),
+ vim_snprintf_add((char *)buffer, IOSIZE, _("%ld lines --%d%%--"),
(long)curbuf->b_ml.ml_line_count, n);
}
#endif
else
{
- vim_snprintf((char *)buffer + len, IOSIZE - len,
+ vim_snprintf_add((char *)buffer, IOSIZE,
_("line %ld of %ld --%d%%-- col "),
(long)curwin->w_cursor.lnum,
(long)curbuf->b_ml.ml_line_count,
#endif
char_u *line;
int max_buffers;
- size_t len;
if (find_viminfo_parameter('%') == NULL)
return;
break;
putc('%', fp);
home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
- len = STRLEN(line);
- vim_snprintf((char *)line + len, len - LINE_BUF_LEN, "\t%ld\t%d",
+ vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d",
(long)buf->b_last_cursor.lnum,
buf->b_last_cursor.col);
viminfo_writestring(fp, line);
static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID));
static void set_ref_in_list __ARGS((list_T *l, int copyID));
static void set_ref_in_item __ARGS((typval_T *tv, int copyID));
+static int rettv_dict_alloc __ARGS((typval_T *rettv));
static void dict_unref __ARGS((dict_T *d));
static void dict_free __ARGS((dict_T *d, int recurse));
static dictitem_T *dictitem_copy __ARGS((dictitem_T *org));
#endif
static void f_type __ARGS((typval_T *argvars, typval_T *rettv));
static void f_undofile __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_undotree __ARGS((typval_T *argvars, typval_T *rettv));
static void f_values __ARGS((typval_T *argvars, typval_T *rettv));
static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv));
static void f_visualmode __ARGS((typval_T *argvars, typval_T *rettv));
return d;
}
+/*
+ * Allocate an empty dict for a return value.
+ * Returns OK or FAIL.
+ */
+ static int
+rettv_dict_alloc(rettv)
+ typval_T *rettv;
+{
+ dict_T *d = dict_alloc();
+
+ if (d == NULL)
+ return FAIL;
+
+ rettv->vval.v_dict = d;
+ rettv->v_type = VAR_DICT;
+ ++d->dv_refcount;
+ return OK;
+}
+
+
/*
* Unreference a Dictionary: decrement the reference count and free it when it
* becomes zero.
/*
* Add item "item" to Dictionary "d".
- * Returns FAIL when out of memory and when key already existed.
+ * Returns FAIL when out of memory and when key already exists.
*/
int
dict_add(d, item)
return OK;
}
+/*
+ * Add a list entry to dictionary "d".
+ * Returns FAIL when out of memory and when key already exists.
+ */
+ int
+dict_add_list(d, key, list)
+ dict_T *d;
+ char *key;
+ list_T *list;
+{
+ dictitem_T *item;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ item->di_tv.v_lock = 0;
+ item->di_tv.v_type = VAR_LIST;
+ item->di_tv.vval.v_list = list;
+ if (dict_add(d, item) == FAIL)
+ {
+ dictitem_free(item);
+ return FAIL;
+ }
+ return OK;
+}
+
/*
* Get the number of items in a Dictionary.
*/
#endif
{"type", 1, 1, f_type},
{"undofile", 1, 1, f_undofile},
+ {"undotree", 0, 0, f_undotree},
{"values", 1, 1, f_values},
{"virtcol", 1, 1, f_virtcol},
{"visualmode", 0, 1, f_visualmode},
#endif
}
+/*
+ * "undotree()" function
+ */
+ static void
+f_undotree(argvars, rettv)
+ typval_T *argvars UNUSED;
+ typval_T *rettv;
+{
+ if (rettv_dict_alloc(rettv) == OK)
+ {
+ dict_T *dict = rettv->vval.v_dict;
+ list_T *list;
+
+ dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
+ dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
+ dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
+ dict_add_nr_str(dict, "save_last",
+ (long)curbuf->b_u_last_save_nr, NULL);
+ dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
+
+ list = list_alloc();
+ if (list != NULL)
+ {
+ u_eval_tree(curbuf->b_u_oldhead, list);
+ dict_add_list(dict, "entries", list);
+ }
+ }
+}
+
/*
* "values(dict)" function
*/
{
dict_T *dict;
- dict = dict_alloc();
- if (dict == NULL)
+ if (rettv_dict_alloc(rettv) == FAIL)
return;
- rettv->v_type = VAR_DICT;
- rettv->vval.v_dict = dict;
- ++dict->dv_refcount;
+ dict = rettv->vval.v_dict;
dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
do_sub_msg(count_only)
int count_only; /* used 'n' flag for ":s" */
{
- int len = 0;
-
/*
* Only report substitutions when:
* - more than 'report' substitutions
&& messaging())
{
if (got_int)
- {
STRCPY(msg_buf, _("(Interrupted) "));
- len = (int)STRLEN(msg_buf);
- }
if (sub_nsubs == 1)
- vim_snprintf((char *)msg_buf + len, sizeof(msg_buf) - len,
+ vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
"%s", count_only ? _("1 match") : _("1 substitution"));
else
- vim_snprintf((char *)msg_buf + len, sizeof(msg_buf) - len,
+ vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
count_only ? _("%ld matches") : _("%ld substitutions"),
sub_nsubs);
- len = (int)STRLEN(msg_buf);
if (sub_nlines == 1)
- vim_snprintf((char *)msg_buf + len, sizeof(msg_buf) - len,
+ vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
"%s", _(" on 1 line"));
else
- vim_snprintf((char *)msg_buf + len, sizeof(msg_buf) - len,
+ vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
_(" on %ld lines"), (long)sub_nlines);
if (msg(msg_buf))
/* save message to display it after redraw */
STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE;
if (write_info.bw_conv_error_lnum != 0)
- {
- size_t l = STRLEN(IObuff);
- vim_snprintf((char *)IObuff + l, IOSIZE - l, _(" in line %ld;"),
+ vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %ld;"),
(long)write_info.bw_conv_error_lnum);
- }
}
else if (notconverted)
{
/* When generating prototypes all of this is skipped, cproto doesn't
* understand this. */
#ifndef PROTO
+
+# ifdef HAVE_STDARG_H
+/* Like vim_vsnprintf() but append to the string. */
+ int
+vim_snprintf_add(char *str, size_t str_m, char *fmt, ...)
+{
+ va_list ap;
+ int str_l;
+ size_t len = STRLEN(str);
+ size_t space;
+
+ if (str_m <= len)
+ space = 0;
+ else
+ space = str_m - len;
+ va_start(ap, fmt);
+ str_l = vim_vsnprintf(str + len, space, fmt, ap, NULL);
+ va_end(ap);
+ return str_l;
+}
+# else
+/* Like vim_vsnprintf() but append to the string. */
+ int
+vim_snprintf_add(str, str_m, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+ char *str;
+ size_t str_m;
+ char *fmt;
+ long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
+{
+ size_t len = STRLEN(str);
+ size_t space;
+
+ if (str_m <= len)
+ space = 0;
+ else
+ space = str_m - len;
+ return vim_vsnprintf(str + len, space, fmt,
+ a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
+}
+# endif
+
# ifdef HAVE_STDARG_H
int
vim_snprintf(char *str, size_t str_m, char *fmt, ...)
_RTLENTRYF
# endif
smsg __ARGS((char_u *, ...));
+
int
# ifdef __BORLANDC__
_RTLENTRYF
# endif
smsg_attr __ARGS((int, char_u *, ...));
+
+int
+# ifdef __BORLANDC__
+_RTLENTRYF
+# endif
+vim_snprintf_add __ARGS((char *, size_t, char *, ...));
+
int
# ifdef __BORLANDC__
_RTLENTRYF
# endif
vim_snprintf __ARGS((char *, size_t, char *, ...));
+
# if defined(HAVE_STDARG_H)
int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs);
# endif
void dictitem_free __ARGS((dictitem_T *item));
int dict_add __ARGS((dict_T *d, dictitem_T *item));
int dict_add_nr_str __ARGS((dict_T *d, char *key, long nr, char_u *str));
+int dict_add_list __ARGS((dict_T *d, char *key, list_T *list));
dictitem_T *dict_find __ARGS((dict_T *d, char_u *key, int len));
char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save));
long get_dict_number __ARGS((dict_T *d, char_u *key));
void u_blockfree __ARGS((buf_T *buf));
int bufIsChanged __ARGS((buf_T *buf));
int curbufIsChanged __ARGS((void));
+void u_eval_tree __ARGS((u_header_T *first_uhp, list_T *list));
/* vim: set ft=c : */
visualinfo_T uh_visual; /* Visual areas before undo/after redo */
#endif
time_t uh_time; /* timestamp when the change was made */
+ long_u uh_save_nr; /* counter for last time saved */
#ifdef U_DEBUG
int uh_magic; /* magic number to check allocation */
#endif
int b_u_synced; /* entry lists are synced */
long b_u_seq_last; /* last used undo sequence number */
long b_u_seq_cur; /* hu_seq of header below which we are now */
- time_t b_u_seq_time; /* uh_time of header below which we are now */
+ time_t b_u_time_cur; /* uh_time of header below which we are now */
+ long_u b_u_last_save_nr; /* counter for last file write */
/*
* variables for "U" command in undo.c
static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len));
static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
-static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
+static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name, int new_version));
static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
static void serialize_pos __ARGS((pos_T pos, FILE *fp));
uhp->uh_seq = ++curbuf->b_u_seq_last;
curbuf->b_u_seq_cur = uhp->uh_seq;
uhp->uh_time = time(NULL);
- curbuf->b_u_seq_time = uhp->uh_time + 1;
+ uhp->uh_save_nr = 0;
+ curbuf->b_u_time_cur = uhp->uh_time + 1;
uhp->uh_walk = 0;
uhp->uh_entry = NULL;
# define UF_HEADER_END_MAGIC 0xe7aa /* magic after last header */
# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
-# define UF_VERSION 1 /* 2-byte undofile version number */
-# define UF_VERSION_CRYPT 0x8001 /* idem, encrypted */
+# define UF_VERSION_PREV 1 /* 2-byte undofile version number */
+# define UF_VERSION 2 /* 2-byte undofile version number */
+# define UF_VERSION_CRYPT_PREV 0x8001 /* idem, encrypted */
+# define UF_VERSION_CRYPT 0x8002 /* idem, encrypted */
+
+/* extra fields for header */
+# define UF_LAST_SAVE_NR 1
+
+/* extra fields for uhp */
+# define UHP_SAVE_NR 1
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
put_bytes(fp, (long_u)buf->b_u_numhead, 4);
put_bytes(fp, (long_u)buf->b_u_seq_last, 4);
put_bytes(fp, (long_u)buf->b_u_seq_cur, 4);
- put_time(fp, buf->b_u_seq_time);
+ put_time(fp, buf->b_u_time_cur);
+
+ /* Optional fields. */
+ putc(4, fp);
+ putc(UF_LAST_SAVE_NR, fp);
+ put_bytes(fp, (long_u)buf->b_u_last_save_nr, 4);
+
+ putc(0, fp); /* end marker */
return OK;
}
#endif
put_time(fp, uhp->uh_time);
+ /* Optional fields. */
+ putc(4, fp);
+ putc(UHP_SAVE_NR, fp);
+ put_bytes(fp, (long_u)uhp->uh_save_nr, 4);
+
+ putc(0, fp); /* end marker */
+
/* Write all the entries. */
for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
{
}
static u_header_T *
-unserialize_uhp(fp, file_name)
+unserialize_uhp(fp, file_name, new_version)
FILE *fp;
char_u *file_name;
+ int new_version;
{
u_header_T *uhp;
int i;
#endif
uhp->uh_time = get8ctime(fp);
+ /* Optional fields. */
+ if (new_version)
+ for (;;)
+ {
+ int len = getc(fp);
+ int what;
+
+ if (len == 0)
+ break;
+ what = getc(fp);
+ switch (what)
+ {
+ case UHP_SAVE_NR:
+ uhp->uh_save_nr = get4c(fp);
+ break;
+ default:
+ /* field not supported, skip */
+ while (--len >= 0)
+ (void)getc(fp);
+ }
+ }
+
/* Unserialize the uep list. */
last_uep = NULL;
while ((c = get2c(fp)) == UF_ENTRY_MAGIC)
/* Undo must be synced. */
u_sync(TRUE);
+ /* Increase the write count, store it in the last undo header, what would
+ * be used for "u". */
+ ++buf->b_u_last_save_nr;
+ uhp = buf->b_u_curhead;
+ if (uhp != NULL)
+ uhp = uhp->uh_next.ptr;
+ else
+ uhp = buf->b_u_newhead;
+ if (uhp != NULL)
+ uhp->uh_save_nr = buf->b_u_last_save_nr;
+
/*
* Write the header.
*/
char_u *file_name;
FILE *fp;
long version, str_len;
+ int new_version;
char_u *line_ptr = NULL;
linenr_T line_lnum;
colnr_T line_colnr;
int num_head = 0;
long old_header_seq, new_header_seq, cur_header_seq;
long seq_last, seq_cur;
+ long_u last_save_nr = 0;
short old_idx = -1, new_idx = -1, cur_idx = -1;
long num_read_uhps = 0;
time_t seq_time;
goto error;
}
version = get2c(fp);
- if (version == UF_VERSION_CRYPT)
+ if (version == UF_VERSION_CRYPT || version == UF_VERSION_CRYPT_PREV)
{
#ifdef FEAT_CRYPT
if (*curbuf->b_p_key == NUL)
goto error;
#endif
}
- else if (version != UF_VERSION)
+ else if (version != UF_VERSION && version != UF_VERSION_PREV)
{
EMSG2(_("E824: Incompatible undo file: %s"), file_name);
goto error;
}
+ new_version = (version == UF_VERSION || version == UF_VERSION_CRYPT);
if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1)
{
seq_cur = get4c(fp);
seq_time = get8ctime(fp);
+ /* Optional header fields, not in previous version. */
+ if (new_version)
+ for (;;)
+ {
+ int len = getc(fp);
+ int what;
+
+ if (len == 0 || len == EOF)
+ break;
+ what = getc(fp);
+ switch (what)
+ {
+ case UF_LAST_SAVE_NR:
+ last_save_nr = get4c(fp);
+ break;
+ default:
+ /* field not supported, skip */
+ while (--len >= 0)
+ (void)getc(fp);
+ }
+ }
+
/* uhp_table will store the freshly created undo headers we allocate
* until we insert them into curbuf. The table remains sorted by the
* sequence numbers of the headers.
goto error;
}
- uhp = unserialize_uhp(fp, file_name);
+ uhp = unserialize_uhp(fp, file_name, new_version);
if (uhp == NULL)
goto error;
uhp_table[num_read_uhps++] = uhp;
curbuf->b_u_numhead = num_head;
curbuf->b_u_seq_last = seq_last;
curbuf->b_u_seq_cur = seq_cur;
- curbuf->b_u_seq_time = seq_time;
+ curbuf->b_u_time_cur = seq_time;
+ curbuf->b_u_last_save_nr = last_save_nr;
curbuf->b_u_synced = TRUE;
vim_free(uhp_table);
/* When doing computations with time_t subtract starttime, because
* time_t converted to a long may result in a wrong number. */
if (sec)
- target = (long)(curbuf->b_u_seq_time - starttime) + step;
+ target = (long)(curbuf->b_u_time_cur - starttime) + step;
else
target = curbuf->b_u_seq_cur + step;
if (step < 0)
/* The timestamp can be the same for multiple changes, just use the one of
* the undone/redone change. */
- curbuf->b_u_seq_time = curhead->uh_time;
+ curbuf->b_u_time_cur = curhead->uh_time;
#ifdef U_DEBUG
u_check(FALSE);
#endif
uhp->uh_seq, changes);
u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
uhp->uh_time);
+ if (uhp->uh_save_nr > 0)
+ {
+ while (STRLEN(IObuff) < 32)
+ STRCAT(IObuff, " ");
+ vim_snprintf_add((char *)IObuff, IOSIZE,
+ " %3ld", uhp->uh_save_nr);
+ }
((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff);
}
sort_strings((char_u **)ga.ga_data, ga.ga_len);
msg_start();
- msg_puts_attr((char_u *)_("number changes time"), hl_attr(HLF_T));
+ msg_puts_attr((char_u *)_("number changes time saved"),
+ hl_attr(HLF_T));
for (i = 0; i < ga.ga_len && !got_int; ++i)
{
msg_putchar('\n');
#endif
(curbuf->b_changed || file_ff_differs(curbuf));
}
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * For undotree(): Append the list of undo blocks at "first_uhp" to "list".
+ * Recursive.
+ */
+ void
+u_eval_tree(first_uhp, list)
+ u_header_T *first_uhp;
+ list_T *list;
+{
+ u_header_T *uhp = first_uhp;
+ dict_T *dict;
+
+ while (uhp != NULL)
+ {
+ dict = dict_alloc();
+ if (dict == NULL)
+ return;
+ dict_add_nr_str(dict, "seq", uhp->uh_seq, NULL);
+ dict_add_nr_str(dict, "time", uhp->uh_time, NULL);
+ if (uhp == curbuf->b_u_newhead)
+ dict_add_nr_str(dict, "newhead", 1, NULL);
+ if (uhp == curbuf->b_u_curhead)
+ dict_add_nr_str(dict, "curhead", 1, NULL);
+ if (uhp->uh_save_nr > 0)
+ dict_add_nr_str(dict, "save", uhp->uh_save_nr, NULL);
+
+ if (uhp->uh_alt_next.ptr != NULL)
+ {
+ list_T *alt_list = list_alloc();
+
+ if (alt_list != NULL)
+ {
+ /* Recursive call to add alternate undo tree. */
+ u_eval_tree(uhp->uh_alt_next.ptr, alt_list);
+ dict_add_list(dict, "alt", alt_list);
+ }
+ }
+
+ list_append_dict(list, dict);
+ uhp = uhp->uh_prev.ptr;
+ }
+}
+#endif
char namebuf[BUFSIZ];
static int tbid = 1;
char_u *p;
- int len;
#ifdef WSDEBUG_TRACE
if (WSDLEVEL(WS_TRACE_VERBOSE))
if (file != NULL && *file != NUL)
{
p = vim_strsave_escaped((char_u *)file, (char_u *)" ");
- len = STRLEN(cbuf);
- vim_snprintf(cbuf + len, sizeof(cbuf) - len, "icon=%s ", p);
+ vim_snprintf_add(cbuf, sizeof(cbuf), "icon=%s ", p);
vim_free(p);
}
- len = STRLEN(cbuf);
- vim_snprintf(cbuf + len, sizeof(cbuf) - len,"1.%d %s :wsverb %s<CR>",
+ vim_snprintf_add(cbuf, sizeof(cbuf),"1.%d %s :wsverb %s<CR>",
tbpri, namebuf, verb);
/* Define the menu item */