0

I have configured .dotfiles. Eg. see here https://wiki.archlinux.org/index.php/Dotfiles

So now I can do dgit push or dgit pull on whichever computer I want, and I have all my config files (including .vimrc) with me.

Now I wish to share vim history across all my accounts on different computers. I suppose that there can be many different solutions to this problem.

So far I am doing this manually by storing vim history inside a ~/.vim_history_manual.txt file. I do this by typing exactly this inside gvim (version 8.0.707):

q:ggVGY:q<CR>:e ~/.vim_history_manual.txt<CR>PggVG!sort|uniq<CR>:wq<CR>

These commands followed by a dgit push will make my vim history available on other computers.

I wanted to make it more automatic. However I have never written such advanced functions in gvim :) I started typing in .vimrc this:

function! ExportVimHistoryManually()
...?
endfunction

only to realize that, I suppose, putting these commands there verbatim would not work:

q:ggVGY:q<CR>:e ~/.vim_history_manual.txt<CR>PggVG!sort|uniq<CR>

So could you tell me:

  1. how to solve this problem in general - share vim history across different accounts, using vim / gvim version 8.0.707

  2. or how to solve this problem in particular - how to write this function ExportVimHistoryManually() which I started?

  3. Perhaps then this function could be supplemented by a second function ImportVimHistoryManually() ? Because currently, when I want to check some of my old commands, I open ~/.vim_history_manual.txt file.

  4. or maybe there is some vim plugin for this which I missed?

EDIT: I didn't mention it before, but only now (after seeing B Layer's answer, and earlier discussion) I realized, that it would be most useful when invoked from inside a running vim session. This is because usually I have multiple instances of gvim opened, and the instance which has quit last is overwriting the viminfo file. So it seems to me, that the best way to preserve history of other instances is to export it manually without ever quitting. The other way is to save session then quit, run B Layer's command, then start it again and restore session.

NOTE: I am using devuan linux ascii release.

  • Just FYI, an alternative approach would be to use *nix command line tools (if you're on Cygwin-less Windows disregard this). E.g. this would extract the command line history entries from .viminfo: sed -n '/# Command Line History/,/^$/p' ~/.viminfo > ~/.vim_history_manual. Of course, you can run this from vim: :!sed -n ... – B Layer Oct 4 '18 at 21:05
  • ah! I thought that ~/.vim/viminfo format is magic somehow. Thanks for the hint. This command looks promising for me: sed -n '/# Command Line History/,/^$/p' ~/.vim/viminfo | grep -v -e "^|" | sort | uniq – cosurgi Oct 4 '18 at 22:05
  • sed -n '/# Command Line History/,/^$/p' ~/.vim/viminfo | grep -v -e "^|" | sort | uniq – cosurgi Oct 4 '18 at 22:10
  • If you want to filter out those lines this is better: awk 'h==1 && /^[^|]/ { if (/^#/) exit; print; } /# Command Line History/ { h=1; } ~/.viminfo | sort -u'. It (1) Quits after the history section, not wasting time scanning the remainder of the file, (2) doesn't show the lines starting with | or the starting # Command Line History or the ending blank line (3) Uses -u flag to sort to do the unique filtering (if your version of sort supports that). – B Layer Oct 5 '18 at 1:14
0

Originally I proposed a simple solution for extracting the command line history out of the "viminfo" file using standard command line tools. I'll cover that first. Then based on pop-up requirements from OP I proposed a solution that does everything from within Vim using some viminfo management commands and settings. That's in the second section below.

External (Command Line) Solution

You can get the Vim command line history from the "viminfo" file (usually ~/.viminfo for Linux)...no need to be in Vim at all. Here's one command that will extract it...

awk 'h==1 && /^[^|]/ { if (/^#/) exit; print; } /# Command Line History/ { h=1; } ~/.viminfo

This can be put through sort, uniq, etc...whatever you need...then saved to your target file with > ~/.vmi_history_manual.txt.

This is a Vim site, though, so in that vein here is an alternative:

vim -es -c '/# Command Line History/+1;/^$/-1 g/^:/p' -c 'q' ~/.viminfo

This uses the ex line editor mode of Vim. Those are just Vim commands so there shouldn't be any mystery to this but here's a description of the main command...

/# Command Line History/+1;/^$/-1 g/^:/p : Run the global command (:g) against a range in the buffer. It starts after (+1) the comment that opens the history section and stops before (-1) the terminating blank line. The global command prints lines starting with colon (IOW, it skips those lines starting with | as you indicated you need to do).

As with the previous command, you can pump the output through post-processing utils and send it to the target file.


Internal (In-Vim) Solution

Alternatively, you can leverage Vim's own mechanism for mangaging the viminfo file.

  • The contents of viminfo are determined by the 'viminfo' settings. You can set that so only the parts you care about are saved (e.g. command line history).
  • You can tell Vim to write to the viminfo file with :wv [file]. Yes that's an optional filename parameter. You can use your ~/.vim_history_manual.txt.
  • Do this for all running Vim instances. The data will be merged and only if there's a conflict will anything be lost. (Last Vim instance to write wins.)
  • You can then read that new viminfo file into whatever Vim instances you want, whenever you want with :rv [file].

A function to do the writing:

func! SaveCmdHist(filename)
    " Save current config so we can restore after our custom write.
    let l:oldconfig = &viminfo

    " Turn off all viminfo except command line history
    let &viminfo = "'0,/0,<0,@0,f0,s0"

    " Now write out the info. The bang (!) says to skip reading in
    " the info to this Vim instance. In this context we don't want that.
    exec "wv! " . a:filename

    " Restore original config
    let &viminfo = l:oldconfig
endfunc

Note that we don't explicitly configure command history in the 'viminfo' value as we can just rely on defaults (limit is in 'history').

Call with :call SaveCmdHist('~/.vim_history_manual.txt'), for instance.

It'd be a good idea for you to read this help section about manual reads (and writes): :h viminfo-read-write. Heck, while you're there you might as well read that entire section (:h viminfo).

  • After this discussion I realized that I want to run this from inside a running vim instance. I added and EDIT note, and I am sorry as it seems that I changed my mind mid-asking. Perhaps there is a way to turn your /# Command Line History/+1;/^$/-1 g/^:/p into that function ExportVimHistoryManually() ? – cosurgi Oct 5 '18 at 10:31
  • BTW, why do you say you have to quit Vim to run one of my commands? Any one of these keeps Vim running: (1) run command from Vim (:!command ...) or launch terminal within (neo)vim if you have that feature), (2) suspend VIm (Ctrl-Z), run command from the shell command line, resume VIm (fg), (3) run command in shell from a terminal/psuedo-terminal separate from that which VIm is running in... – B Layer Oct 5 '18 at 15:43
  • I guess I have to quit vim in order to have latest history inside viminfo. Does vim update viminfo continuously, so that without quitting it, the content of q: window and viminfo file are the same? Also note that I am running multiple instances of gvim 8.0.707 simultaneously. Ideally I would like to export (and eventually import, though that is much less important) history from all of them. – cosurgi Oct 5 '18 at 17:42
  • It's not continuously updated but you can manually update it with :wv. If you run that in each running Vim instance in sequence you'll have up-to-date information. Note that the order you choose matters because, while :wv merges data, if there is a conflict the last one to write wins. On the other hand if all you care about is command history that's not going to matter too much except that some commands from a vim instance(s) that did :wv prior may be lost if you've exceeded the max history entries limit. – B Layer Oct 5 '18 at 19:30
  • Great! I'm defnitely going to read :h viminfo. I should have done that earlier! :-)) Oops. I called this function :call SaveCmdHist("~/.vim_history_manual_2.txt") and a file with name a:filename appeared in my ~/. This is a little strange ;) – cosurgi Oct 6 '18 at 12:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.