diff options
author | Bram Moolenaar <Bram@vim.org> | 2010-06-27 01:15:55 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2010-06-27 01:15:55 +0200 |
commit | a800b42975f7a62282cb90d8c61ef3cff2fe810a (patch) | |
tree | 9ecc9705a77dcc23b87ba2dffb9a06765625519a /src/undo.c | |
parent | d69980f9dd1a538e9ba4313616f3be452c95206d (diff) | |
download | vim-git-a800b42975f7a62282cb90d8c61ef3cff2fe810a.tar.gz |
Add file save counter to undo information. Add undotree() function.
Diffstat (limited to 'src/undo.c')
-rw-r--r-- | src/undo.c | 162 |
1 files changed, 149 insertions, 13 deletions
diff --git a/src/undo.c b/src/undo.c index b17378153..ddd31117f 100644 --- a/src/undo.c +++ b/src/undo.c @@ -106,7 +106,7 @@ static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, F 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)); @@ -473,7 +473,8 @@ u_savecommon(top, bot, newbot) 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; @@ -671,8 +672,16 @@ nomem: # 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"); @@ -918,7 +927,14 @@ serialize_header(fp, buf, hash) 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; } @@ -962,6 +978,13 @@ serialize_uhp(fp, buf, uhp) #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) { @@ -974,9 +997,10 @@ serialize_uhp(fp, buf, uhp) } 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; @@ -1021,6 +1045,28 @@ unserialize_uhp(fp, file_name) #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) @@ -1398,6 +1444,17 @@ u_write_undo(name, forceit, buf, hash) /* 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. */ @@ -1496,6 +1553,7 @@ u_read_undo(name, hash, orig_name) 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; @@ -1503,6 +1561,7 @@ u_read_undo(name, hash, orig_name) 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; @@ -1575,7 +1634,7 @@ u_read_undo(name, hash, orig_name) 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) @@ -1595,11 +1654,12 @@ u_read_undo(name, hash, orig_name) 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) { @@ -1645,6 +1705,28 @@ u_read_undo(name, hash, orig_name) 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. @@ -1665,7 +1747,7 @@ u_read_undo(name, hash, orig_name) 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; @@ -1766,7 +1848,8 @@ u_read_undo(name, hash, orig_name) 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); @@ -1962,7 +2045,7 @@ undo_time(step, sec, absolute) /* 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) @@ -2458,7 +2541,7 @@ u_undoredo(undo) /* 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 @@ -2595,6 +2678,13 @@ ex_undolist(eap) 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); } @@ -2645,7 +2735,8 @@ ex_undolist(eap) 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'); @@ -3048,3 +3139,48 @@ curbufIsChanged() #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 |