-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Description
There is one known problem with Vim: if you launched two instances, did some things in both of them and quit only data from last Vim is saved into viminfo: Vim does not bother reading viminfo before writing it (except for marks). Thus my suggestion:
- Tag all saved values with the time they were modified. Specifically
- Variables (
:h viminfo-!
), registers, uppercase marks should be tagged per-element (one tag for one variable, register and mark). Default tag (for unset or converted values) is-inf
. - Buffer list should not be tagged at all (last one always wins).
- Each previous edited file (
:h viminfo-'
) should be tagged on its own, and each saved lowercase mark should be tagged as well. Tags on edited files are updated whenever file is closed (if file is not closed then it should use exit time). - Each history item should be tagged on its own.
- Variables (
- When saving read this back and
- Update variables, registers and uppercase marks only in case they were modified in this vim instance after those in viminfo or at the same time. Decision is to be made element-wise.
- Buffer list is just saved.
- When deciding on previously edited file first decide on the list (if it is too lengthy drop the oldest elements), then retag remaining files using the most recent time. After this merge lowercase marks just like uppercase marks were merged before.
- History items are ordered according to their tag (if times are equal quiting neovim instance’s history comes last) and drop some oldest elements if list became too lengthy.
- Use some kind of synchronization before saving file in order to not mess up with viminfo. I think documenting officially that viminfo must not be a symlink, writing viminfo to some adjacent location and overwriting viminfo with new one iff inode did not change should work (if inode did change merging should be repeated) (some sort of CAS) nearly always, even though between reading inode and moving saved viminfo it may be overwritten: there is not much sense in having 100% bullet-proof solution here. I also know about
flock()
, but never saw it working. And using lock files is slow and requires detection of the situation “other neovim crashed before releasing lock”.
Before implementing any of the above it is good to look at zsh: it has such interesting options as INC_APPEND_HISTORY (update history file as soon as history item appears), APPEND_HISTORY (the most simple way to avoid problem Vim has) and SHARE_HISTORY (history file is read each time it is updated, so all zsh instances have the same history list always).
It may be better to take alternative approach: write viminfo as a log and when it grows too large clean it. This makes it possible to directly take code from zsh and support all of the above options. Log should look like this: timestamp:action:arguments
:
1406449750:set_previously_edited_file:/home/zyx/foo
1406449750:set_file_mark:\0/home/zyx/foo\0:.:18:0
(Note: using NUL to terminate file name. Newline can also be present in the filename and I do not want to bother with escaping. First NUL is there to indicate that newline may be in the argument.)
Though I am not sure whether we should make this log human-readable: using uint64_t
casted to char[8]
(need to ensure endianness though), one character for action (with switch
) and special parser for each of the actions should work much faster and reqire much less on-disk space. Will need a tool to show this log in a human-readable fashion, but this is really simple.
By cleaning I mean first removing successive elements that obsolete each other (e.g. two elements setting one uppercase mark). Then remove oldest duplicate elements from history (e.g. two successive appends of identical history lines). Last: remove oldest items that makes some list (of old files, history lines, etc) grow too large.
This should be decided before first release because we do not want to add compatibility code, do we?
Want to back this issue? Place a bounty on it! We accept bounties via Bountysource.