1
0
forked from aniani/vim

updated for version 7.0224

This commit is contained in:
Bram Moolenaar
2006-03-14 23:00:46 +00:00
parent 3b1ddfed51
commit 1f4d4de1ba
9 changed files with 358 additions and 78 deletions

View File

@@ -1,7 +1,7 @@
" netrw.vim: Handles file transfer and remote directory listing across a network " netrw.vim: Handles file transfer and remote directory listing across a network
" AUTOLOAD PORTION " AUTOLOAD PORTION
" Date: Mar 09, 2006 " Date: Mar 13, 2006
" Version: 79 " Version: 80
" Maintainer: Charles E Campbell, Jr <drchipNOSPAM at campbellfamily dot biz> " Maintainer: Charles E Campbell, Jr <drchipNOSPAM at campbellfamily dot biz>
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim " GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 1999-2005 Charles E. Campbell, Jr. {{{1 " Copyright: Copyright (C) 1999-2005 Charles E. Campbell, Jr. {{{1
@@ -23,7 +23,7 @@
if &cp || exists("g:loaded_netrw") if &cp || exists("g:loaded_netrw")
finish finish
endif endif
let g:loaded_netrw = "v79" let g:loaded_netrw = "v80"
if v:version < 700 if v:version < 700
echohl WarningMsg | echo "***netrw*** you need vim version 7.0 or later for version ".g:loaded_netrw." of netrw" | echohl None echohl WarningMsg | echo "***netrw*** you need vim version 7.0 or later for version ".g:loaded_netrw." of netrw" | echohl None
finish finish
@@ -2802,6 +2802,23 @@ fun! netrw#DirBrowse(dirname)
endif endif
let s:last_sort_by= g:netrw_sort_by let s:last_sort_by= g:netrw_sort_by
" set up ShellCmdPost handling. Append current buffer to browselist
if !exists("s:netrw_browselist")
let s:netrw_browselist= []
endif
if g:netrw_fastbrowse <= 1 && (empty(s:netrw_browselist) || bufnr("%") > s:netrw_browselist[-1])
call add(s:netrw_browselist,bufnr("%"))
" call Decho("browselist=".string(s:netrw_browselist))
endif
if !exists("s:netrw_browser_shellcmd") && g:netrw_fastbrowse <= 1
" call Decho("setting up local-browser shell command refresh")
let s:netrw_browser_shellcmd= 1
augroup AuNetrwShellCmd
au!
au ShellCmdPost * call s:LocalBrowseShellCmdRefresh()
augroup END
endif
" get the new directory name " get the new directory name
if has("win32") || has("win95") || has("win64") || has("win16") if has("win32") || has("win95") || has("win64") || has("win16")
let b:netrw_curdir= substitute(a:dirname,'\\','/','ge') let b:netrw_curdir= substitute(a:dirname,'\\','/','ge')
@@ -3161,6 +3178,36 @@ fun! s:LocalBrowseChgDir(dirname,newdir,...)
return dirname return dirname
endfun endfun
" ---------------------------------------------------------------------
" LocalBrowseShellCmdRefresh: this function is called after a user has {{{2
" performed any shell command. The idea is to cause all local-browsing
" buffers to be refreshed after a user has executed some shell command,
" on the chance that s/he removed/created a file/directory with it.
fun! s:LocalBrowseShellCmdRefresh()
" call Dfunc("LocalBrowseShellCmdRefresh() browselist=".string(s:netrw_browselist))
" go through all buffers,
" including unlisted (which is why I can't use bufdo)
let curwin = winnr()
let ibl = 0
for ibuf in s:netrw_browselist
if bufwinnr(ibuf) == -1
" call Decho("wiping buf#".ibuf)
exe "bw ".ibuf
call remove(s:netrw_browselist,ibl)
" call Decho("browselist=".string(s:netrw_browselist))
continue
else
" call Decho("refresh buf#".ibuf.'-> win#'.bufwinnr(ibuf))
exe bufwinnr(ibuf)."wincmd w"
call s:NetRefresh(s:LocalBrowseChgDir(b:netrw_curdir,'./'),1)
endif
let ibl= ibl + 1
endfor
exe curwin."wincmd w"
" call Dret("LocalBrowseShellCmdRefresh")
endfun
" --------------------------------------------------------------------- " ---------------------------------------------------------------------
" LocalBrowseRm: {{{2 " LocalBrowseRm: {{{2
fun! s:LocalBrowseRm(path) range fun! s:LocalBrowseRm(path) range
@@ -3465,7 +3512,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
call search('\<'.substitute(dirfile,"^.*/","","").'\>',"w") call search('\<'.substitute(dirfile,"^.*/","","").'\>',"w")
endif endif
let w:netrw_explore_mtchcnt = indx + 1 let w:netrw_explore_mtchcnt = indx + 1
let w:netrw_explore_bufnr = bufnr(".") let w:netrw_explore_bufnr = bufnr("%")
let w:netrw_explore_line = line(".") let w:netrw_explore_line = line(".")
call s:SetupNetrwStatusLine('%f %h%m%r%=%9*%{NetrwStatusLine()}') call s:SetupNetrwStatusLine('%f %h%m%r%=%9*%{NetrwStatusLine()}')
" call Decho("explore: mtchcnt=".w:netrw_explore_mtchcnt." bufnr=".w:netrw_explore_bufnr." line#".w:netrw_explore_line) " call Decho("explore: mtchcnt=".w:netrw_explore_mtchcnt." bufnr=".w:netrw_explore_bufnr." line#".w:netrw_explore_line)
@@ -3537,8 +3584,8 @@ fun! NetrwStatusLine()
" let g:stlmsg="" " let g:stlmsg=""
" if !exists("w:netrw_explore_bufnr") " if !exists("w:netrw_explore_bufnr")
" let g:stlmsg="!X<explore_bufnr>" " let g:stlmsg="!X<explore_bufnr>"
" elseif w:netrw_explore_bufnr != bufnr(".") " elseif w:netrw_explore_bufnr != bufnr("%")
" let g:stlmsg="explore_bufnr!=".bufnr(".") " let g:stlmsg="explore_bufnr!=".bufnr("%")
" endif " endif
" if !exists("w:netrw_explore_line") " if !exists("w:netrw_explore_line")
" let g:stlmsg=" !X<explore_line>" " let g:stlmsg=" !X<explore_line>"
@@ -3550,7 +3597,7 @@ fun! NetrwStatusLine()
" endif " endif
" ^^^ NetrwStatusLine() debugging ^^^ " ^^^ NetrwStatusLine() debugging ^^^
if !exists("w:netrw_explore_bufnr") || w:netrw_explore_bufnr != bufnr(".") || !exists("w:netrw_explore_line") || w:netrw_explore_line != line(".") || !exists("w:netrw_explore_list") if !exists("w:netrw_explore_bufnr") || w:netrw_explore_bufnr != bufnr("%") || !exists("w:netrw_explore_line") || w:netrw_explore_line != line(".") || !exists("w:netrw_explore_list")
" restore user's status line " restore user's status line
let &stl = s:netrw_users_stl let &stl = s:netrw_users_stl
let &laststatus = s:netrw_users_ls let &laststatus = s:netrw_users_ls

View File

@@ -1,4 +1,4 @@
*diff.txt* For Vim version 7.0aa. Last change: 2006 Feb 18 *diff.txt* For Vim version 7.0aa. Last change: 2006 Mar 14
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -378,7 +378,7 @@ will have the same effect. These variables are set to the file names used:
Example (this does the same as 'patchexpr' being empty): > Example (this does the same as 'patchexpr' being empty): >
let patchexpr=MyPatch let patchexpr=MyPatch()
function MyPatch function MyPatch
:call system("patch -o " . v:fname_out . " " . v:fname_in . :call system("patch -o " . v:fname_out . " " . v:fname_in .
\ " < " . v:fname_diff) \ " < " . v:fname_diff)

View File

@@ -1,4 +1,4 @@
*pi_netrw.txt* For Vim version 7.0. Last change: Mar 09, 2006 *pi_netrw.txt* For Vim version 7.0. Last change: Mar 10, 2006
VIM REFERENCE MANUAL by Charles E. Campbell, Jr. VIM REFERENCE MANUAL by Charles E. Campbell, Jr.

View File

@@ -1965,6 +1965,8 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
:dsp tagsrch.txt /*:dsp* :dsp tagsrch.txt /*:dsp*
:dsplit tagsrch.txt /*:dsplit* :dsplit tagsrch.txt /*:dsplit*
:e editing.txt /*:e* :e editing.txt /*:e*
:ea undo.txt /*:ea*
:earlier undo.txt /*:earlier*
:ec eval.txt /*:ec* :ec eval.txt /*:ec*
:echo eval.txt /*:echo* :echo eval.txt /*:echo*
:echoe eval.txt /*:echoe* :echoe eval.txt /*:echoe*
@@ -2142,6 +2144,8 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
:lang mlang.txt /*:lang* :lang mlang.txt /*:lang*
:language mlang.txt /*:language* :language mlang.txt /*:language*
:last editing.txt /*:last* :last editing.txt /*:last*
:lat undo.txt /*:lat*
:later undo.txt /*:later*
:lb quickfix.txt /*:lb* :lb quickfix.txt /*:lb*
:lbuffer quickfix.txt /*:lbuffer* :lbuffer quickfix.txt /*:lbuffer*
:lc editing.txt /*:lc* :lc editing.txt /*:lc*
@@ -5281,7 +5285,9 @@ g$ motion.txt /*g$*
g& change.txt /*g&* g& change.txt /*g&*
g' motion.txt /*g'* g' motion.txt /*g'*
g'a motion.txt /*g'a* g'a motion.txt /*g'a*
g+ undo.txt /*g+*
g, motion.txt /*g,* g, motion.txt /*g,*
g- undo.txt /*g-*
g0 motion.txt /*g0* g0 motion.txt /*g0*
g8 various.txt /*g8* g8 various.txt /*g8*
g:DrChipTopLvlMenu pi_netrw.txt /*g:DrChipTopLvlMenu* g:DrChipTopLvlMenu pi_netrw.txt /*g:DrChipTopLvlMenu*
@@ -6254,6 +6260,7 @@ new-searchpat version6.txt /*new-searchpat*
new-session-files version5.txt /*new-session-files* new-session-files version5.txt /*new-session-files*
new-spell version7.txt /*new-spell* new-spell version7.txt /*new-spell*
new-tab-pages version7.txt /*new-tab-pages* new-tab-pages version7.txt /*new-tab-pages*
new-undo-branches version7.txt /*new-undo-branches*
new-unlisted-buffers version6.txt /*new-unlisted-buffers* new-unlisted-buffers version6.txt /*new-unlisted-buffers*
new-user-defined version5.txt /*new-user-defined* new-user-defined version5.txt /*new-user-defined*
new-user-manual version6.txt /*new-user-manual* new-user-manual version6.txt /*new-user-manual*
@@ -7212,6 +7219,7 @@ undercurl syntax.txt /*undercurl*
underline syntax.txt /*underline* underline syntax.txt /*underline*
undo undo.txt /*undo* undo undo.txt /*undo*
undo-blocks undo.txt /*undo-blocks* undo-blocks undo.txt /*undo-blocks*
undo-branches undo.txt /*undo-branches*
undo-commands undo.txt /*undo-commands* undo-commands undo.txt /*undo-commands*
undo-redo undo.txt /*undo-redo* undo-redo undo.txt /*undo-redo*
undo-remarks undo.txt /*undo-remarks* undo-remarks undo.txt /*undo-remarks*

View File

@@ -1,4 +1,4 @@
*undo.txt* For Vim version 7.0aa. Last change: 2006 Feb 28 *undo.txt* For Vim version 7.0aa. Last change: 2006 Mar 14
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -11,7 +11,8 @@ The basics are explained in section |02.5| of the user manual.
1. Undo and redo commands |undo-commands| 1. Undo and redo commands |undo-commands|
2. Two ways of undo |undo-two-ways| 2. Two ways of undo |undo-two-ways|
3. Undo blocks |undo-blocks| 3. Undo blocks |undo-blocks|
4. Remarks about undo |undo-remarks| 4. Undo branches |undo-branches|
5. Remarks about undo |undo-remarks|
============================================================================== ==============================================================================
1. Undo and redo commands *undo-commands* 1. Undo and redo commands *undo-commands*
@@ -102,7 +103,88 @@ After this an "u" command will undo the delete command and the previous
change. change.
============================================================================== ==============================================================================
4. Remarks about undo *undo-remarks* 4. Undo branches *undo-branches*
Above we only discussed one line of undo. But it is also possible to branch
off. This happens when you undo a few changes and then make a new change.
The undone changes become a branch. You can go to that branch with the
following commands.
What matters here is the order in which the changes are made. Undo and redo
are not considered changes in this context. After each change you have a new
state of the text.
*g-*
g- Go to older text state. With a count repeat that many
times. {not in Vi}
*:ea* *:earlier*
:earlier {count} Go to older text state {count} times.
:earlier {N}s Go to older text state about {N} seconds before.
:earlier {N}m Go to older text state about {N} minutes before.
:earlier {N}h Go to older text state about {N} hours before.
*g+*
g+ Go to newer text state. With a count repeat that many
times. {not in Vi}
*:lat* *:later*
:later {count} Go to newer text state {count} times.
:later {N}s Go to newer text state about {N} seconds later.
:later {N}m Go to newer text state about {N} minutes later.
:later {N}h Go to newer text state about {N} hours later.
Note that text states will become unreachable when undo information is cleared
for 'undolevels'.
Don't be surprised when moving through time shows multiple changes to take
place at a time. This happens when moving through the undo tree and then
making a new change.
EXAMPLE
Start with this text:
one two three ~
Delete the first word by pressing "x" three times:
ne two three ~
e two three ~
two three ~
Now undo that by pressing "u" three times:
e two three ~
ne two three ~
one two three ~
Delete the second word by pressing "x" three times:
one wo three ~
one o three ~
one three ~
Now undo that by using "g-" three times:
one o three ~
one wo three ~
one two three ~
Continue going back in time by pressing "g-" one more time:
two three ~
You are now back in the first undo branch, after deleting "one". Repeating
"g-" will now bring you back to the original text:
e two three ~
ne two three ~
one two three ~
Jump to the last change with ":later 1h":
one three ~
And back to the start again with ":earlier 1h":
one two three ~
Note that using "u" and CTRL-R will not get you to all possible text states
while repeating "g-" and "g+" does.
==============================================================================
5. Remarks about undo *undo-remarks*
The number of changes that are remembered is set with the 'undolevels' option. The number of changes that are remembered is set with the 'undolevels' option.
If it is zero, the Vi-compatible way is always used. If it is negative no If it is zero, the Vi-compatible way is always used. If it is negative no

View File

@@ -931,6 +931,29 @@ deathtrap SIGDEFARG(sigarg)
get_stack_limit(); get_stack_limit();
#endif #endif
#if 0
/* This is for opening gdb the moment Vim crashes.
* You need to manually adjust the file name and Vim executable name.
* Suggested by SungHyun Nam. */
{
# define VI_GDB_FILE "/tmp/vimgdb"
# define VIM_NAME "/usr/bin/vim"
FILE *fp = fopen(VI_GDB_FILE, "w");
if (fp)
{
fprintf(fp,
"file %s\n"
"attach %d\n"
"set height 1000\n"
"bt full\n"
, VIM_NAME, getpid());
fclose(fp);
system("xterm -e gdb -x "VI_GDB_FILE);
unlink(VI_GDB_FILE);
}
}
#endif
#ifdef SIGHASARG #ifdef SIGHASARG
/* try to find the name of this signal */ /* try to find the name of this signal */
for (i = 0; signal_info[i].sig != -1; i++) for (i = 0; signal_info[i].sig != -1; i++)

View File

@@ -504,6 +504,7 @@ pum_undisplay()
{ {
pum_array = NULL; pum_array = NULL;
redraw_all_later(SOME_VALID); redraw_all_later(SOME_VALID);
status_redraw_all();
} }
/* /*

View File

@@ -4273,9 +4273,15 @@ win_line(wp, lnum, startrow, endrow, nochange)
#ifdef FEAT_SYN_HL #ifdef FEAT_SYN_HL
/* Highlight 'cursorcolumn' past end of the line. */ /* Highlight 'cursorcolumn' past end of the line. */
if (wp->w_p_wrap)
v = wp->w_skipcol;
else
v = wp->w_leftcol;
if (vcol < v) /* line ends before left margin */
vcol = v;
if (wp->w_p_cuc if (wp->w_p_cuc
&& (int)wp->w_virtcol >= vcol && (int)wp->w_virtcol >= vcol
&& (int)wp->w_virtcol < W_WIDTH(wp) && (int)wp->w_virtcol < W_WIDTH(wp) + v
&& lnum != wp->w_cursor.lnum && lnum != wp->w_cursor.lnum
# ifdef FEAT_RIGHTLEFT # ifdef FEAT_RIGHTLEFT
&& !wp->w_p_rl && !wp->w_p_rl

View File

@@ -39,13 +39,39 @@
* *
* Each u_entry list contains the information for one undo or redo. * Each u_entry list contains the information for one undo or redo.
* curbuf->b_u_curhead points to the header of the last undo (the next redo), * curbuf->b_u_curhead points to the header of the last undo (the next redo),
* or is NULL if nothing has been undone. * or is NULL if nothing has been undone (end of the branch).
* *
* For keeping alternate undo/redo branches the uh_alt field is used. Thus at * For keeping alternate undo/redo branches the uh_alt field is used. Thus at
* each point in the list a branch may appear for an alternate to redo. The * each point in the list a branch may appear for an alternate to redo. The
* uh_seq field is numbered sequentially to be able to find a newer or older * uh_seq field is numbered sequentially to be able to find a newer or older
* branch. * branch.
* *
* +---------------+ +---------------+
* b_u_oldhead --->| u_header | | u_header |
* | uh_alt_next ---->| uh_alt_next ----> NULL
* NULL <----- uh_alt_prev |<------ uh_alt_prev |
* | uh_prev | | uh_prev |
* +-----|---------+ +-----|---------+
* | |
* V V
* +---------------+ +---------------+
* | u_header | | u_header |
* | uh_alt_next | | uh_alt_next |
* b_u_newhead --->| uh_alt_prev | | uh_alt_prev |
* | uh_prev | | uh_prev |
* +-----|---------+ +-----|---------+
* | |
* V V
* NULL +---------------+ +---------------+
* | u_header | | u_header |
* | uh_alt_next ---->| uh_alt_next |
* | uh_alt_prev |<------ uh_alt_prev |
* | uh_prev | | uh_prev |
* +-----|---------+ +-----|---------+
* | |
* etc. etc.
*
*
* All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the
* buffer is unloaded. * buffer is unloaded.
*/ */
@@ -55,6 +81,7 @@
/* See below: use malloc()/free() for memory management. */ /* See below: use malloc()/free() for memory management. */
#define U_USE_MALLOC 1 #define U_USE_MALLOC 1
static void u_unch_branch __ARGS((u_header_T *uhp));
static u_entry_T *u_get_headentry __ARGS((void)); static u_entry_T *u_get_headentry __ARGS((void));
static void u_getbot __ARGS((void)); static void u_getbot __ARGS((void));
static int undo_allowed __ARGS((void)); static int undo_allowed __ARGS((void));
@@ -62,7 +89,7 @@ static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T));
static void u_doit __ARGS((int count)); static void u_doit __ARGS((int count));
static void u_undoredo __ARGS((void)); static void u_undoredo __ARGS((void));
static void u_undo_end __ARGS((void)); static void u_undo_end __ARGS((void));
static void u_freelist __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); static void u_freeheader __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); static void u_freebranch __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp)); static void u_freeentries __ARGS((buf_T *buf, u_header_T *uhp, u_header_T **uhpp));
static void u_freeentry __ARGS((u_entry_T *, long)); static void u_freeentry __ARGS((u_entry_T *, long));
@@ -270,8 +297,8 @@ u_savecommon(top, bot, newbot)
} }
/* /*
* If we undid more than we redid, remove the entry lists before and * If we undid more than we redid, move the entry lists before and
* including curbuf->b_u_curhead to the alternate branch. * including curbuf->b_u_curhead to an alternate branch.
*/ */
old_curhead = curbuf->b_u_curhead; old_curhead = curbuf->b_u_curhead;
if (old_curhead != NULL) if (old_curhead != NULL)
@@ -285,17 +312,17 @@ u_savecommon(top, bot, newbot)
*/ */
while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL) while (curbuf->b_u_numhead > p_ul && curbuf->b_u_oldhead != NULL)
{ {
u_header_T *upfree = curbuf->b_u_oldhead; u_header_T *uhfree = curbuf->b_u_oldhead;
/* If there is no branch only free one header. */ /* If there is no branch only free one header. */
if (upfree->uh_alt_next == NULL) if (uhfree->uh_alt_next == NULL)
u_freelist(curbuf, upfree, &old_curhead); u_freeheader(curbuf, uhfree, &old_curhead);
else else
{ {
/* Free the oldest alternate branch as a whole. */ /* Free the oldest alternate branch as a whole. */
while (upfree->uh_alt_next != NULL) while (uhfree->uh_alt_next != NULL)
upfree = upfree->uh_alt_next; uhfree = uhfree->uh_alt_next;
u_freebranch(curbuf, upfree, &old_curhead); u_freebranch(curbuf, uhfree, &old_curhead);
} }
} }
@@ -317,10 +344,14 @@ u_savecommon(top, bot, newbot)
curbuf->b_u_oldhead = uhp; curbuf->b_u_oldhead = uhp;
} }
uhp->uh_alt_prev = NULL; uhp->uh_alt_prev = NULL;
uhp->uh_seq = curbuf->b_u_seq_last++;
curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
if (curbuf->b_u_newhead != NULL) if (curbuf->b_u_newhead != NULL)
curbuf->b_u_newhead->uh_prev = uhp; curbuf->b_u_newhead->uh_prev = uhp;
uhp->uh_seq = curbuf->b_u_seq_last++;
curbuf->b_u_seq_cur = curbuf->b_u_seq_last;
uhp->uh_time = time(NULL);
curbuf->b_u_seq_time = uhp->uh_time + 1;
uhp->uh_walk = 0; uhp->uh_walk = 0;
uhp->uh_entry = NULL; uhp->uh_entry = NULL;
uhp->uh_getbot_entry = NULL; uhp->uh_getbot_entry = NULL;
@@ -331,7 +362,6 @@ u_savecommon(top, bot, newbot)
else else
uhp->uh_cursor_vcol = -1; uhp->uh_cursor_vcol = -1;
#endif #endif
uhp->uh_time = time(NULL);
/* save changed and buffer empty flag for undo */ /* save changed and buffer empty flag for undo */
uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) + uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
@@ -575,7 +605,6 @@ u_doit(count)
} }
u_undoredo(); u_undoredo();
curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq;
} }
else else
{ {
@@ -586,7 +615,8 @@ u_doit(count)
} }
u_undoredo(); u_undoredo();
curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_seq + 1; ++curbuf->b_u_seq_cur;
++curbuf->b_u_seq_time;
/* Advance for next redo. Set "newhead" when at the end of the /* Advance for next redo. Set "newhead" when at the end of the
* redoable changes. */ * redoable changes. */
@@ -603,18 +633,27 @@ static int lastmark = 0;
/* /*
* Undo or redo over the timeline. * Undo or redo over the timeline.
* When "step" is negative go back in time, otherwise goes forward in time. * When "step" is negative go back in time, otherwise goes forward in time.
* When "sec" is FALSE make "step" steps, when "sec" is TRUE use "step" as
* seconds.
*/ */
void void
undo_time(step) undo_time(step, sec)
int step; long step;
int sec;
{ {
long target; long target;
long closest; long closest;
long closest_start;
long closest_seq = 0;
long val;
long limit;
u_header_T *uhp; u_header_T *uhp;
u_header_T *last; u_header_T *last;
int mark; int mark;
int nomark; int nomark;
int round; int round;
int dosec = sec;
int above = FALSE;
u_newcount = 0; u_newcount = 0;
u_oldcount = 0; u_oldcount = 0;
@@ -625,18 +664,43 @@ undo_time(step)
* the current one also counts, thus do one less. */ * the current one also counts, thus do one less. */
if (step < 0) if (step < 0)
{ {
target = curbuf->b_u_seq_cur + step; if (sec)
closest = -1; target = (long)curbuf->b_u_seq_time + step;
else
target = curbuf->b_u_seq_cur + step;
if (target < 0)
target = -1;
closest = -2;
} }
else else
{ {
target = curbuf->b_u_seq_cur + step - 1; if (sec)
closest = curbuf->b_u_seq_last + 1; {
target = curbuf->b_u_seq_time + step - 1;
closest = time(NULL) + 1;
}
else
{
target = curbuf->b_u_seq_cur + step - 1;
closest = curbuf->b_u_seq_last + 1;
}
if (target >= closest)
target = closest - 1;
} }
closest_start = closest;
if (sec)
limit = curbuf->b_u_seq_time + (step > 0 ? -1 : 1);
else
limit = curbuf->b_u_seq_cur;
/* May do this twice: /*
* May do this twice:
* 1. Search for "target", update "closest" to the best match found. * 1. Search for "target", update "closest" to the best match found.
* 2. If "target" not found search for "closest". */ * 2. If "target" not found search for "closest".
*
* When using the closest time we use the sequence number in the second
* round, because there may be several entries with the same time.
*/
for (round = 1; round <= 2; ++round) for (round = 1; round <= 2; ++round)
{ {
/* Find the path from the current state to where we want to go. The /* Find the path from the current state to where we want to go. The
@@ -654,13 +718,37 @@ undo_time(step)
while (uhp != NULL) while (uhp != NULL)
{ {
uhp->uh_walk = mark; uhp->uh_walk = mark;
if (uhp->uh_seq == target) /* found it! */ val = (dosec ? uhp->uh_time : uhp->uh_seq);
break;
if (round == 1 && (step < 0 if (round == 1)
? (uhp->uh_seq < target && uhp->uh_seq > closest) {
: (uhp->uh_seq > target && uhp->uh_seq < closest))) /* Remember the header that is closest to the target.
closest = uhp->uh_seq; * It must be at least in the right direction (checked with
* "limit"). When the timestamp is equal find the
* highest/lowest sequence number. */
if ((dosec && val == closest)
? (step < 0
? uhp->uh_seq < closest_seq
: uhp->uh_seq > closest_seq)
: (step < 0
? (val < limit
&& (closest > target
? (val <= closest)
: (val >= closest)))
: (val > limit
&& (closest < target
? val >= closest
: val <= closest))))
{
closest = val;
closest_seq = uhp->uh_seq;
}
}
/* Quit searching when we found a match. But when searching for a
* time we need to continue looking for the best uh_seq. */
if (target == val && !dosec)
break;
/* go down in the tree if we haven't been there */ /* go down in the tree if we haven't been there */
if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != nomark
@@ -693,18 +781,19 @@ undo_time(step)
if (uhp != NULL) /* found it */ if (uhp != NULL) /* found it */
break; break;
if (step < 0 && closest == -1) if (closest == closest_start)
{ {
MSG(_("Already at oldest change")); if (step < 0)
return; MSG(_("Already at oldest change"));
} else
if (step > 0 && closest == curbuf->b_u_seq_last + 1) MSG(_("Already at newest change"));
{
MSG(_("Already at newest change"));
return; return;
} }
target = closest; target = closest_seq;
dosec = FALSE;
if (step < 0)
above = TRUE; /* stop above the header */
} }
/* If we found it: Follow the path to go to where we want to be. */ /* If we found it: Follow the path to go to where we want to be. */
@@ -720,7 +809,8 @@ undo_time(step)
uhp = curbuf->b_u_newhead; uhp = curbuf->b_u_newhead;
else else
{ {
while (uhp->uh_alt_prev != NULL) while (uhp->uh_alt_prev != NULL
&& uhp->uh_alt_prev->uh_walk == mark)
{ {
uhp->uh_walk = nomark; uhp->uh_walk = nomark;
uhp = uhp->uh_alt_prev; uhp = uhp->uh_alt_prev;
@@ -732,11 +822,10 @@ undo_time(step)
curbuf->b_u_curhead = uhp; curbuf->b_u_curhead = uhp;
u_undoredo(); u_undoredo();
uhp->uh_walk = nomark; /* don't go back down here */ uhp->uh_walk = nomark; /* don't go back down here */
curbuf->b_u_seq_cur = uhp->uh_seq;
} }
/* /*
* And now go down the tree, branching off where needed. * And now go down the tree (redo), branching off where needed.
*/ */
uhp = curbuf->b_u_curhead; uhp = curbuf->b_u_curhead;
for (;;) for (;;)
@@ -759,13 +848,21 @@ undo_time(step)
uhp = last; uhp = last;
} }
curbuf->b_u_curhead = uhp;
curbuf->b_u_seq_cur = uhp->uh_seq;
curbuf->b_u_seq_time = uhp->uh_time;
if (uhp->uh_walk != mark) if (uhp->uh_walk != mark)
break; /* must have reached the target */ break; /* must have reached the target */
curbuf->b_u_curhead = uhp; /* Stop when going backwards in time and didn't find the exact
* header we were looking for. */
if (uhp->uh_seq == target && above)
break;
u_undoredo(); u_undoredo();
curbuf->b_u_seq_cur = uhp->uh_seq + 1; ++curbuf->b_u_seq_cur;
++curbuf->b_u_seq_time;
/* Advance "curhead" to below the header we last used. If it /* Advance "curhead" to below the header we last used. If it
* becomes NULL then we need to set "newhead" to this leaf. */ * becomes NULL then we need to set "newhead" to this leaf. */
@@ -813,8 +910,9 @@ u_undoredo()
visualinfo_T visualinfo; visualinfo_T visualinfo;
#endif #endif
int empty_buffer; /* buffer became empty */ int empty_buffer; /* buffer became empty */
u_header_T *curhead = curbuf->b_u_curhead;
old_flags = curbuf->b_u_curhead->uh_flags; old_flags = curhead->uh_flags;
new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + new_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
setpcmark(); setpcmark();
@@ -831,7 +929,7 @@ u_undoredo()
curbuf->b_op_end.lnum = 0; curbuf->b_op_end.lnum = 0;
curbuf->b_op_end.col = 0; curbuf->b_op_end.col = 0;
for (uep = curbuf->b_u_curhead->uh_entry; uep != NULL; uep = nuep) for (uep = curhead->uh_entry; uep != NULL; uep = nuep)
{ {
top = uep->ue_top; top = uep->ue_top;
bot = uep->ue_bot; bot = uep->ue_bot;
@@ -853,10 +951,10 @@ u_undoredo()
/* If the saved cursor is somewhere in this undo block, move it to /* If the saved cursor is somewhere in this undo block, move it to
* the remembered position. Makes "gwap" put the cursor back * the remembered position. Makes "gwap" put the cursor back
* where it was. */ * where it was. */
lnum = curbuf->b_u_curhead->uh_cursor.lnum; lnum = curhead->uh_cursor.lnum;
if (lnum >= top && lnum <= top + newsize + 1) if (lnum >= top && lnum <= top + newsize + 1)
{ {
curwin->w_cursor = curbuf->b_u_curhead->uh_cursor; curwin->w_cursor = curhead->uh_cursor;
newlnum = curwin->w_cursor.lnum - 1; newlnum = curwin->w_cursor.lnum - 1;
} }
else else
@@ -970,8 +1068,8 @@ u_undoredo()
newlist = uep; newlist = uep;
} }
curbuf->b_u_curhead->uh_entry = newlist; curhead->uh_entry = newlist;
curbuf->b_u_curhead->uh_flags = new_flags; curhead->uh_flags = new_flags;
if ((old_flags & UH_EMPTYBUF) && bufempty()) if ((old_flags & UH_EMPTYBUF) && bufempty())
curbuf->b_ml.ml_flags |= ML_EMPTY; curbuf->b_ml.ml_flags |= ML_EMPTY;
if (old_flags & UH_CHANGED) if (old_flags & UH_CHANGED)
@@ -987,16 +1085,16 @@ u_undoredo()
* restore marks from before undo/redo * restore marks from before undo/redo
*/ */
for (i = 0; i < NMARKS; ++i) for (i = 0; i < NMARKS; ++i)
if (curbuf->b_u_curhead->uh_namedm[i].lnum != 0) if (curhead->uh_namedm[i].lnum != 0)
{ {
curbuf->b_namedm[i] = curbuf->b_u_curhead->uh_namedm[i]; curbuf->b_namedm[i] = curhead->uh_namedm[i];
curbuf->b_u_curhead->uh_namedm[i] = namedm[i]; curhead->uh_namedm[i] = namedm[i];
} }
#ifdef FEAT_VISUAL #ifdef FEAT_VISUAL
if (curbuf->b_u_curhead->uh_visual.vi_start.lnum != 0) if (curhead->uh_visual.vi_start.lnum != 0)
{ {
curbuf->b_visual = curbuf->b_u_curhead->uh_visual; curbuf->b_visual = curhead->uh_visual;
curbuf->b_u_curhead->uh_visual = visualinfo; curhead->uh_visual = visualinfo;
} }
#endif #endif
@@ -1005,15 +1103,15 @@ u_undoredo()
* before starting the change (for the "o" command). * before starting the change (for the "o" command).
* Otherwise the cursor should go to the first undone line. * Otherwise the cursor should go to the first undone line.
*/ */
if (curbuf->b_u_curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
&& curwin->w_cursor.lnum > 1) && curwin->w_cursor.lnum > 1)
--curwin->w_cursor.lnum; --curwin->w_cursor.lnum;
if (curbuf->b_u_curhead->uh_cursor.lnum == curwin->w_cursor.lnum) if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum)
{ {
curwin->w_cursor.col = curbuf->b_u_curhead->uh_cursor.col; curwin->w_cursor.col = curhead->uh_cursor.col;
#ifdef FEAT_VIRTUALEDIT #ifdef FEAT_VIRTUALEDIT
if (virtual_active() && curbuf->b_u_curhead->uh_cursor_vcol >= 0) if (virtual_active() && curhead->uh_cursor_vcol >= 0)
coladvance((colnr_T)curbuf->b_u_curhead->uh_cursor_vcol); coladvance((colnr_T)curhead->uh_cursor_vcol);
else else
curwin->w_cursor.coladd = 0; curwin->w_cursor.coladd = 0;
#endif #endif
@@ -1034,6 +1132,10 @@ u_undoredo()
/* Make sure the cursor is on an existing line and column. */ /* Make sure the cursor is on an existing line and column. */
check_cursor(); check_cursor();
/* Remember where we are for "g-" and ":earlier 10s". */
curbuf->b_u_seq_cur = curhead->uh_seq;
curbuf->b_u_seq_time = curhead->uh_time;
} }
/* /*
@@ -1135,12 +1237,23 @@ ex_undojoin(eap)
void void
u_unchanged(buf) u_unchanged(buf)
buf_T *buf; buf_T *buf;
{
u_unch_branch(buf->b_u_oldhead);
buf->b_did_warn = FALSE;
}
static void
u_unch_branch(uhp)
u_header_T *uhp;
{ {
u_header_T *uh; u_header_T *uh;
for (uh = buf->b_u_newhead; uh; uh = uh->uh_next) for (uh = uhp; uh != NULL; uh = uh->uh_prev)
{
uh->uh_flags |= UH_CHANGED; uh->uh_flags |= UH_CHANGED;
buf->b_did_warn = FALSE; if (uh->uh_alt_next != NULL)
u_unch_branch(uh->uh_alt_next); /* recursive */
}
} }
/* /*
@@ -1201,7 +1314,7 @@ u_getbot()
* Free one header and its entry list and adjust the pointers. * Free one header and its entry list and adjust the pointers.
*/ */
static void static void
u_freelist(buf, uhp, uhpp) u_freeheader(buf, uhp, uhpp)
buf_T *buf; buf_T *buf;
u_header_T *uhp; u_header_T *uhp;
u_header_T **uhpp; /* if not NULL reset when freeing this header */ u_header_T **uhpp; /* if not NULL reset when freeing this header */
@@ -1229,7 +1342,7 @@ u_freelist(buf, uhp, uhpp)
} }
/* /*
* Free an alternate branch and all following alternate branches. * Free an alternate branch and any following alternate branches.
*/ */
static void static void
u_freebranch(buf, uhp, uhpp) u_freebranch(buf, uhp, uhpp)
@@ -1415,7 +1528,7 @@ u_blockfree(buf)
buf_T *buf; buf_T *buf;
{ {
while (buf->b_u_oldhead != NULL) while (buf->b_u_oldhead != NULL)
u_freelist(buf, buf->b_u_oldhead, NULL); u_freeheader(buf, buf->b_u_oldhead, NULL);
U_FREE_LINE(buf->b_u_line_ptr); U_FREE_LINE(buf->b_u_line_ptr);
} }