mirror of
https://github.com/vim/vim.git
synced 2025-07-24 10:45:12 -04:00
Included patch for persistent undo. Lots of changes and added test.
This commit is contained in:
parent
c39125d7c4
commit
55debbe384
@ -805,6 +805,7 @@ Note: these are typed literally, they are not special keys!
|
|||||||
|
|
||||||
*filename-modifiers*
|
*filename-modifiers*
|
||||||
*:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs*
|
*:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs*
|
||||||
|
*%:8* *%:p* *%:.* *%:~* *%:h* *%:t* *%:r* *%:e* *%:s* *%:gs*
|
||||||
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<sfile>",
|
The file name modifiers can be used after "%", "#", "#n", "<cfile>", "<sfile>",
|
||||||
"<afile>" or "<abuf>". They are also used with the |fnamemodify()| function.
|
"<afile>" or "<abuf>". They are also used with the |fnamemodify()| function.
|
||||||
These are not available when Vim has been compiled without the |+modify_fname|
|
These are not available when Vim has been compiled without the |+modify_fname|
|
||||||
|
@ -6053,6 +6053,7 @@ os2 OS/2 version of Vim.
|
|||||||
osfiletype Compiled with support for osfiletypes |+osfiletype|
|
osfiletype Compiled with support for osfiletypes |+osfiletype|
|
||||||
path_extra Compiled with up/downwards search in 'path' and 'tags'
|
path_extra Compiled with up/downwards search in 'path' and 'tags'
|
||||||
perl Compiled with Perl interface.
|
perl Compiled with Perl interface.
|
||||||
|
persistent_undo Compiled with support for persistent undo history.
|
||||||
postscript Compiled with PostScript file printing.
|
postscript Compiled with PostScript file printing.
|
||||||
printer Compiled with |:hardcopy| support.
|
printer Compiled with |:hardcopy| support.
|
||||||
profile Compiled with |:profile| support.
|
profile Compiled with |:profile| support.
|
||||||
|
@ -7220,6 +7220,33 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
global
|
global
|
||||||
Alias for 'term', see above.
|
Alias for 'term', see above.
|
||||||
|
|
||||||
|
*'undodir'* *'udir'*
|
||||||
|
'undodir' 'udir' string (default ".")
|
||||||
|
global
|
||||||
|
{not in Vi}
|
||||||
|
{only when compiled with the +persistent_undo feature}
|
||||||
|
List of directory names for undo files, separated with commas.
|
||||||
|
See |'backupdir'| for the format. Specifically, "." means using the
|
||||||
|
directory of the file.
|
||||||
|
When writing: The first directory that exists is used. "." always
|
||||||
|
works, no directories after "." will be used for writing.
|
||||||
|
When reading all entries are tried to find an undo file. The first
|
||||||
|
undo file that exists is used. When it cannot be read an error is
|
||||||
|
given, no further entry is used.
|
||||||
|
See |undo-persistence|.
|
||||||
|
|
||||||
|
*'undofile'* *'udf'*
|
||||||
|
'undofile' 'udf' boolean (default off)
|
||||||
|
local to buffer
|
||||||
|
{not in Vi}
|
||||||
|
{only when compiled with the +persistent_undo feature}
|
||||||
|
When on, Vim automatically saves undo history to an undo file when
|
||||||
|
writing a buffer to a file, and restores undo history from the same
|
||||||
|
file on buffer read.
|
||||||
|
The name of the undo file is specified by 'undodir'.
|
||||||
|
See |undo-persistence|.
|
||||||
|
WARNING: this is a very new feature. Use at your own risc!
|
||||||
|
|
||||||
*'undolevels'* *'ul'*
|
*'undolevels'* *'ul'*
|
||||||
'undolevels' 'ul' number (default 100, 1000 for Unix, VMS,
|
'undolevels' 'ul' number (default 100, 1000 for Unix, VMS,
|
||||||
Win32 and OS/2)
|
Win32 and OS/2)
|
||||||
|
@ -10,6 +10,16 @@ $VIM starting.txt /*$VIM*
|
|||||||
$VIM-use version5.txt /*$VIM-use*
|
$VIM-use version5.txt /*$VIM-use*
|
||||||
$VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
$VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
||||||
% motion.txt /*%*
|
% motion.txt /*%*
|
||||||
|
%:. cmdline.txt /*%:.*
|
||||||
|
%:8 cmdline.txt /*%:8*
|
||||||
|
%:e cmdline.txt /*%:e*
|
||||||
|
%:gs cmdline.txt /*%:gs*
|
||||||
|
%:h cmdline.txt /*%:h*
|
||||||
|
%:p cmdline.txt /*%:p*
|
||||||
|
%:r cmdline.txt /*%:r*
|
||||||
|
%:s cmdline.txt /*%:s*
|
||||||
|
%:t cmdline.txt /*%:t*
|
||||||
|
%:~ cmdline.txt /*%:~*
|
||||||
& change.txt /*&*
|
& change.txt /*&*
|
||||||
' motion.txt /*'*
|
' motion.txt /*'*
|
||||||
'' motion.txt /*''*
|
'' motion.txt /*''*
|
||||||
@ -1005,7 +1015,11 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
|||||||
'tw' options.txt /*'tw'*
|
'tw' options.txt /*'tw'*
|
||||||
'tx' options.txt /*'tx'*
|
'tx' options.txt /*'tx'*
|
||||||
'uc' options.txt /*'uc'*
|
'uc' options.txt /*'uc'*
|
||||||
|
'udf' options.txt /*'udf'*
|
||||||
|
'udir' options.txt /*'udir'*
|
||||||
'ul' options.txt /*'ul'*
|
'ul' options.txt /*'ul'*
|
||||||
|
'undodir' options.txt /*'undodir'*
|
||||||
|
'undofile' options.txt /*'undofile'*
|
||||||
'undolevels' options.txt /*'undolevels'*
|
'undolevels' options.txt /*'undolevels'*
|
||||||
'updatecount' options.txt /*'updatecount'*
|
'updatecount' options.txt /*'updatecount'*
|
||||||
'updatetime' options.txt /*'updatetime'*
|
'updatetime' options.txt /*'updatetime'*
|
||||||
@ -1163,6 +1177,7 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
|||||||
+path_extra various.txt /*+path_extra*
|
+path_extra various.txt /*+path_extra*
|
||||||
+perl various.txt /*+perl*
|
+perl various.txt /*+perl*
|
||||||
+perl/dyn various.txt /*+perl\/dyn*
|
+perl/dyn various.txt /*+perl\/dyn*
|
||||||
|
+persistent_undo various.txt /*+persistent_undo*
|
||||||
+postscript various.txt /*+postscript*
|
+postscript various.txt /*+postscript*
|
||||||
+printer various.txt /*+printer*
|
+printer various.txt /*+printer*
|
||||||
+profile various.txt /*+profile*
|
+profile various.txt /*+profile*
|
||||||
@ -2582,6 +2597,7 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
|||||||
:rubydo if_ruby.txt /*:rubydo*
|
:rubydo if_ruby.txt /*:rubydo*
|
||||||
:rubyf if_ruby.txt /*:rubyf*
|
:rubyf if_ruby.txt /*:rubyf*
|
||||||
:rubyfile if_ruby.txt /*:rubyfile*
|
:rubyfile if_ruby.txt /*:rubyfile*
|
||||||
|
:rundo undo.txt /*:rundo*
|
||||||
:runtime repeat.txt /*:runtime*
|
:runtime repeat.txt /*:runtime*
|
||||||
:rv starting.txt /*:rv*
|
:rv starting.txt /*:rv*
|
||||||
:rviminfo starting.txt /*:rviminfo*
|
:rviminfo starting.txt /*:rviminfo*
|
||||||
@ -2964,6 +2980,7 @@ $VIMRUNTIME starting.txt /*$VIMRUNTIME*
|
|||||||
:write_f editing.txt /*:write_f*
|
:write_f editing.txt /*:write_f*
|
||||||
:ws workshop.txt /*:ws*
|
:ws workshop.txt /*:ws*
|
||||||
:wsverb workshop.txt /*:wsverb*
|
:wsverb workshop.txt /*:wsverb*
|
||||||
|
:wundo undo.txt /*:wundo*
|
||||||
:wv starting.txt /*:wv*
|
:wv starting.txt /*:wv*
|
||||||
:wviminfo starting.txt /*:wviminfo*
|
:wviminfo starting.txt /*:wviminfo*
|
||||||
:x editing.txt /*:x*
|
:x editing.txt /*:x*
|
||||||
@ -6913,6 +6930,7 @@ perl-overview if_perl.txt /*perl-overview*
|
|||||||
perl-patterns pattern.txt /*perl-patterns*
|
perl-patterns pattern.txt /*perl-patterns*
|
||||||
perl-using if_perl.txt /*perl-using*
|
perl-using if_perl.txt /*perl-using*
|
||||||
perl.vim syntax.txt /*perl.vim*
|
perl.vim syntax.txt /*perl.vim*
|
||||||
|
persistent-undo undo.txt /*persistent-undo*
|
||||||
pexpr-option print.txt /*pexpr-option*
|
pexpr-option print.txt /*pexpr-option*
|
||||||
pfn-option print.txt /*pfn-option*
|
pfn-option print.txt /*pfn-option*
|
||||||
pheader-option print.txt /*pheader-option*
|
pheader-option print.txt /*pheader-option*
|
||||||
@ -7835,6 +7853,7 @@ undo undo.txt /*undo*
|
|||||||
undo-blocks undo.txt /*undo-blocks*
|
undo-blocks undo.txt /*undo-blocks*
|
||||||
undo-branches undo.txt /*undo-branches*
|
undo-branches undo.txt /*undo-branches*
|
||||||
undo-commands undo.txt /*undo-commands*
|
undo-commands undo.txt /*undo-commands*
|
||||||
|
undo-persistence undo.txt /*undo-persistence*
|
||||||
undo-redo undo.txt /*undo-redo*
|
undo-redo undo.txt /*undo-redo*
|
||||||
undo-remarks undo.txt /*undo-remarks*
|
undo-remarks undo.txt /*undo-remarks*
|
||||||
undo-tree undo.txt /*undo-tree*
|
undo-tree undo.txt /*undo-tree*
|
||||||
|
@ -30,6 +30,9 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
|
|||||||
*known-bugs*
|
*known-bugs*
|
||||||
-------------------- Known bugs and current work -----------------------
|
-------------------- Known bugs and current work -----------------------
|
||||||
|
|
||||||
|
When Vim crashes it may run out of stack while executing autocommands. Patch
|
||||||
|
to not run autocommands when leaving Vim? (James Vega, 2010 May 23)
|
||||||
|
|
||||||
Cursor positioning wrong with 0x200e character. (John Becket, 2010 May 6)
|
Cursor positioning wrong with 0x200e character. (John Becket, 2010 May 6)
|
||||||
|
|
||||||
E315 when trying to change a file in FileChangedRO autocommand event.
|
E315 when trying to change a file in FileChangedRO autocommand event.
|
||||||
@ -1082,6 +1085,18 @@ restored. (Luc St-Louis)
|
|||||||
|
|
||||||
Vim 7.3:
|
Vim 7.3:
|
||||||
Patches to include:
|
Patches to include:
|
||||||
|
8 Persistent undo bugs / fixes:
|
||||||
|
- Add tests. Also with different 'enc'
|
||||||
|
- Add undofile(name): get undo file name for buffer "name".
|
||||||
|
- Extend test62 for gettabvar() and settabvar(). (Yegappan Lakshmanan, 2010
|
||||||
|
May 23)
|
||||||
|
- Also crypt the undo file.
|
||||||
|
- Also crypt the swap file, each block separately. Change mf_write() and
|
||||||
|
mf_read(). How to get b_p_key to these functions?
|
||||||
|
- Do profiling on sha256 code to find obvious bottlenecks.
|
||||||
|
- Do profiling on crypt code to find obvious bottlenecks.
|
||||||
|
- Use off_t instead of long for bytes in a buffer. (James Vega, 2010 May 22,
|
||||||
|
update next day)
|
||||||
- Include conceal patch?
|
- Include conceal patch?
|
||||||
http://vince.negri.googlepages.com/
|
http://vince.negri.googlepages.com/
|
||||||
http://vim.wikia.com/wiki/Patch_to_conceal_parts_of_lines
|
http://vim.wikia.com/wiki/Patch_to_conceal_parts_of_lines
|
||||||
@ -1150,42 +1165,17 @@ Needs some work:
|
|||||||
Needs some more testing.
|
Needs some more testing.
|
||||||
Update 2010 Apr 20, patch by Andy Kittner, May 16
|
Update 2010 Apr 20, patch by Andy Kittner, May 16
|
||||||
- Easier/standard way to disable default plugins.
|
- Easier/standard way to disable default plugins.
|
||||||
8 Persistent undo: store undo in a file. Patch by Jordan Lewis, 2009 Feb
|
|
||||||
20. Repost 2009 Nov 16.
|
|
||||||
Get tar file from: http://repo.or.cz/w/vim_extended.git/tree/feat/persistent-undo
|
|
||||||
-> disable by default and add remark that it's new and may fail.
|
|
||||||
Testing remarks by Christian Brabandt, 2010 May 1:
|
|
||||||
- doesn't work well with symlinks (Jordan will look into it)
|
|
||||||
- old undo files tend to pile up
|
|
||||||
- :rundo should output a message (Jordan will fix this)
|
|
||||||
Bugs / fixes:
|
|
||||||
- Undo file should be stored with the original file by default, the undo
|
|
||||||
directory doesn't handle remote files or directory renames.
|
|
||||||
Use same mechanism as for swap files? But only with one file name.
|
|
||||||
- Read coladd depending on FEAT_VIRTUALEDIT, should always read/write it
|
|
||||||
- invoke u_wundo() inside buf_write()
|
|
||||||
- invoke u_rundo() inside readfile()
|
|
||||||
- Document that ":wundo" and ":rundo" should only be used in autocommands.
|
|
||||||
- unserialize_pos() does not need a return value
|
|
||||||
- function comments go before the function, not inside
|
|
||||||
- u_get_undofile() changes its argument ffname
|
|
||||||
- make magic four bytes.
|
|
||||||
- errors need numbers "E000:"
|
|
||||||
- also put 'enc' in undo file.
|
|
||||||
- don't use timestamp, "touch file" or dir copy may change it and undo
|
|
||||||
still works.
|
|
||||||
Older ideas:
|
|
||||||
- Use timestamps, so that a version a certain time ago can be found and
|
|
||||||
info before some time/date can be flushed. 'undopersist' gives maximum
|
|
||||||
time to keep undo: "3h", "1d", "2w", "1y", etc. For the file use dot
|
|
||||||
and extension: ".filename.un~" (like swapfile but "un~" instead of
|
|
||||||
"swp").
|
|
||||||
- ":{range}source": source the lines from the current file.
|
- ":{range}source": source the lines from the current file.
|
||||||
You can already yank lines and use :@" to execute them.
|
You can already yank lines and use :@" to execute them.
|
||||||
Most of do_source() would not be used, need a new function.
|
Most of do_source() would not be used, need a new function.
|
||||||
It's easy when not doing breakpoints or profiling.
|
It's easy when not doing breakpoints or profiling.
|
||||||
|
Probably not now:
|
||||||
|
- Use timestamps for undo, so that a version a certain time ago can be found
|
||||||
|
and info before some time/date can be flushed. 'undopersist' gives maximum
|
||||||
|
time to keep undo: "3h", "1d", "2w", "1y", etc.
|
||||||
Before (beta) release:
|
Before (beta) release:
|
||||||
- Add fixes for 7.2 to version7.txt
|
- Add fixes for 7.2 to version7.txt
|
||||||
|
- Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23)
|
||||||
|
|
||||||
|
|
||||||
More patches:
|
More patches:
|
||||||
@ -1292,7 +1282,6 @@ Awaiting updated patches:
|
|||||||
to left as well? See patch of Dec 26. (Nadim Shaikli)
|
to left as well? See patch of Dec 26. (Nadim Shaikli)
|
||||||
8 Option to lock all used memory so that it doesn't get swapped to disk
|
8 Option to lock all used memory so that it doesn't get swapped to disk
|
||||||
(uncrypted). Patch by Jason Holt, 2003 May 23. Uses mlock.
|
(uncrypted). Patch by Jason Holt, 2003 May 23. Uses mlock.
|
||||||
7 Support a stronger encryption. Jason Holt implemented AES (May 6 2003).
|
|
||||||
7 Add ! register, for shell commands. (patch from Grenie)
|
7 Add ! register, for shell commands. (patch from Grenie)
|
||||||
8 In the gzip plugin, also recognize *.gz.orig, *.gz.bak, etc. Like it's
|
8 In the gzip plugin, also recognize *.gz.orig, *.gz.bak, etc. Like it's
|
||||||
done for filetype detection. Patch from Walter Briscoe, 2003 Jul 1.
|
done for filetype detection. Patch from Walter Briscoe, 2003 Jul 1.
|
||||||
@ -4320,11 +4309,6 @@ Mouse support:
|
|||||||
- When mouse click after 'r' command, get character that was pointed to.
|
- When mouse click after 'r' command, get character that was pointed to.
|
||||||
|
|
||||||
|
|
||||||
Crypt and security:
|
|
||||||
8 Also crypt the swapfile, each block separately. Change mf_write() and
|
|
||||||
mf_read(). How to get b_p_key to these functions?
|
|
||||||
|
|
||||||
|
|
||||||
Argument list:
|
Argument list:
|
||||||
6 Add command to put all filenames from the tag files in the argument list.
|
6 Add command to put all filenames from the tag files in the argument list.
|
||||||
When given an argument, only use the files where that argument matches
|
When given an argument, only use the files where that argument matches
|
||||||
|
@ -12,7 +12,8 @@ The basics are explained in section |02.5| of the user manual.
|
|||||||
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. Undo branches |undo-branches|
|
4. Undo branches |undo-branches|
|
||||||
5. Remarks about undo |undo-remarks|
|
5. Undo persistence |undo-persistence|
|
||||||
|
6. Remarks about undo |undo-remarks|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
1. Undo and redo commands *undo-commands*
|
1. Undo and redo commands *undo-commands*
|
||||||
@ -22,7 +23,7 @@ u Undo [count] changes. {Vi: only one level}
|
|||||||
|
|
||||||
*:u* *:un* *:undo*
|
*:u* *:un* *:undo*
|
||||||
:u[ndo] Undo one change. {Vi: only one level}
|
:u[ndo] Undo one change. {Vi: only one level}
|
||||||
|
*E830*
|
||||||
:u[ndo] {N} Jump to after change number {N}. See |undo-branches|
|
:u[ndo] {N} Jump to after change number {N}. See |undo-branches|
|
||||||
for the meaning of {N}. {not in Vi}
|
for the meaning of {N}. {not in Vi}
|
||||||
|
|
||||||
@ -109,6 +110,8 @@ change.
|
|||||||
To do the opposite, break a change into two undo blocks, in Insert mode use
|
To do the opposite, break a change into two undo blocks, in Insert mode use
|
||||||
CTRL-G u. This is useful if you want an insert command to be undoable in
|
CTRL-G u. This is useful if you want an insert command to be undoable in
|
||||||
parts. E.g., for each sentence. |i_CTRL-G_u|
|
parts. E.g., for each sentence. |i_CTRL-G_u|
|
||||||
|
Setting the value of 'undolevels' also breaks undo. Even when the new value
|
||||||
|
is equal to the old value.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
4. Undo branches *undo-branches* *undo-tree*
|
4. Undo branches *undo-branches* *undo-tree*
|
||||||
@ -201,7 +204,88 @@ Note that using "u" and CTRL-R will not get you to all possible text states
|
|||||||
while repeating "g-" and "g+" does.
|
while repeating "g-" and "g+" does.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
5. Remarks about undo *undo-remarks*
|
5. Undo persistence *undo-persistence* *persistent-undo*
|
||||||
|
|
||||||
|
When unloading a buffer Vim normally destroys the tree of undos created for
|
||||||
|
that buffer. By setting the 'undofile' option, Vim will automatically save
|
||||||
|
your undo history when you write a file and restore undo history when you edit
|
||||||
|
the file again.
|
||||||
|
|
||||||
|
The 'undofile' option is checked after writing a file, before the BufWritePost
|
||||||
|
autocommands. If you want to control what files to write undo information
|
||||||
|
for, you can use a BufWritePre autocommand: >
|
||||||
|
au BufWritePre /tmp/* setlocal noundofile
|
||||||
|
|
||||||
|
Vim saves undo trees in a separate undo file, one for each edited file, using
|
||||||
|
a simple scheme that maps filesystem paths directly to undo files. Vim will
|
||||||
|
detect if an undo file is no longer synchronized with the file it was written
|
||||||
|
for (with a hash of the file contents) and ignore it when the file was changed
|
||||||
|
after the undo file was written, to prevent corruption.
|
||||||
|
|
||||||
|
Undo files are normally saved in the same directory as the file. This can be
|
||||||
|
changed with the 'undodir' option.
|
||||||
|
|
||||||
|
You can also save and restore undo histories by using ":wundo" and ":rundo"
|
||||||
|
respectively:
|
||||||
|
*:wundo* *:rundo*
|
||||||
|
:wundo[!] {file}
|
||||||
|
Write undo history to {file}.
|
||||||
|
When {file} exists and it does not look like an undo file
|
||||||
|
(the magic number at the start of the file is wrong), then
|
||||||
|
this fails, unless the ! was added.
|
||||||
|
If it exists and does look like an undo file it is
|
||||||
|
overwritten.
|
||||||
|
{not in Vi}
|
||||||
|
|
||||||
|
:rundo {file} Read undo history from {file}.
|
||||||
|
{not in Vi}
|
||||||
|
|
||||||
|
You can use these in autocommands to explicitly specify the name of the
|
||||||
|
history file. E.g.: >
|
||||||
|
|
||||||
|
au BufReadPost * rundo %:h/UNDO/%:t
|
||||||
|
au BufWritePost * wundo %:h/UNDO/%:t
|
||||||
|
|
||||||
|
You should keep 'undofile' off, otherwise you end up with two undo files for
|
||||||
|
every write.
|
||||||
|
Note: I did not verify this always works!
|
||||||
|
|
||||||
|
Note that while reading/writing files and 'undofile' is set most errors will
|
||||||
|
be silent, unless 'verbose' is set. With :wundo and :rundo you will get more
|
||||||
|
error messages, e.g., when the file cannot be read or written.
|
||||||
|
|
||||||
|
NOTE: undo files are never deleted by Vim. You need to delete them yourself.
|
||||||
|
|
||||||
|
Reading an existing undo file may fail for several reasons:
|
||||||
|
*E822* It cannot be opened, because the file permissions don't allow it.
|
||||||
|
*E823* The magic number at the start of the file doesn't match. This usually
|
||||||
|
means it is not an undo file.
|
||||||
|
*E824* The version number of the undo file indicates that it's written by a
|
||||||
|
newer version of Vim. You need that newer version to open it. Don't
|
||||||
|
write the buffer if you want to keep the undo info in the file.
|
||||||
|
"Undo file contents changed"
|
||||||
|
The file text differs from when the undo file was written. This means
|
||||||
|
the undo file cannot be used, it would corrupt the text.
|
||||||
|
*E825* *E826* The undo file does not contain valid contents and cannot be
|
||||||
|
used.
|
||||||
|
*E827* The magic number at the end of the file was not found. This usually
|
||||||
|
means the file was truncated.
|
||||||
|
|
||||||
|
Writing an undo file may fail for these reasons:
|
||||||
|
*E828* The file to be written cannot be created. Perhaps you do not have
|
||||||
|
write permissions in the directory.
|
||||||
|
"Will not overwrite with undo file, cannot read"
|
||||||
|
A file exists with the name of the undo file to be written, but it
|
||||||
|
cannot be read. You may want to delete this file or rename it.
|
||||||
|
"Will not overwrite, this is not an undo file"
|
||||||
|
A file exists with the name of the undo file to be written, but it
|
||||||
|
does not start with the right magic number. You may want to delete
|
||||||
|
this file or rename it.
|
||||||
|
*E829* An error occurred while writing the undo file. You may want to try
|
||||||
|
again.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
6. 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
|
||||||
|
@ -359,6 +359,7 @@ m *+ole* Win32 GUI only: |ole-interface|
|
|||||||
N *+path_extra* Up/downwards search in 'path' and 'tags'
|
N *+path_extra* Up/downwards search in 'path' and 'tags'
|
||||||
m *+perl* Perl interface |perl|
|
m *+perl* Perl interface |perl|
|
||||||
m *+perl/dyn* Perl interface |perl-dynamic| |/dyn|
|
m *+perl/dyn* Perl interface |perl-dynamic| |/dyn|
|
||||||
|
H *+persistent_undo* Persistent undo |undo-persistence|
|
||||||
*+postscript* |:hardcopy| writes a PostScript file
|
*+postscript* |:hardcopy| writes a PostScript file
|
||||||
N *+printer* |:hardcopy| command
|
N *+printer* |:hardcopy| command
|
||||||
H *+profile* |:profile| command
|
H *+profile* |:profile| command
|
||||||
|
@ -7170,6 +7170,10 @@ the buffer is marked as modified.
|
|||||||
Added *added-7.3*
|
Added *added-7.3*
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
Persistent undo: store undo information in a file. Can undo to before when
|
||||||
|
the file was read, also for unloaded buffers. |undo-persistence|
|
||||||
|
(partly by Jordan Lewis)
|
||||||
|
|
||||||
Added the 'relativenumber' option. (Markus Heidelberg)
|
Added the 'relativenumber' option. (Markus Heidelberg)
|
||||||
|
|
||||||
Support for Blowfish encryption. Added the 'cryptmethod' option.
|
Support for Blowfish encryption. Added the 'cryptmethod' option.
|
||||||
|
@ -1032,6 +1032,10 @@ if has("vertsplit")
|
|||||||
call append("$", "cmdwinheight\theight of the command-line window")
|
call append("$", "cmdwinheight\theight of the command-line window")
|
||||||
call <SID>OptionG("cwh", &cwh)
|
call <SID>OptionG("cwh", &cwh)
|
||||||
endif
|
endif
|
||||||
|
call append("$", "undofile\tautomatically save and restore undo history")
|
||||||
|
call <SID>BinOptionG("udf", &udf)
|
||||||
|
call append("$", "undodir\tlist of directories for undo files")
|
||||||
|
call <SID>OptionG("udir", &udir)
|
||||||
|
|
||||||
|
|
||||||
call <SID>Header("executing external commands")
|
call <SID>Header("executing external commands")
|
||||||
|
@ -288,7 +288,7 @@ NOTA: Se batti solo il movimento mentre sei in Modalit
|
|||||||
|
|
||||||
2. Batti d2w per cancellare le due parole MAIUSCOLE
|
2. Batti d2w per cancellare le due parole MAIUSCOLE
|
||||||
|
|
||||||
3. Ripeti i passi 1 e 2 con un contatore diverso per cancellare la parole
|
3. Ripeti i passi 1 e 2 con un contatore diverso per cancellare le parole
|
||||||
MAIUSCOLE consecutive con un solo comando
|
MAIUSCOLE consecutive con un solo comando
|
||||||
|
|
||||||
---> questa ABC DE linea FGHI JK LMN OP di parole è Q RS TUV ora ripulita.
|
---> questa ABC DE linea FGHI JK LMN OP di parole è Q RS TUV ora ripulita.
|
||||||
|
@ -288,7 +288,7 @@ NOTA: Se batti solo il movimento mentre sei in Modalità Normale, senza
|
|||||||
|
|
||||||
2. Batti d2w per cancellare le due parole MAIUSCOLE
|
2. Batti d2w per cancellare le due parole MAIUSCOLE
|
||||||
|
|
||||||
3. Ripeti i passi 1 e 2 con un contatore diverso per cancellare la parole
|
3. Ripeti i passi 1 e 2 con un contatore diverso per cancellare le parole
|
||||||
MAIUSCOLE consecutive con un solo comando
|
MAIUSCOLE consecutive con un solo comando
|
||||||
|
|
||||||
---> questa ABC DE linea FGHI JK LMN OP di parole è Q RS TUV ora ripulita.
|
---> questa ABC DE linea FGHI JK LMN OP di parole è Q RS TUV ora ripulita.
|
||||||
|
@ -61,8 +61,9 @@ static void buf_delete_signs __ARGS((buf_T *buf));
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open current buffer, that is: open the memfile and read the file into memory
|
* Open current buffer, that is: open the memfile and read the file into
|
||||||
* return FAIL for failure, OK otherwise
|
* memory.
|
||||||
|
* Return FAIL for failure, OK otherwise.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
open_buffer(read_stdin, eap)
|
open_buffer(read_stdin, eap)
|
||||||
|
@ -11869,6 +11869,9 @@ f_has(argvars, rettv)
|
|||||||
"perl",
|
"perl",
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
"persistent_undo",
|
||||||
|
#endif
|
||||||
#ifdef FEAT_PYTHON
|
#ifdef FEAT_PYTHON
|
||||||
#ifndef DYNAMIC_PYTHON
|
#ifndef DYNAMIC_PYTHON
|
||||||
"python",
|
"python",
|
||||||
|
@ -773,6 +773,8 @@ EX(CMD_rubydo, "rubydo", ex_rubydo,
|
|||||||
RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN),
|
RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN),
|
||||||
EX(CMD_rubyfile, "rubyfile", ex_rubyfile,
|
EX(CMD_rubyfile, "rubyfile", ex_rubyfile,
|
||||||
RANGE|FILE1|NEEDARG|CMDWIN),
|
RANGE|FILE1|NEEDARG|CMDWIN),
|
||||||
|
EX(CMD_rundo, "rundo", ex_rundo,
|
||||||
|
NEEDARG|EXTRA|XFILE),
|
||||||
EX(CMD_rviminfo, "rviminfo", ex_viminfo,
|
EX(CMD_rviminfo, "rviminfo", ex_viminfo,
|
||||||
BANG|FILE1|TRLBAR|CMDWIN),
|
BANG|FILE1|TRLBAR|CMDWIN),
|
||||||
EX(CMD_substitute, "substitute", do_sub,
|
EX(CMD_substitute, "substitute", do_sub,
|
||||||
@ -1061,6 +1063,8 @@ EX(CMD_wqall, "wqall", do_wqall,
|
|||||||
BANG|FILE1|ARGOPT|DFLALL|TRLBAR),
|
BANG|FILE1|ARGOPT|DFLALL|TRLBAR),
|
||||||
EX(CMD_wsverb, "wsverb", ex_wsverb,
|
EX(CMD_wsverb, "wsverb", ex_wsverb,
|
||||||
EXTRA|NOTADR|NEEDARG),
|
EXTRA|NOTADR|NEEDARG),
|
||||||
|
EX(CMD_wundo, "wundo", ex_wundo,
|
||||||
|
BANG|NEEDARG|EXTRA|XFILE),
|
||||||
EX(CMD_wviminfo, "wviminfo", ex_viminfo,
|
EX(CMD_wviminfo, "wviminfo", ex_viminfo,
|
||||||
BANG|FILE1|TRLBAR|CMDWIN),
|
BANG|FILE1|TRLBAR|CMDWIN),
|
||||||
EX(CMD_xit, "xit", ex_exit,
|
EX(CMD_xit, "xit", ex_exit,
|
||||||
|
@ -243,6 +243,10 @@ static void ex_popup __ARGS((exarg_T *eap));
|
|||||||
# define ex_spellinfo ex_ni
|
# define ex_spellinfo ex_ni
|
||||||
# define ex_spellrepall ex_ni
|
# define ex_spellrepall ex_ni
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef FEAT_PERSISTENT_UNDO
|
||||||
|
# define ex_rundo ex_ni
|
||||||
|
# define ex_wundo ex_ni
|
||||||
|
#endif
|
||||||
#ifndef FEAT_MZSCHEME
|
#ifndef FEAT_MZSCHEME
|
||||||
# define ex_mzscheme ex_script_ni
|
# define ex_mzscheme ex_script_ni
|
||||||
# define ex_mzfile ex_ni
|
# define ex_mzfile ex_ni
|
||||||
@ -298,6 +302,10 @@ static void ex_join __ARGS((exarg_T *eap));
|
|||||||
static void ex_at __ARGS((exarg_T *eap));
|
static void ex_at __ARGS((exarg_T *eap));
|
||||||
static void ex_bang __ARGS((exarg_T *eap));
|
static void ex_bang __ARGS((exarg_T *eap));
|
||||||
static void ex_undo __ARGS((exarg_T *eap));
|
static void ex_undo __ARGS((exarg_T *eap));
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
static void ex_wundo __ARGS((exarg_T *eap));
|
||||||
|
static void ex_rundo __ARGS((exarg_T *eap));
|
||||||
|
#endif
|
||||||
static void ex_redo __ARGS((exarg_T *eap));
|
static void ex_redo __ARGS((exarg_T *eap));
|
||||||
static void ex_later __ARGS((exarg_T *eap));
|
static void ex_later __ARGS((exarg_T *eap));
|
||||||
static void ex_redir __ARGS((exarg_T *eap));
|
static void ex_redir __ARGS((exarg_T *eap));
|
||||||
@ -8452,6 +8460,28 @@ ex_undo(eap)
|
|||||||
u_undo(1);
|
u_undo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
void
|
||||||
|
ex_wundo(eap)
|
||||||
|
exarg_T *eap;
|
||||||
|
{
|
||||||
|
char_u hash[UNDO_HASH_SIZE];
|
||||||
|
|
||||||
|
u_compute_hash(hash);
|
||||||
|
u_write_undo(eap->arg, eap->forceit, curbuf, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ex_rundo(eap)
|
||||||
|
exarg_T *eap;
|
||||||
|
{
|
||||||
|
char_u hash[UNDO_HASH_SIZE];
|
||||||
|
|
||||||
|
u_compute_hash(hash);
|
||||||
|
u_read_undo(eap->arg, hash);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":redo".
|
* ":redo".
|
||||||
*/
|
*/
|
||||||
|
@ -1275,3 +1275,11 @@
|
|||||||
|| defined(FEAT_BIG)
|
|| defined(FEAT_BIG)
|
||||||
# define FEAT_AUTOCHDIR
|
# define FEAT_AUTOCHDIR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +persistent_undo 'undofile', 'undodir' options, :wundo and :rundo, and
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
#ifdef FEAT_NORMAL
|
||||||
|
# define FEAT_PERSISTENT_UNDO
|
||||||
|
#endif
|
||||||
|
71
src/fileio.c
71
src/fileio.c
@ -252,6 +252,10 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
|||||||
#ifdef FEAT_CRYPT
|
#ifdef FEAT_CRYPT
|
||||||
char_u *cryptkey = NULL;
|
char_u *cryptkey = NULL;
|
||||||
int did_ask_for_key = FALSE;
|
int did_ask_for_key = FALSE;
|
||||||
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
context_sha256_T sha_ctx;
|
||||||
|
int read_undo_file = FALSE;
|
||||||
#endif
|
#endif
|
||||||
int split = 0; /* number of split lines */
|
int split = 0; /* number of split lines */
|
||||||
#define UNKNOWN 0x0fffffff /* file size is unknown */
|
#define UNKNOWN 0x0fffffff /* file size is unknown */
|
||||||
@ -1177,6 +1181,12 @@ retry:
|
|||||||
read_count = lines_to_read;
|
read_count = lines_to_read;
|
||||||
#ifdef FEAT_MBYTE
|
#ifdef FEAT_MBYTE
|
||||||
conv_restlen = 0;
|
conv_restlen = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
read_undo_file = (newfile && curbuf->b_ffname != NULL && curbuf->b_p_udf
|
||||||
|
&& !filtering && !read_stdin && !read_buffer);
|
||||||
|
if (read_undo_file)
|
||||||
|
sha256_start(&sha_ctx);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2133,6 +2143,10 @@ rewind_retry:
|
|||||||
error = TRUE;
|
error = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
if (read_undo_file)
|
||||||
|
sha256_update(&sha_ctx, line_start, len);
|
||||||
|
#endif
|
||||||
++lnum;
|
++lnum;
|
||||||
if (--read_count == 0)
|
if (--read_count == 0)
|
||||||
{
|
{
|
||||||
@ -2197,6 +2211,10 @@ rewind_retry:
|
|||||||
error = TRUE;
|
error = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
if (read_undo_file)
|
||||||
|
sha256_update(&sha_ctx, line_start, len);
|
||||||
|
#endif
|
||||||
++lnum;
|
++lnum;
|
||||||
if (--read_count == 0)
|
if (--read_count == 0)
|
||||||
{
|
{
|
||||||
@ -2237,11 +2255,17 @@ failed:
|
|||||||
if (set_options)
|
if (set_options)
|
||||||
curbuf->b_p_eol = FALSE;
|
curbuf->b_p_eol = FALSE;
|
||||||
*ptr = NUL;
|
*ptr = NUL;
|
||||||
if (ml_append(lnum, line_start,
|
len = (colnr_T)(ptr - line_start + 1);
|
||||||
(colnr_T)(ptr - line_start + 1), newfile) == FAIL)
|
if (ml_append(lnum, line_start, len, newfile) == FAIL)
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
if (read_undo_file)
|
||||||
|
sha256_update(&sha_ctx, line_start, len);
|
||||||
|
#endif
|
||||||
read_no_eol_lnum = ++lnum;
|
read_no_eol_lnum = ++lnum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_options)
|
if (set_options)
|
||||||
@ -2555,6 +2579,19 @@ failed:
|
|||||||
*/
|
*/
|
||||||
write_no_eol_lnum = read_no_eol_lnum;
|
write_no_eol_lnum = read_no_eol_lnum;
|
||||||
|
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
/*
|
||||||
|
* When opening a new file locate undo info and read it.
|
||||||
|
*/
|
||||||
|
if (read_undo_file)
|
||||||
|
{
|
||||||
|
char_u hash[UNDO_HASH_SIZE];
|
||||||
|
|
||||||
|
sha256_finish(&sha_ctx, hash);
|
||||||
|
u_read_undo(NULL, hash);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FEAT_AUTOCMD
|
#ifdef FEAT_AUTOCMD
|
||||||
if (!read_stdin && !read_buffer)
|
if (!read_stdin && !read_buffer)
|
||||||
{
|
{
|
||||||
@ -3038,6 +3075,10 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
|
|||||||
vim_acl_T acl = NULL; /* ACL copied from original file to
|
vim_acl_T acl = NULL; /* ACL copied from original file to
|
||||||
backup or new file */
|
backup or new file */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
int write_undo_file = FALSE;
|
||||||
|
context_sha256_T sha_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fname == NULL || *fname == NUL) /* safety check */
|
if (fname == NULL || *fname == NUL) /* safety check */
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -4344,6 +4385,14 @@ restore_backup:
|
|||||||
write_info.bw_start_lnum = start;
|
write_info.bw_start_lnum = start;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
write_undo_file = (buf->b_p_udf && overwriting && !append
|
||||||
|
&& !filtering && reset_changed);
|
||||||
|
if (write_undo_file)
|
||||||
|
/* Prepare for computing the hash value of the text. */
|
||||||
|
sha256_start(&sha_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
write_info.bw_len = bufsize;
|
write_info.bw_len = bufsize;
|
||||||
#ifdef HAS_BW_FLAGS
|
#ifdef HAS_BW_FLAGS
|
||||||
write_info.bw_flags = wb_flags;
|
write_info.bw_flags = wb_flags;
|
||||||
@ -4358,6 +4407,10 @@ restore_backup:
|
|||||||
* Keep it fast!
|
* Keep it fast!
|
||||||
*/
|
*/
|
||||||
ptr = ml_get_buf(buf, lnum, FALSE) - 1;
|
ptr = ml_get_buf(buf, lnum, FALSE) - 1;
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
if (write_undo_file)
|
||||||
|
sha256_update(&sha_ctx, ptr + 1, STRLEN(ptr + 1) + 1);
|
||||||
|
#endif
|
||||||
while ((c = *++ptr) != NUL)
|
while ((c = *++ptr) != NUL)
|
||||||
{
|
{
|
||||||
if (c == NL)
|
if (c == NL)
|
||||||
@ -4886,6 +4939,20 @@ nofail:
|
|||||||
}
|
}
|
||||||
msg_scroll = msg_save;
|
msg_scroll = msg_save;
|
||||||
|
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
/*
|
||||||
|
* When writing the whole file and 'undofile' is set, also write the undo
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
if (retval == OK && write_undo_file)
|
||||||
|
{
|
||||||
|
char_u hash[UNDO_HASH_SIZE];
|
||||||
|
|
||||||
|
sha256_finish(&sha_ctx, hash);
|
||||||
|
u_write_undo(NULL, FALSE, buf, hash);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FEAT_AUTOCMD
|
#ifdef FEAT_AUTOCMD
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
if (!should_abort(retval))
|
if (!should_abort(retval))
|
||||||
|
@ -245,9 +245,6 @@ static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
|
|||||||
#ifdef FEAT_BYTEOFF
|
#ifdef FEAT_BYTEOFF
|
||||||
static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
|
static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_READLINK
|
|
||||||
static int resolve_symlink __ARGS((char_u *fname, char_u *buf));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open a new memline for "buf".
|
* Open a new memline for "buf".
|
||||||
@ -3559,7 +3556,7 @@ ml_lineadd(buf, count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_READLINK
|
#if defined(HAVE_READLINK) || defined(PROTO)
|
||||||
/*
|
/*
|
||||||
* Resolve a symlink in the last component of a file name.
|
* Resolve a symlink in the last component of a file name.
|
||||||
* Note that f_resolve() does it for every part of the path, we don't do that
|
* Note that f_resolve() does it for every part of the path, we don't do that
|
||||||
@ -3567,7 +3564,7 @@ ml_lineadd(buf, count)
|
|||||||
* If it worked returns OK and the resolved link in "buf[MAXPATHL]".
|
* If it worked returns OK and the resolved link in "buf[MAXPATHL]".
|
||||||
* Otherwise returns FAIL.
|
* Otherwise returns FAIL.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
resolve_symlink(fname, buf)
|
resolve_symlink(fname, buf)
|
||||||
char_u *fname;
|
char_u *fname;
|
||||||
char_u *buf;
|
char_u *buf;
|
||||||
@ -3862,7 +3859,7 @@ do_swapexists(buf, fname)
|
|||||||
* Returns the name in allocated memory or NULL.
|
* Returns the name in allocated memory or NULL.
|
||||||
*
|
*
|
||||||
* Note: If BASENAMELEN is not correct, you will get error messages for
|
* Note: If BASENAMELEN is not correct, you will get error messages for
|
||||||
* not being able to open the swapfile
|
* not being able to open the swap or undo file
|
||||||
* Note: May trigger SwapExists autocmd, pointers may change!
|
* Note: May trigger SwapExists autocmd, pointers may change!
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
@ -3886,29 +3883,29 @@ findswapname(buf, dirp, old_fname)
|
|||||||
# define CREATE_DUMMY_FILE
|
# define CREATE_DUMMY_FILE
|
||||||
FILE *dummyfd = NULL;
|
FILE *dummyfd = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we start editing a new file, e.g. "test.doc", which resides on an MSDOS
|
* If we start editing a new file, e.g. "test.doc", which resides on an
|
||||||
* compatible filesystem, it is possible that the file "test.doc.swp" which we
|
* MSDOS compatible filesystem, it is possible that the file
|
||||||
* create will be exactly the same file. To avoid this problem we temporarily
|
* "test.doc.swp" which we create will be exactly the same file. To avoid
|
||||||
* create "test.doc".
|
* this problem we temporarily create "test.doc". Don't do this when the
|
||||||
* Don't do this when the check below for a 8.3 file name is used.
|
* check below for a 8.3 file name is used.
|
||||||
*/
|
*/
|
||||||
if (!(buf->b_p_sn || buf->b_shortname) && buf->b_fname != NULL
|
if (!(buf->b_p_sn || buf->b_shortname) && buf->b_fname != NULL
|
||||||
&& mch_getperm(buf->b_fname) < 0)
|
&& mch_getperm(buf->b_fname) < 0)
|
||||||
dummyfd = mch_fopen((char *)buf->b_fname, "w");
|
dummyfd = mch_fopen((char *)buf->b_fname, "w");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Isolate a directory name from *dirp and put it in dir_name.
|
* Isolate a directory name from *dirp and put it in dir_name.
|
||||||
* First allocate some memory to put the directory name in.
|
* First allocate some memory to put the directory name in.
|
||||||
*/
|
*/
|
||||||
dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
|
dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
|
||||||
if (dir_name != NULL)
|
if (dir_name != NULL)
|
||||||
(void)copy_option_part(dirp, dir_name, 31000, ",");
|
(void)copy_option_part(dirp, dir_name, 31000, ",");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we try different names until we find one that does not exist yet
|
* we try different names until we find one that does not exist yet
|
||||||
*/
|
*/
|
||||||
if (dir_name == NULL) /* out of memory */
|
if (dir_name == NULL) /* out of memory */
|
||||||
fname = NULL;
|
fname = NULL;
|
||||||
else
|
else
|
||||||
|
28
src/option.c
28
src/option.c
@ -177,6 +177,9 @@
|
|||||||
#define PV_TS OPT_BUF(BV_TS)
|
#define PV_TS OPT_BUF(BV_TS)
|
||||||
#define PV_TW OPT_BUF(BV_TW)
|
#define PV_TW OPT_BUF(BV_TW)
|
||||||
#define PV_TX OPT_BUF(BV_TX)
|
#define PV_TX OPT_BUF(BV_TX)
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
# define PV_UDF OPT_BUF(BV_UDF)
|
||||||
|
#endif
|
||||||
#define PV_WM OPT_BUF(BV_WM)
|
#define PV_WM OPT_BUF(BV_WM)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -362,6 +365,9 @@ static char_u *p_spl;
|
|||||||
static long p_ts;
|
static long p_ts;
|
||||||
static long p_tw;
|
static long p_tw;
|
||||||
static int p_tx;
|
static int p_tx;
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
static int p_udf;
|
||||||
|
#endif
|
||||||
static long p_wm;
|
static long p_wm;
|
||||||
#ifdef FEAT_KEYMAP
|
#ifdef FEAT_KEYMAP
|
||||||
static char_u *p_keymap;
|
static char_u *p_keymap;
|
||||||
@ -2586,6 +2592,22 @@ static struct vimoption
|
|||||||
{"ttytype", "tty", P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
|
{"ttytype", "tty", P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
|
||||||
(char_u *)&T_NAME, PV_NONE,
|
(char_u *)&T_NAME, PV_NONE,
|
||||||
{(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
|
{(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
|
||||||
|
{"undodir", "udir", P_STRING|P_EXPAND|P_COMMA|P_NODUP|P_SECURE|P_VI_DEF,
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
(char_u *)&p_udir, PV_NONE,
|
||||||
|
{(char_u *)".", (char_u *)0L}
|
||||||
|
#else
|
||||||
|
(char_u *)NULL, PV_NONE,
|
||||||
|
{(char_u *)0L, (char_u *)0L}
|
||||||
|
#endif
|
||||||
|
SCRIPTID_INIT},
|
||||||
|
{"undofile", "udf", P_BOOL|P_VI_DEF|P_VIM,
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
(char_u *)&p_udf, PV_UDF,
|
||||||
|
#else
|
||||||
|
(char_u *)NULL, PV_NONE,
|
||||||
|
#endif
|
||||||
|
{(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
|
||||||
{"undolevels", "ul", P_NUM|P_VI_DEF,
|
{"undolevels", "ul", P_NUM|P_VI_DEF,
|
||||||
(char_u *)&p_ul, PV_NONE,
|
(char_u *)&p_ul, PV_NONE,
|
||||||
{
|
{
|
||||||
@ -9404,6 +9426,9 @@ get_varp(p)
|
|||||||
case PV_TS: return (char_u *)&(curbuf->b_p_ts);
|
case PV_TS: return (char_u *)&(curbuf->b_p_ts);
|
||||||
case PV_TW: return (char_u *)&(curbuf->b_p_tw);
|
case PV_TW: return (char_u *)&(curbuf->b_p_tw);
|
||||||
case PV_TX: return (char_u *)&(curbuf->b_p_tx);
|
case PV_TX: return (char_u *)&(curbuf->b_p_tx);
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
|
||||||
|
#endif
|
||||||
case PV_WM: return (char_u *)&(curbuf->b_p_wm);
|
case PV_WM: return (char_u *)&(curbuf->b_p_wm);
|
||||||
#ifdef FEAT_KEYMAP
|
#ifdef FEAT_KEYMAP
|
||||||
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
|
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
|
||||||
@ -9774,6 +9799,9 @@ buf_copy_options(buf, flags)
|
|||||||
#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
|
#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
|
||||||
buf->b_p_bexpr = empty_option;
|
buf->b_p_bexpr = empty_option;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
buf->b_p_udf = p_udf;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't copy the options set by ex_help(), use the saved values,
|
* Don't copy the options set by ex_help(), use the saved values,
|
||||||
|
@ -815,6 +815,7 @@ static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm"
|
|||||||
# define TTYM_JSBTERM 0x10
|
# define TTYM_JSBTERM 0x10
|
||||||
# define TTYM_PTERM 0x20
|
# define TTYM_PTERM 0x20
|
||||||
#endif
|
#endif
|
||||||
|
EXTERN char_u *p_udir; /* 'undodir' */
|
||||||
EXTERN long p_ul; /* 'undolevels' */
|
EXTERN long p_ul; /* 'undolevels' */
|
||||||
EXTERN long p_uc; /* 'updatecount' */
|
EXTERN long p_uc; /* 'updatecount' */
|
||||||
EXTERN long p_ut; /* 'updatetime' */
|
EXTERN long p_ut; /* 'updatetime' */
|
||||||
@ -1004,6 +1005,7 @@ enum
|
|||||||
, BV_TS
|
, BV_TS
|
||||||
, BV_TW
|
, BV_TW
|
||||||
, BV_TX
|
, BV_TX
|
||||||
|
, BV_UDF
|
||||||
, BV_WM
|
, BV_WM
|
||||||
, BV_COUNT /* must be the last one */
|
, BV_COUNT /* must be the last one */
|
||||||
};
|
};
|
||||||
|
@ -204,7 +204,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DFLT_VDIR
|
#ifndef DFLT_VDIR
|
||||||
# define DFLT_VDIR "$VIM/vimfiles/view" /* default for 'viewdir' */
|
# define DFLT_VDIR "$VIM/vimfiles/view" /* default for 'viewdir' */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DFLT_ERRORFILE "errors.err"
|
#define DFLT_ERRORFILE "errors.err"
|
||||||
|
@ -25,6 +25,7 @@ int ml_delete __ARGS((linenr_T lnum, int message));
|
|||||||
void ml_setmarked __ARGS((linenr_T lnum));
|
void ml_setmarked __ARGS((linenr_T lnum));
|
||||||
linenr_T ml_firstmarked __ARGS((void));
|
linenr_T ml_firstmarked __ARGS((void));
|
||||||
void ml_clearmarked __ARGS((void));
|
void ml_clearmarked __ARGS((void));
|
||||||
|
int resolve_symlink __ARGS((char_u *fname, char_u *buf));
|
||||||
char_u *makeswapname __ARGS((char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name));
|
char_u *makeswapname __ARGS((char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name));
|
||||||
char_u *get_file_in_dir __ARGS((char_u *fname, char_u *dname));
|
char_u *get_file_in_dir __ARGS((char_u *fname, char_u *dname));
|
||||||
void ml_setflags __ARGS((buf_T *buf));
|
void ml_setflags __ARGS((buf_T *buf));
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
/* sha256.c */
|
/* sha256.c */
|
||||||
|
void sha256_start __ARGS((context_sha256_T *ctx));
|
||||||
|
void sha256_update __ARGS((context_sha256_T *ctx, char_u *input, uint32_t length));
|
||||||
|
void sha256_finish __ARGS((context_sha256_T *ctx, char_u digest[32]));
|
||||||
char_u *sha256_key __ARGS((char_u *buf));
|
char_u *sha256_key __ARGS((char_u *buf));
|
||||||
int sha256_self_test __ARGS((void));
|
int sha256_self_test __ARGS((void));
|
||||||
void sha2_seed __ARGS((char_u header[], int header_len));
|
void sha2_seed __ARGS((char_u header[], int header_len));
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, int docount));
|
int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, int docount));
|
||||||
int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, hlf_T *attrp));
|
int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, hlf_T *attrp));
|
||||||
void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen));
|
void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen));
|
||||||
|
int get2c __ARGS((FILE *fd));
|
||||||
|
int get3c __ARGS((FILE *fd));
|
||||||
|
int get4c __ARGS((FILE *fd));
|
||||||
char_u *did_set_spelllang __ARGS((buf_T *buf));
|
char_u *did_set_spelllang __ARGS((buf_T *buf));
|
||||||
void spell_free_all __ARGS((void));
|
void spell_free_all __ARGS((void));
|
||||||
void spell_reload __ARGS((void));
|
void spell_reload __ARGS((void));
|
||||||
int spell_check_msm __ARGS((void));
|
int spell_check_msm __ARGS((void));
|
||||||
void put_bytes __ARGS((FILE *fd, long_u nr, int len));
|
int put_bytes __ARGS((FILE *fd, long_u nr, int len));
|
||||||
void ex_mkspell __ARGS((exarg_T *eap));
|
void ex_mkspell __ARGS((exarg_T *eap));
|
||||||
void ex_spell __ARGS((exarg_T *eap));
|
void ex_spell __ARGS((exarg_T *eap));
|
||||||
void spell_add_word __ARGS((char_u *word, int len, int bad, int idx, int undo));
|
void spell_add_word __ARGS((char_u *word, int len, int bad, int idx, int undo));
|
||||||
|
@ -5,6 +5,9 @@ int u_savesub __ARGS((linenr_T lnum));
|
|||||||
int u_inssub __ARGS((linenr_T lnum));
|
int u_inssub __ARGS((linenr_T lnum));
|
||||||
int u_savedel __ARGS((linenr_T lnum, long nlines));
|
int u_savedel __ARGS((linenr_T lnum, long nlines));
|
||||||
int undo_allowed __ARGS((void));
|
int undo_allowed __ARGS((void));
|
||||||
|
void u_compute_hash __ARGS((char_u *hash));
|
||||||
|
void u_read_undo __ARGS((char_u *name, char_u *hash));
|
||||||
|
void u_write_undo __ARGS((char_u *name, int forceit, buf_T *buf, char_u *hash));
|
||||||
void u_undo __ARGS((int count));
|
void u_undo __ARGS((int count));
|
||||||
void u_redo __ARGS((int count));
|
void u_redo __ARGS((int count));
|
||||||
void undo_time __ARGS((long step, int sec, int absolute));
|
void undo_time __ARGS((long step, int sec, int absolute));
|
||||||
|
27
src/sha256.c
27
src/sha256.c
@ -20,18 +20,9 @@
|
|||||||
|
|
||||||
#include "vim.h"
|
#include "vim.h"
|
||||||
|
|
||||||
#ifdef FEAT_CRYPT
|
#if defined(FEAT_CRYPT) || defined(FEAT_PERSISTENT_UNDO)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
UINT32_T total[2];
|
|
||||||
UINT32_T state[8];
|
|
||||||
char_u buffer[64];
|
|
||||||
} context_sha256_T;
|
|
||||||
|
|
||||||
static void sha256_starts __ARGS((context_sha256_T *ctx));
|
|
||||||
static void sha256_process __ARGS((context_sha256_T *ctx, char_u data[64]));
|
static void sha256_process __ARGS((context_sha256_T *ctx, char_u data[64]));
|
||||||
static void sha256_update __ARGS((context_sha256_T *ctx, char_u *input, UINT32_T length));
|
|
||||||
static void sha256_finish __ARGS((context_sha256_T *ctx, char_u digest[32]));
|
|
||||||
static char_u *sha256_bytes __ARGS((char_u *buf, int buflen));
|
static char_u *sha256_bytes __ARGS((char_u *buf, int buflen));
|
||||||
static unsigned int get_some_time __ARGS((void));
|
static unsigned int get_some_time __ARGS((void));
|
||||||
|
|
||||||
@ -52,8 +43,8 @@ static unsigned int get_some_time __ARGS((void));
|
|||||||
(b)[(i) + 3] = (char_u)((n) ); \
|
(b)[(i) + 3] = (char_u)((n) ); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
sha256_starts(ctx)
|
sha256_start(ctx)
|
||||||
context_sha256_T *ctx;
|
context_sha256_T *ctx;
|
||||||
{
|
{
|
||||||
ctx->total[0] = 0;
|
ctx->total[0] = 0;
|
||||||
@ -203,7 +194,7 @@ sha256_process(ctx, data)
|
|||||||
ctx->state[7] += H;
|
ctx->state[7] += H;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
sha256_update(ctx, input, length)
|
sha256_update(ctx, input, length)
|
||||||
context_sha256_T *ctx;
|
context_sha256_T *ctx;
|
||||||
char_u *input;
|
char_u *input;
|
||||||
@ -250,7 +241,7 @@ static char_u sha256_padding[64] = {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
void
|
||||||
sha256_finish(ctx, digest)
|
sha256_finish(ctx, digest)
|
||||||
context_sha256_T *ctx;
|
context_sha256_T *ctx;
|
||||||
char_u digest[32];
|
char_u digest[32];
|
||||||
@ -296,7 +287,7 @@ sha256_bytes(buf, buflen)
|
|||||||
|
|
||||||
sha256_self_test();
|
sha256_self_test();
|
||||||
|
|
||||||
sha256_starts(&ctx);
|
sha256_start(&ctx);
|
||||||
sha256_update(&ctx, buf, buflen);
|
sha256_update(&ctx, buf, buflen);
|
||||||
sha256_finish(&ctx, sha256sum);
|
sha256_finish(&ctx, sha256sum);
|
||||||
for (j = 0; j < 32; j++)
|
for (j = 0; j < 32; j++)
|
||||||
@ -368,7 +359,7 @@ sha256_self_test()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sha256_starts(&ctx);
|
sha256_start(&ctx);
|
||||||
memset(buf, 'a', 1000);
|
memset(buf, 'a', 1000);
|
||||||
for (j = 0; j < 1000; j++)
|
for (j = 0; j < 1000; j++)
|
||||||
sha256_update(&ctx, (char_u *)buf, 1000);
|
sha256_update(&ctx, (char_u *)buf, 1000);
|
||||||
@ -416,7 +407,7 @@ sha2_seed(header, header_len)
|
|||||||
|
|
||||||
for (i = 0; i < (int)sizeof(random_data) - 1; i++)
|
for (i = 0; i < (int)sizeof(random_data) - 1; i++)
|
||||||
random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff);
|
random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff);
|
||||||
sha256_starts(&ctx);
|
sha256_start(&ctx);
|
||||||
sha256_update(&ctx, (char_u *)random_data, sizeof(random_data));
|
sha256_update(&ctx, (char_u *)random_data, sizeof(random_data));
|
||||||
sha256_finish(&ctx, sha256sum);
|
sha256_finish(&ctx, sha256sum);
|
||||||
|
|
||||||
@ -424,4 +415,4 @@ sha2_seed(header, header_len)
|
|||||||
header[i] = sha256sum[i % sizeof(sha256sum)];
|
header[i] = sha256sum[i % sizeof(sha256sum)];
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* FEAT_CRYPT */
|
#endif /* FEAT_CRYPT || FEAT_PERSISTENT_UNDO */
|
||||||
|
15
src/spell.c
15
src/spell.c
@ -854,9 +854,6 @@ static char_u *spell_enc __ARGS((void));
|
|||||||
static void int_wordlist_spl __ARGS((char_u *fname));
|
static void int_wordlist_spl __ARGS((char_u *fname));
|
||||||
static void spell_load_cb __ARGS((char_u *fname, void *cookie));
|
static void spell_load_cb __ARGS((char_u *fname, void *cookie));
|
||||||
static slang_T *spell_load_file __ARGS((char_u *fname, char_u *lang, slang_T *old_lp, int silent));
|
static slang_T *spell_load_file __ARGS((char_u *fname, char_u *lang, slang_T *old_lp, int silent));
|
||||||
static int get2c __ARGS((FILE *fd));
|
|
||||||
static int get3c __ARGS((FILE *fd));
|
|
||||||
static int get4c __ARGS((FILE *fd));
|
|
||||||
static time_t get8c __ARGS((FILE *fd));
|
static time_t get8c __ARGS((FILE *fd));
|
||||||
static char_u *read_cnt_string __ARGS((FILE *fd, int cnt_bytes, int *lenp));
|
static char_u *read_cnt_string __ARGS((FILE *fd, int cnt_bytes, int *lenp));
|
||||||
static char_u *read_string __ARGS((FILE *fd, int cnt));
|
static char_u *read_string __ARGS((FILE *fd, int cnt));
|
||||||
@ -2988,7 +2985,7 @@ endOK:
|
|||||||
/*
|
/*
|
||||||
* Read 2 bytes from "fd" and turn them into an int, MSB first.
|
* Read 2 bytes from "fd" and turn them into an int, MSB first.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
get2c(fd)
|
get2c(fd)
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
{
|
{
|
||||||
@ -3002,7 +2999,7 @@ get2c(fd)
|
|||||||
/*
|
/*
|
||||||
* Read 3 bytes from "fd" and turn them into an int, MSB first.
|
* Read 3 bytes from "fd" and turn them into an int, MSB first.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
get3c(fd)
|
get3c(fd)
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
{
|
{
|
||||||
@ -3017,7 +3014,7 @@ get3c(fd)
|
|||||||
/*
|
/*
|
||||||
* Read 4 bytes from "fd" and turn them into an int, MSB first.
|
* Read 4 bytes from "fd" and turn them into an int, MSB first.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
get4c(fd)
|
get4c(fd)
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
{
|
{
|
||||||
@ -8018,7 +8015,7 @@ node_equal(n1, n2)
|
|||||||
/*
|
/*
|
||||||
* Write a number to file "fd", MSB first, in "len" bytes.
|
* Write a number to file "fd", MSB first, in "len" bytes.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
put_bytes(fd, nr, len)
|
put_bytes(fd, nr, len)
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
long_u nr;
|
long_u nr;
|
||||||
@ -8027,7 +8024,9 @@ put_bytes(fd, nr, len)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = len - 1; i >= 0; --i)
|
for (i = len - 1; i >= 0; --i)
|
||||||
putc((int)(nr >> (i * 8)), fd);
|
if (putc((int)(nr >> (i * 8)), fd) == EOF)
|
||||||
|
return FAIL;
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -1465,6 +1465,9 @@ struct file_buffer
|
|||||||
char_u *b_p_dict; /* 'dictionary' local value */
|
char_u *b_p_dict; /* 'dictionary' local value */
|
||||||
char_u *b_p_tsr; /* 'thesaurus' local value */
|
char_u *b_p_tsr; /* 'thesaurus' local value */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
int b_p_udf; /* 'undofile' */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* end of buffer options */
|
/* end of buffer options */
|
||||||
|
|
||||||
@ -2392,3 +2395,9 @@ typedef struct
|
|||||||
#define CPT_KIND 2 /* "kind" */
|
#define CPT_KIND 2 /* "kind" */
|
||||||
#define CPT_INFO 3 /* "info" */
|
#define CPT_INFO 3 /* "info" */
|
||||||
#define CPT_COUNT 4 /* Number of entries */
|
#define CPT_COUNT 4 /* Number of entries */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32_T total[2];
|
||||||
|
UINT32_T state[8];
|
||||||
|
char_u buffer[64];
|
||||||
|
} context_sha256_T;
|
||||||
|
@ -69,7 +69,7 @@ test1.out: test1.in
|
|||||||
fi \
|
fi \
|
||||||
else echo $* NO OUTPUT >>test.log; \
|
else echo $* NO OUTPUT >>test.log; \
|
||||||
fi"
|
fi"
|
||||||
#-rm -rf X* test.ok viminfo
|
-rm -rf X* test.ok viminfo
|
||||||
|
|
||||||
test49.out: test49.vim
|
test49.out: test49.vim
|
||||||
|
|
||||||
|
@ -50,6 +50,53 @@ obbbbu:.w >>test.out
|
|||||||
obbbb:set ul=100
|
obbbb:set ul=100
|
||||||
:undojoin
|
:undojoin
|
||||||
occccu:.w >>test.out
|
occccu:.w >>test.out
|
||||||
|
:"
|
||||||
|
:" Test 'undofile': first a simple one-line change.
|
||||||
|
:set nocp ul=100 undofile
|
||||||
|
:e! Xtestfile
|
||||||
|
ggdGithis is one line:set ul=100
|
||||||
|
:s/one/ONE/
|
||||||
|
:set ul=100
|
||||||
|
:w
|
||||||
|
:bwipe!
|
||||||
|
:e Xtestfile
|
||||||
|
u:.w >>test.out
|
||||||
|
:"
|
||||||
|
:" Test 'undofile', change in original file fails check
|
||||||
|
:set noundofile
|
||||||
|
:e! Xtestfile
|
||||||
|
:s/line/Line/
|
||||||
|
:w
|
||||||
|
:set undofile
|
||||||
|
:bwipe!
|
||||||
|
:e Xtestfile
|
||||||
|
u:.w >>test.out
|
||||||
|
:"
|
||||||
|
:" Test 'undofile', add 10 lines, delete 6 lines, undo 3
|
||||||
|
:set undofile
|
||||||
|
ggdGione
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten:set ul=100
|
||||||
|
3Gdd:set ul=100
|
||||||
|
dd:set ul=100
|
||||||
|
dd:set ul=100
|
||||||
|
dd:set ul=100
|
||||||
|
dd:set ul=100
|
||||||
|
dd:set ul=100
|
||||||
|
:w
|
||||||
|
:bwipe!
|
||||||
|
:e Xtestfile
|
||||||
|
uuu:w >>test.out
|
||||||
|
:"
|
||||||
|
:" Rename the undo file so that it gets cleaned up.
|
||||||
|
:call rename(".Xtestfile.un~", "Xtestundo")
|
||||||
:qa!
|
:qa!
|
||||||
ENDTEST
|
ENDTEST
|
||||||
|
|
||||||
|
@ -22,3 +22,12 @@
|
|||||||
123456abc
|
123456abc
|
||||||
aaaa
|
aaaa
|
||||||
aaaa
|
aaaa
|
||||||
|
this is one line
|
||||||
|
this is ONE Line
|
||||||
|
one
|
||||||
|
two
|
||||||
|
six
|
||||||
|
seven
|
||||||
|
eight
|
||||||
|
nine
|
||||||
|
ten
|
||||||
|
803
src/undo.c
803
src/undo.c
@ -99,6 +99,14 @@ 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));
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
|
||||||
|
static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
|
||||||
|
static char_u *u_get_undo_file_name __ARGS((char_u *, int reading));
|
||||||
|
static int serialize_uep __ARGS((u_entry_T *uep, FILE *fp));
|
||||||
|
static void serialize_pos __ARGS((pos_T pos, FILE *fp));
|
||||||
|
static void serialize_visualinfo __ARGS((visualinfo_T info, FILE *fp));
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef U_USE_MALLOC
|
#ifdef U_USE_MALLOC
|
||||||
# define U_FREE_LINE(ptr) vim_free(ptr)
|
# define U_FREE_LINE(ptr) vim_free(ptr)
|
||||||
@ -119,6 +127,8 @@ static long u_newcount, u_oldcount;
|
|||||||
*/
|
*/
|
||||||
static int undo_undoes = FALSE;
|
static int undo_undoes = FALSE;
|
||||||
|
|
||||||
|
static int lastmark = 0;
|
||||||
|
|
||||||
#ifdef U_DEBUG
|
#ifdef U_DEBUG
|
||||||
/*
|
/*
|
||||||
* Check the undo structures for being valid. Print a warning when something
|
* Check the undo structures for being valid. Print a warning when something
|
||||||
@ -652,6 +662,795 @@ nomem:
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
|
||||||
|
# define UF_START_MAGIC 0xfeac /* magic at start of undofile */
|
||||||
|
# define UF_HEADER_MAGIC 0x5fd0 /* magic at start of header */
|
||||||
|
# define UF_END_MAGIC 0xe7aa /* magic after last header */
|
||||||
|
# define UF_VERSION 1 /* 2-byte undofile version number */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE].
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
u_compute_hash(hash)
|
||||||
|
char_u *hash;
|
||||||
|
{
|
||||||
|
context_sha256_T ctx;
|
||||||
|
linenr_T lnum;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
sha256_start(&ctx);
|
||||||
|
for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum)
|
||||||
|
{
|
||||||
|
p = ml_get(lnum);
|
||||||
|
sha256_update(&ctx, p, STRLEN(p) + 1);
|
||||||
|
}
|
||||||
|
sha256_finish(&ctx, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unserialize the pos_T at the current position in fp.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
unserialize_pos(pos, fp)
|
||||||
|
pos_T *pos;
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
pos->lnum = get4c(fp);
|
||||||
|
pos->col = get4c(fp);
|
||||||
|
#ifdef FEAT_VIRTUALEDIT
|
||||||
|
pos->coladd = get4c(fp);
|
||||||
|
#else
|
||||||
|
(void)get4c(fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unserialize the visualinfo_T at the current position in fp.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
unserialize_visualinfo(info, fp)
|
||||||
|
visualinfo_T *info;
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
unserialize_pos(&info->vi_start, fp);
|
||||||
|
unserialize_pos(&info->vi_end, fp);
|
||||||
|
info->vi_mode = get4c(fp);
|
||||||
|
info->vi_curswant = get4c(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return an allocated string of the full path of the target undofile.
|
||||||
|
* When "reading" is TRUE find the file to read, go over all directories in
|
||||||
|
* 'undodir'.
|
||||||
|
* When "reading" is FALSE use the first name where the directory exists.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
u_get_undo_file_name(buf_ffname, reading)
|
||||||
|
char_u *buf_ffname;
|
||||||
|
int reading;
|
||||||
|
{
|
||||||
|
char_u *dirp;
|
||||||
|
char_u dir_name[IOSIZE + 1];
|
||||||
|
char_u *munged_name = NULL;
|
||||||
|
char_u *undo_file_name = NULL;
|
||||||
|
int dir_len;
|
||||||
|
char_u *p;
|
||||||
|
struct stat st;
|
||||||
|
char_u *ffname = buf_ffname;
|
||||||
|
#ifdef HAVE_READLINK
|
||||||
|
char_u fname_buf[MAXPATHL];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ffname == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_READLINK
|
||||||
|
/* Expand symlink in the file name, so that we put the undo file with the
|
||||||
|
* actual file instead of with the symlink. */
|
||||||
|
if (resolve_symlink(ffname, fname_buf) == OK)
|
||||||
|
ffname = fname_buf;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Loop over 'undodir'. When reading find the first file that exists.
|
||||||
|
* When not reading use the first directory that exists or ".". */
|
||||||
|
dirp = p_udir;
|
||||||
|
while (*dirp != NUL)
|
||||||
|
{
|
||||||
|
dir_len = copy_option_part(&dirp, dir_name, IOSIZE, ",");
|
||||||
|
if (dir_len == 1 && dir_name[0] == '.')
|
||||||
|
{
|
||||||
|
/* Use same directory as the ffname,
|
||||||
|
* "dir/name" -> "dir/.name.un~" */
|
||||||
|
undo_file_name = vim_strnsave(ffname, STRLEN(ffname) + 5);
|
||||||
|
if (undo_file_name == NULL)
|
||||||
|
break;
|
||||||
|
p = gettail(undo_file_name);
|
||||||
|
mch_memmove(p + 1, p, STRLEN(p) + 1);
|
||||||
|
*p = '.';
|
||||||
|
STRCAT(p, ".un~");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dir_name[dir_len] = NUL;
|
||||||
|
if (mch_isdir(dir_name))
|
||||||
|
{
|
||||||
|
if (munged_name == NULL)
|
||||||
|
{
|
||||||
|
munged_name = vim_strsave(ffname);
|
||||||
|
if (munged_name == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (p = munged_name; *p != NUL; mb_ptr_adv(p))
|
||||||
|
if (vim_ispathsep(*p))
|
||||||
|
*p = '%';
|
||||||
|
}
|
||||||
|
undo_file_name = concat_fnames(dir_name, munged_name, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When reading check if the file exists. */
|
||||||
|
if (undo_file_name != NULL && (!reading
|
||||||
|
|| mch_stat((char *)undo_file_name, &st) >= 0))
|
||||||
|
break;
|
||||||
|
vim_free(undo_file_name);
|
||||||
|
undo_file_name = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vim_free(munged_name);
|
||||||
|
return undo_file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the undo tree from an undo file.
|
||||||
|
* If "name" is not NULL use it as the undo file name. This also means being
|
||||||
|
* a bit more verbose.
|
||||||
|
* Otherwise use curbuf->b_ffname to generate the undo file name.
|
||||||
|
* "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
u_read_undo(name, hash)
|
||||||
|
char_u *name;
|
||||||
|
char_u *hash;
|
||||||
|
{
|
||||||
|
char_u *file_name;
|
||||||
|
FILE *fp;
|
||||||
|
long magic, version, str_len;
|
||||||
|
char_u *line_ptr = NULL;
|
||||||
|
linenr_T line_lnum;
|
||||||
|
colnr_T line_colnr;
|
||||||
|
linenr_T line_count;
|
||||||
|
int uep_len;
|
||||||
|
int line_len;
|
||||||
|
int num_head;
|
||||||
|
long old_header_seq, new_header_seq, cur_header_seq;
|
||||||
|
long seq_last, seq_cur;
|
||||||
|
short old_idx = -1, new_idx = -1, cur_idx = -1;
|
||||||
|
long num_read_uhps = 0;
|
||||||
|
time_t seq_time;
|
||||||
|
int i, j;
|
||||||
|
int c;
|
||||||
|
short found_first_uep = 0;
|
||||||
|
char_u **array;
|
||||||
|
char_u *line;
|
||||||
|
u_entry_T *uep, *last_uep, *nuep;
|
||||||
|
u_header_T *uhp;
|
||||||
|
u_header_T **uhp_table = NULL;
|
||||||
|
char_u read_hash[UNDO_HASH_SIZE];
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
{
|
||||||
|
file_name = u_get_undo_file_name(curbuf->b_ffname, TRUE);
|
||||||
|
if (file_name == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file_name = name;
|
||||||
|
|
||||||
|
if (p_verbose > 0)
|
||||||
|
smsg((char_u *)_("Reading undo file: %s"), file_name);
|
||||||
|
fp = mch_fopen((char *)file_name, "r");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
if (name != NULL || p_verbose > 0)
|
||||||
|
EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin overall file information */
|
||||||
|
magic = get2c(fp);
|
||||||
|
if (magic != UF_START_MAGIC)
|
||||||
|
{
|
||||||
|
EMSG2(_("E823: Corrupted undo file: %s"), file_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
version = get2c(fp);
|
||||||
|
if (version != UF_VERSION)
|
||||||
|
{
|
||||||
|
EMSG2(_("E824: Incompatible undo file: %s"), file_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(read_hash, UNDO_HASH_SIZE, 1, fp);
|
||||||
|
line_count = (linenr_T)get4c(fp);
|
||||||
|
if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
|
||||||
|
|| line_count != curbuf->b_ml.ml_line_count)
|
||||||
|
{
|
||||||
|
if (p_verbose > 0 || name != NULL)
|
||||||
|
{
|
||||||
|
verbose_enter();
|
||||||
|
give_warning((char_u *)_("Undo file contents changed"), TRUE);
|
||||||
|
verbose_leave();
|
||||||
|
}
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin undo data for U */
|
||||||
|
str_len = get4c(fp);
|
||||||
|
if (str_len < 0)
|
||||||
|
goto error;
|
||||||
|
else if (str_len > 0)
|
||||||
|
{
|
||||||
|
if ((line_ptr = U_ALLOC_LINE(str_len)) == NULL)
|
||||||
|
goto error;
|
||||||
|
for (i = 0; i < str_len; i++)
|
||||||
|
line_ptr[i] = (char_u)getc(fp);
|
||||||
|
line_ptr[i] = NUL;
|
||||||
|
}
|
||||||
|
line_lnum = (linenr_T)get4c(fp);
|
||||||
|
line_colnr = (colnr_T)get4c(fp);
|
||||||
|
|
||||||
|
/* Begin general undo data */
|
||||||
|
old_header_seq = get4c(fp);
|
||||||
|
new_header_seq = get4c(fp);
|
||||||
|
cur_header_seq = get4c(fp);
|
||||||
|
num_head = get4c(fp);
|
||||||
|
seq_last = get4c(fp);
|
||||||
|
seq_cur = get4c(fp);
|
||||||
|
seq_time = get4c(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. */
|
||||||
|
uhp_table = (u_header_T **)U_ALLOC_LINE(num_head * sizeof(u_header_T *));
|
||||||
|
if (uhp_table == NULL)
|
||||||
|
goto error;
|
||||||
|
vim_memset(uhp_table, 0, num_head * sizeof(u_header_T *));
|
||||||
|
|
||||||
|
c = get2c(fp);
|
||||||
|
while (c == UF_HEADER_MAGIC)
|
||||||
|
{
|
||||||
|
found_first_uep = 0;
|
||||||
|
uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T));
|
||||||
|
if (uhp == NULL)
|
||||||
|
goto error;
|
||||||
|
vim_memset(uhp, 0, sizeof(u_header_T));
|
||||||
|
/* We're not actually trying to store pointers here. We're just storing
|
||||||
|
* IDs so we can swizzle them into pointers later - hence the type
|
||||||
|
* cast. */
|
||||||
|
uhp->uh_next = (u_header_T *)(long)get4c(fp);
|
||||||
|
uhp->uh_prev = (u_header_T *)(long)get4c(fp);
|
||||||
|
uhp->uh_alt_next = (u_header_T *)(long)get4c(fp);
|
||||||
|
uhp->uh_alt_prev = (u_header_T *)(long)get4c(fp);
|
||||||
|
uhp->uh_seq = get4c(fp);
|
||||||
|
if (uhp->uh_seq <= 0)
|
||||||
|
{
|
||||||
|
EMSG2(_("E825: Undo file corruption: invalid uh_seq.: %s"),
|
||||||
|
file_name);
|
||||||
|
U_FREE_LINE(uhp);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
uhp->uh_walk = 0;
|
||||||
|
unserialize_pos(&uhp->uh_cursor, fp);
|
||||||
|
#ifdef FEAT_VIRTUALEDIT
|
||||||
|
uhp->uh_cursor_vcol = get4c(fp);
|
||||||
|
#else
|
||||||
|
(void)get4c(fp);
|
||||||
|
#endif
|
||||||
|
uhp->uh_flags = get2c(fp);
|
||||||
|
for (i = 0; i < NMARKS; ++i)
|
||||||
|
unserialize_pos(&uhp->uh_namedm[i], fp);
|
||||||
|
#ifdef FEAT_VISUAL
|
||||||
|
unserialize_visualinfo(&uhp->uh_visual, fp);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
visualinfo_T info;
|
||||||
|
unserialize_visualinfo(&info, fp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
uhp->uh_time = get4c(fp);
|
||||||
|
|
||||||
|
/* Unserialize uep list. The first 4 bytes is the length of the
|
||||||
|
* entire uep in bytes minus the length of the strings within.
|
||||||
|
* -1 is a sentinel value meaning no more ueps.*/
|
||||||
|
last_uep = NULL;
|
||||||
|
while ((uep_len = get4c(fp)) != -1)
|
||||||
|
{
|
||||||
|
uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T));
|
||||||
|
vim_memset(uep, 0, sizeof(u_entry_T));
|
||||||
|
if (uep == NULL)
|
||||||
|
goto error;
|
||||||
|
uep->ue_top = get4c(fp);
|
||||||
|
uep->ue_bot = get4c(fp);
|
||||||
|
uep->ue_lcount = get4c(fp);
|
||||||
|
uep->ue_size = get4c(fp);
|
||||||
|
uep->ue_next = NULL;
|
||||||
|
array = (char_u **)U_ALLOC_LINE(
|
||||||
|
(unsigned)(sizeof(char_u *) * uep->ue_size));
|
||||||
|
for (i = 0; i < uep->ue_size; i++)
|
||||||
|
{
|
||||||
|
line_len = get4c(fp);
|
||||||
|
/* U_ALLOC_LINE provides an extra byte for the NUL terminator.*/
|
||||||
|
line = (char_u *)U_ALLOC_LINE(
|
||||||
|
(unsigned) (sizeof(char_u) * line_len));
|
||||||
|
if (line == NULL)
|
||||||
|
goto error;
|
||||||
|
for (j = 0; j < line_len; j++)
|
||||||
|
{
|
||||||
|
line[j] = getc(fp);
|
||||||
|
}
|
||||||
|
line[j] = '\0';
|
||||||
|
array[i] = line;
|
||||||
|
}
|
||||||
|
uep->ue_array = array;
|
||||||
|
if (found_first_uep == 0)
|
||||||
|
{
|
||||||
|
uhp->uh_entry = uep;
|
||||||
|
found_first_uep = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_uep->ue_next = uep;
|
||||||
|
}
|
||||||
|
last_uep = uep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insertion sort the uhp into the table by its uh_seq. This is
|
||||||
|
* required because, while the number of uhps is limited to
|
||||||
|
* num_heads, and the uh_seq order is monotonic with respect to
|
||||||
|
* creation time, the starting uh_seq can be > 0 if any undolevel
|
||||||
|
* culling was done at undofile write time, and there can be uh_seq
|
||||||
|
* gaps in the uhps.
|
||||||
|
*/
|
||||||
|
for (i = num_read_uhps - 1; i >= -1; i--)
|
||||||
|
{
|
||||||
|
/* if i == -1, we've hit the leftmost side of the table, so insert
|
||||||
|
* at uhp_table[0]. */
|
||||||
|
if (i == -1 || uhp->uh_seq > uhp_table[i]->uh_seq)
|
||||||
|
{
|
||||||
|
/* If we've had to move from the rightmost side of the table,
|
||||||
|
* we have to shift everything to the right by one spot. */
|
||||||
|
if (i < num_read_uhps - 1)
|
||||||
|
{
|
||||||
|
memmove(uhp_table + i + 2, uhp_table + i + 1,
|
||||||
|
(num_read_uhps - i) * sizeof(u_header_T *));
|
||||||
|
}
|
||||||
|
uhp_table[i + 1] = uhp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (uhp->uh_seq == uhp_table[i]->uh_seq)
|
||||||
|
{
|
||||||
|
EMSG2(_("E826 Undo file corruption: duplicate uh_seq: %s"),
|
||||||
|
file_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_read_uhps++;
|
||||||
|
c = get2c(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c != UF_END_MAGIC)
|
||||||
|
{
|
||||||
|
EMSG2(_("E827: Undo file corruption; no end marker: %s"), file_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We've organized all of the uhps into a table sorted by uh_seq. Now we
|
||||||
|
* iterate through the table and swizzle each sequence number we've
|
||||||
|
* stored in uh_foo into a pointer corresponding to the header with that
|
||||||
|
* sequence number. Then free curbuf's old undo structure, give curbuf
|
||||||
|
* the updated {old,new,cur}head pointers, and then free the table. */
|
||||||
|
for (i = 0; i < num_head; i++)
|
||||||
|
{
|
||||||
|
uhp = uhp_table[i];
|
||||||
|
if (uhp == NULL)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < num_head; j++)
|
||||||
|
{
|
||||||
|
if (uhp_table[j] == NULL)
|
||||||
|
continue;
|
||||||
|
if (uhp_table[j]->uh_seq == (long)uhp->uh_next)
|
||||||
|
uhp->uh_next = uhp_table[j];
|
||||||
|
if (uhp_table[j]->uh_seq == (long)uhp->uh_prev)
|
||||||
|
uhp->uh_prev = uhp_table[j];
|
||||||
|
if (uhp_table[j]->uh_seq == (long)uhp->uh_alt_next)
|
||||||
|
uhp->uh_alt_next = uhp_table[j];
|
||||||
|
if (uhp_table[j]->uh_seq == (long)uhp->uh_alt_prev)
|
||||||
|
uhp->uh_alt_prev = uhp_table[j];
|
||||||
|
}
|
||||||
|
if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq)
|
||||||
|
old_idx = i;
|
||||||
|
if (new_header_seq > 0 && new_idx < 0 && uhp->uh_seq == new_header_seq)
|
||||||
|
new_idx = i;
|
||||||
|
if (cur_header_seq > 0 && cur_idx < 0 && uhp->uh_seq == cur_header_seq)
|
||||||
|
cur_idx = i;
|
||||||
|
}
|
||||||
|
u_blockfree(curbuf);
|
||||||
|
curbuf->b_u_oldhead = old_idx < 0 ? 0 : uhp_table[old_idx];
|
||||||
|
curbuf->b_u_newhead = new_idx < 0 ? 0 : uhp_table[new_idx];
|
||||||
|
curbuf->b_u_curhead = cur_idx < 0 ? 0 : uhp_table[cur_idx];
|
||||||
|
curbuf->b_u_line_ptr = line_ptr;
|
||||||
|
curbuf->b_u_line_lnum = line_lnum;
|
||||||
|
curbuf->b_u_line_colnr = line_colnr;
|
||||||
|
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;
|
||||||
|
U_FREE_LINE(uhp_table);
|
||||||
|
#ifdef U_DEBUG
|
||||||
|
u_check(TRUE);
|
||||||
|
#endif
|
||||||
|
if (name != NULL)
|
||||||
|
smsg((char_u *)_("Finished reading undo file %s"), file_name);
|
||||||
|
goto theend;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (line_ptr != NULL)
|
||||||
|
U_FREE_LINE(line_ptr);
|
||||||
|
if (uhp_table != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; i < num_head; i++)
|
||||||
|
{
|
||||||
|
if (uhp_table[i] != NULL)
|
||||||
|
{
|
||||||
|
uep = uhp_table[i]->uh_entry;
|
||||||
|
while (uep != NULL)
|
||||||
|
{
|
||||||
|
nuep = uep->ue_next;
|
||||||
|
u_freeentry(uep, uep->ue_size);
|
||||||
|
uep = nuep;
|
||||||
|
}
|
||||||
|
U_FREE_LINE(uhp_table[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U_FREE_LINE(uhp_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
theend:
|
||||||
|
if (fp != NULL)
|
||||||
|
fclose(fp);
|
||||||
|
if (file_name != name)
|
||||||
|
vim_free(file_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize "uep" to "fp".
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
serialize_uep(uep, fp)
|
||||||
|
u_entry_T *uep;
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int uep_len;
|
||||||
|
int *entry_lens;
|
||||||
|
|
||||||
|
if (uep->ue_size > 0)
|
||||||
|
entry_lens = (int *)alloc(uep->ue_size * sizeof(int));
|
||||||
|
|
||||||
|
/* Define uep_len to be the size of the entire uep minus the size of its
|
||||||
|
* component strings, in bytes. The sizes of the component strings
|
||||||
|
* are written before each individual string.
|
||||||
|
* We have 4 entries each of 4 bytes, plus ue_size * 4 bytes
|
||||||
|
* of string size information. */
|
||||||
|
|
||||||
|
uep_len = uep->ue_size * 4;
|
||||||
|
/* Collect sizing information for later serialization. */
|
||||||
|
for (i = 0; i < uep->ue_size; i++)
|
||||||
|
{
|
||||||
|
entry_lens[i] = (int)STRLEN(uep->ue_array[i]);
|
||||||
|
uep_len += entry_lens[i];
|
||||||
|
}
|
||||||
|
put_bytes(fp, (long_u)uep_len, 4);
|
||||||
|
put_bytes(fp, (long_u)uep->ue_top, 4);
|
||||||
|
put_bytes(fp, (long_u)uep->ue_bot, 4);
|
||||||
|
put_bytes(fp, (long_u)uep->ue_lcount, 4);
|
||||||
|
put_bytes(fp, (long_u)uep->ue_size, 4);
|
||||||
|
for (i = 0; i < uep->ue_size; i++)
|
||||||
|
{
|
||||||
|
if (put_bytes(fp, (long_u)entry_lens[i], 4) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
fprintf(fp, "%s", uep->ue_array[i]);
|
||||||
|
}
|
||||||
|
if (uep->ue_size > 0)
|
||||||
|
vim_free(entry_lens);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize "pos" to "fp".
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
serialize_pos(pos, fp)
|
||||||
|
pos_T pos;
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
put_bytes(fp, (long_u)pos.lnum, 4);
|
||||||
|
put_bytes(fp, (long_u)pos.col, 4);
|
||||||
|
#ifdef FEAT_VIRTUALEDIT
|
||||||
|
put_bytes(fp, (long_u)pos.coladd, 4);
|
||||||
|
#else
|
||||||
|
put_bytes(fp, (long_u)0, 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize "info" to "fp".
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
serialize_visualinfo(info, fp)
|
||||||
|
visualinfo_T info;
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
serialize_pos(info.vi_start, fp);
|
||||||
|
serialize_pos(info.vi_end, fp);
|
||||||
|
put_bytes(fp, (long_u)info.vi_mode, 4);
|
||||||
|
put_bytes(fp, (long_u)info.vi_curswant, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the undo tree in an undo file.
|
||||||
|
* When "name" is not NULL, use it as the name of the undo file.
|
||||||
|
* Otherwise use buf->b_ffname to generate the undo file name.
|
||||||
|
* "buf" must never be null, buf->b_ffname is used to obtain the original file
|
||||||
|
* permissions.
|
||||||
|
* "forceit" is TRUE for ":wundo!", FALSE otherwise.
|
||||||
|
* "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
u_write_undo(name, forceit, buf, hash)
|
||||||
|
char_u *name;
|
||||||
|
int forceit;
|
||||||
|
buf_T *buf;
|
||||||
|
char_u *hash;
|
||||||
|
{
|
||||||
|
u_header_T *uhp;
|
||||||
|
u_entry_T *uep;
|
||||||
|
char_u *file_name;
|
||||||
|
int str_len, i, uep_len, mark;
|
||||||
|
int fd;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
int perm;
|
||||||
|
int write_ok = FALSE;
|
||||||
|
#ifdef UNIX
|
||||||
|
struct stat st_old;
|
||||||
|
struct stat st_new;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (name == NULL)
|
||||||
|
{
|
||||||
|
file_name = u_get_undo_file_name(buf->b_ffname, FALSE);
|
||||||
|
if (file_name == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file_name = name;
|
||||||
|
|
||||||
|
#ifdef UNIX
|
||||||
|
if (mch_stat((char *)buf->b_ffname, &st_old) >= 0)
|
||||||
|
perm = st_old.st_mode;
|
||||||
|
else
|
||||||
|
perm = 0600;
|
||||||
|
#else
|
||||||
|
perm = mch_getperm(buf->b_ffname);
|
||||||
|
if (perm < 0)
|
||||||
|
perm = 0600;
|
||||||
|
#endif
|
||||||
|
/* set file protection same as original file, but strip s-bit */
|
||||||
|
perm = perm & 0777;
|
||||||
|
|
||||||
|
/* If the undo file exists, verify that it actually is an undo file, and
|
||||||
|
* delete it. */
|
||||||
|
if (mch_getperm(file_name) >= 0)
|
||||||
|
{
|
||||||
|
if (name == NULL || !forceit)
|
||||||
|
{
|
||||||
|
/* Check we can read it and it's an undo file. */
|
||||||
|
fd = mch_open((char *)file_name, O_RDONLY|O_EXTRA, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
if (name != NULL || p_verbose > 0)
|
||||||
|
smsg((char_u *)_("Will not overwrite with undo file, cannot read: %s"),
|
||||||
|
file_name);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char_u buf[2];
|
||||||
|
|
||||||
|
vim_read(fd, buf, 2);
|
||||||
|
close(fd);
|
||||||
|
if ((buf[0] << 8) + buf[1] != UF_START_MAGIC)
|
||||||
|
{
|
||||||
|
if (name != NULL || p_verbose > 0)
|
||||||
|
smsg((char_u *)_("Will not overwrite, this is not an undo file: %s"),
|
||||||
|
file_name);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mch_remove(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = mch_open((char *)file_name,
|
||||||
|
O_CREAT|O_EXTRA|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
|
||||||
|
(void)mch_setperm(file_name, perm);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
EMSG2(_(e_not_open), file_name);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
if (p_verbose > 0)
|
||||||
|
smsg((char_u *)_("Writing undo file: %s"), file_name);
|
||||||
|
|
||||||
|
#ifdef UNIX
|
||||||
|
/*
|
||||||
|
* Try to set the group of the undo file same as the original file. If
|
||||||
|
* this fails, set the protection bits for the group same as the
|
||||||
|
* protection bits for others.
|
||||||
|
*/
|
||||||
|
if (mch_stat((char *)file_name, &st_new) >= 0
|
||||||
|
&& st_new.st_gid != st_old.st_gid
|
||||||
|
# ifdef HAVE_FCHOWN /* sequent-ptx lacks fchown() */
|
||||||
|
&& fchown(fd, (uid_t)-1, st_old.st_gid) != 0
|
||||||
|
# endif
|
||||||
|
)
|
||||||
|
mch_setperm(file_name, (perm & 0707) | ((perm & 07) << 3));
|
||||||
|
# ifdef HAVE_SELINUX
|
||||||
|
mch_copy_sec(buf->b_ffname, file_name);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fp = fdopen(fd, "w");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
EMSG2(_(e_not_open), file_name);
|
||||||
|
close(fd);
|
||||||
|
mch_remove(file_name);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start writing, first overall file information */
|
||||||
|
put_bytes(fp, (long_u)UF_START_MAGIC, 2);
|
||||||
|
put_bytes(fp, (long_u)UF_VERSION, 2);
|
||||||
|
|
||||||
|
/* Write a hash of the buffer text, so that we can verify it is still the
|
||||||
|
* same when reading the buffer text. */
|
||||||
|
if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1)
|
||||||
|
goto write_error;
|
||||||
|
put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
|
||||||
|
|
||||||
|
/* Begin undo data for U */
|
||||||
|
str_len = buf->b_u_line_ptr != NULL ? STRLEN(buf->b_u_line_ptr) : 0;
|
||||||
|
put_bytes(fp, (long_u)str_len, 4);
|
||||||
|
if (str_len > 0 && fwrite(buf->b_u_line_ptr, (size_t)str_len,
|
||||||
|
(size_t)1, fp) != 1)
|
||||||
|
goto write_error;
|
||||||
|
|
||||||
|
put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
|
||||||
|
put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
|
||||||
|
|
||||||
|
/* Begin general undo data */
|
||||||
|
uhp = buf->b_u_oldhead;
|
||||||
|
put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
|
||||||
|
|
||||||
|
uhp = buf->b_u_newhead;
|
||||||
|
put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
|
||||||
|
|
||||||
|
uhp = buf->b_u_curhead;
|
||||||
|
put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
|
||||||
|
|
||||||
|
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_bytes(fp, (long_u)buf->b_u_seq_time, 4);
|
||||||
|
|
||||||
|
/* Iteratively serialize UHPs and their UEPs from the top down. */
|
||||||
|
mark = ++lastmark;
|
||||||
|
uhp = buf->b_u_oldhead;
|
||||||
|
while (uhp != NULL)
|
||||||
|
{
|
||||||
|
/* Serialize current UHP if we haven't seen it */
|
||||||
|
if (uhp->uh_walk != mark)
|
||||||
|
{
|
||||||
|
if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
|
||||||
|
goto write_error;
|
||||||
|
|
||||||
|
put_bytes(fp, (long_u)((uhp->uh_next != NULL)
|
||||||
|
? uhp->uh_next->uh_seq : 0), 4);
|
||||||
|
put_bytes(fp, (long_u)((uhp->uh_prev != NULL)
|
||||||
|
? uhp->uh_prev->uh_seq : 0), 4);
|
||||||
|
put_bytes(fp, (long_u)((uhp->uh_alt_next != NULL)
|
||||||
|
? uhp->uh_alt_next->uh_seq : 0), 4);
|
||||||
|
put_bytes(fp, (long_u)((uhp->uh_alt_prev != NULL)
|
||||||
|
? uhp->uh_alt_prev->uh_seq : 0), 4);
|
||||||
|
put_bytes(fp, uhp->uh_seq, 4);
|
||||||
|
serialize_pos(uhp->uh_cursor, fp);
|
||||||
|
#ifdef FEAT_VIRTUALEDIT
|
||||||
|
put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4);
|
||||||
|
#else
|
||||||
|
put_bytes(fp, (long_u)0, 4);
|
||||||
|
#endif
|
||||||
|
put_bytes(fp, (long_u)uhp->uh_flags, 2);
|
||||||
|
/* Assume NMARKS will stay the same. */
|
||||||
|
for (i = 0; i < NMARKS; ++i)
|
||||||
|
{
|
||||||
|
serialize_pos(uhp->uh_namedm[i], fp);
|
||||||
|
}
|
||||||
|
#ifdef FEAT_VISUAL
|
||||||
|
serialize_visualinfo(uhp->uh_visual, fp);
|
||||||
|
#endif
|
||||||
|
put_bytes(fp, (long_u)uhp->uh_time, 4);
|
||||||
|
|
||||||
|
uep = uhp->uh_entry;
|
||||||
|
while (uep != NULL)
|
||||||
|
{
|
||||||
|
if (serialize_uep(uep, fp) == FAIL)
|
||||||
|
goto write_error;
|
||||||
|
uep = uep->ue_next;
|
||||||
|
}
|
||||||
|
/* Sentinel value: no more ueps */
|
||||||
|
uep_len = -1;
|
||||||
|
put_bytes(fp, (long_u)uep_len, 4);
|
||||||
|
uhp->uh_walk = mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now walk through the tree - algorithm from undo_time */
|
||||||
|
if (uhp->uh_prev != NULL && uhp->uh_prev->uh_walk != mark)
|
||||||
|
uhp = uhp->uh_prev;
|
||||||
|
else if (uhp->uh_alt_next != NULL && uhp->uh_alt_next->uh_walk != mark)
|
||||||
|
uhp = uhp->uh_alt_next;
|
||||||
|
else if (uhp->uh_next != NULL && uhp->uh_alt_prev == NULL
|
||||||
|
&& uhp->uh_next->uh_walk != mark)
|
||||||
|
uhp = uhp->uh_next;
|
||||||
|
else if (uhp->uh_alt_prev != NULL)
|
||||||
|
uhp = uhp->uh_alt_prev;
|
||||||
|
else
|
||||||
|
uhp = uhp->uh_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (put_bytes(fp, (long_u)UF_END_MAGIC, 2) == OK)
|
||||||
|
write_ok = TRUE;
|
||||||
|
|
||||||
|
write_error:
|
||||||
|
fclose(fp);
|
||||||
|
if (!write_ok)
|
||||||
|
EMSG2(_("E829: write error in undo file: %s"), file_name);
|
||||||
|
|
||||||
|
#if defined(MACOS_CLASSIC) || defined(WIN3264)
|
||||||
|
(void)mch_copy_file_attribute(buf->b_ffname, file_name);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ACL
|
||||||
|
{
|
||||||
|
vim_acl_T acl;
|
||||||
|
|
||||||
|
/* For systems that support ACL: get the ACL from the original file. */
|
||||||
|
acl = mch_get_acl(buf->b_ffname);
|
||||||
|
mch_set_acl(file_name, acl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
theend:
|
||||||
|
if (file_name != name)
|
||||||
|
vim_free(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FEAT_PERSISTENT_UNDO */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
|
* If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
|
||||||
* If 'cpoptions' does not contain 'u': Always undo.
|
* If 'cpoptions' does not contain 'u': Always undo.
|
||||||
@ -757,8 +1556,6 @@ u_doit(startcount)
|
|||||||
u_undo_end(undo_undoes, FALSE);
|
u_undo_end(undo_undoes, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
@ -927,7 +1724,7 @@ undo_time(step, sec, absolute)
|
|||||||
|
|
||||||
if (absolute)
|
if (absolute)
|
||||||
{
|
{
|
||||||
EMSGN(_("Undo number %ld not found"), step);
|
EMSGN(_("E830: Undo number %ld not found"), step);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,6 +426,11 @@ static char *(features[]) =
|
|||||||
#else
|
#else
|
||||||
"-perl",
|
"-perl",
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_PERSISTENT_UNDO
|
||||||
|
"+persistent_undo",
|
||||||
|
#else
|
||||||
|
"-persistent_undo",
|
||||||
|
#endif
|
||||||
#ifdef FEAT_PRINTER
|
#ifdef FEAT_PRINTER
|
||||||
# ifdef FEAT_POSTSCRIPT
|
# ifdef FEAT_POSTSCRIPT
|
||||||
"+postscript",
|
"+postscript",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user