Share marks in vim across machines - vim

I use a few different machines and I was wondering if there was a way to store or share marks in files that are opened on the different machines.
If so, how could this be done? I am fine saving/re-storing a helper file in the .vim directory if that is necessary to do the above.
This would be for both lowercase and uppercase marks. I suppose one option would be to put the .viminfo in a git repository and share that between machines, but I'm wondering what unintended consequences that might have. Currently I have:
set viminfo='100,f1,n~/.vim/viminfo
Note that I'm not interested in storing it across sessions on the same machine, but different computers (one local one in aws).

My advice is to use a separate session-like file that only stores marks. The command :wviminfo can write a separate file. So the plan is: save &viminfo and clear it, write a file with marks, restore &viminfo.
function! SaveMarks()
let save_vim = &viminfo " Save viminfo
set &viminfo='100,:0,/0,<0,#0 " Clear viminfo - store only file marks for 100 files
wviminfo! marks.vim
let &viminfo = save_vim " Restore viminfo
endfunction
Copy the file to the other host, read it using :rviminfo:
:rviminfo! marks.vim

Related

Vim undofile does not work when file is too long

I use a vim persistent undo setup as follows, which have worked all that way here.
set undofile
set undodir=~/.vim/undodir
However now I'm facing a problem when the undofile became too long, notice that an undofile has a name in the form of absolute path like %home%user%directory%...%directory%file that means if your file has a big name, is under a big path directory or both, the chances for reaching the linux file name max length will be higher. In my case, when try to save the open file it raises the error:
E828: Cannot open undo file for writing: /home/user/.vim/undodir/%home%user%workspace%%app%javascript%packs%domains%components%grid%column_cell_factory%inspection_cell_factory.jsx
How can I manage in order to keep my persistent undo working even for these situations?
UPDATE
This is not my real filename, I removed username and others personal information intentionally, at the end they are not relevant and don't contain any special char. The file length is 160, and the whole path with the folder it should be stored is 189 length.

vim: multiple "sessions" in the same instance?

I work on a growing project with vim. I like to have most of the project files open in the same session. However, as the project's growing, I start to have too many files open at the same time; switching between files [*] starts getting a bit unproductive at 40+ files because the list gets too long (for, say, 20 files this way of navigating works very well for me, however).
Is there a way to split the session in multiple "sub-sessions" in the same instance of vim?
How I imagine it is that each session would contain, say, 20 files and only list those with :ls, and that I could switch between them in the same vim window (basicallly the same as if I'd run multiple instances of vim in the same shell and switch between them with Ctrl-Z; fg %X, just without leaving vim).
[*] I like to navigate between files with :ls followed by :bX (or directly :bX in case I've memorized a buffer number), along with :bp/:bn, and I always have at least two split open, and this workflow works quite well for me, so I'm not looking for more efficient alternatives to :ls.
I never use :ls. However I often work on big projects, and I open (many) files from different projects (and I'm still able to compile what I want in the mode I want (debug, release, ...), generate tags independently for each project, have different coding styles, etc)
Your question seems to be about "How do I go from one file to another". I have many split windows opened simultaneously and I jump from one to the other with:
:sb, which supports tab completion on filenames (already opened in buffer)
:sp **/filename*<tab> (When it's not already opened)
an old plugin of mine -- others usually use Unite, command-T or other similar plugins -- to merge :sp and :sb into one command.
Tags. The default integration of tags (/csope) is already nice. Yet, I've developed lh-tags, in order to simply the tags navigation in a world of overloaded and overridden functions as it's the case in C++.
EDIT: I've just pushed a highly experimental :Project <name> :ls feature in lh-vim-lib. Note: this new project feature wasn't meant to do what you're looking for, but it's easy to have a restricted :ls thanks to it.
To use it, you'll have to first register buffers to one project or another. Here, I recommend plugins like local_vimrc if each project can be distinguished as files under a given directory. For each root directory place a _vimrc_local.vim file in it that'll contain:
:let s:k_version = 1
" Global definitions executed everytime we enter a file belonging to the project
" This is where we set g:lobal_variables and options for project-unaware plugins.
....
" Then the anti-reinclusion guards for buffer definitions
if &cp || (exists("b:loaded__my_foobar_project_settings")
\ && (b:loaded__my_foobar_project_settings > s:k_version)
\ && !exists('g:force_reload__my_foobar_project_settings'))
finish
endif
let b:loaded__my_foobar_project_settings = s:k_version
let s:cpo_save=&cpo
set cpo&vim
" HERE, we say the current buffer belongs to a project
" solution 1 when we need more control
:call lh#project#define(s:, {'name': 'YouProjectName'})
" OR solution 2 which is easier to manipulate (tab completion, ...)
:Project --define YourProjectName
You can also have a smaller granularity if you wish (this is something which is still poorly documented).
Then, you'll be able to consult the list of projects with :Project --list, or to consult the buffers associated to a given project with :Project YouProjectName :ls.

conflict in configuration file paths between Linux and Windows

I have this line in my .vimrc file:
set directory=~/.vim/swapfiles//
(Note that one extra slash makes the directory names to be included instead of just file names to reduce conflict)
The above config works fine on my Linux machine, but the problem is when I use the same file on Windows I get some warning about the file cannot be read. That's probably because vim is looking for ~/.vim/swapfiles/ directory, which Windows unfortunately don't have.
Is there any way to store my swap files on Windows somewhere (better if it could be in C:\Program Files\Vim\vimfiles\)?
CASE #2
If you got answer for my above question, here is the another one. I also have some lines similar to this:
autocmd filetype python source ~/path/to/file/python.vim
Windows confuses at this point too. How can I patch up?
If you don't want to introduce a $MYVIM variable as ZyX suggests, maybe an alternative is placing the runtime files in $HOME/.vim instead of the default $HOME/vimfiles on Windows. You can then use ~/.vim/... everywhere. This also helps with synchronizing the files across multiple mixed-platform machines.
" On Windows, also use '.vim' instead of 'vimfiles'; this makes synchronization
" across (heterogeneous) systems easier.
if has('win32') || has('win64')
set runtimepath=$HOME/.vim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,$HOME/.vim/after
endif
Maybe what you want is to have directory set based on the entries in runtimepath? Try this:
let &directory = substitute(&rtp, ",", "/swapfiles//,", "g")
With the default runtimepath setting on Unix-y systems you get
$HOME/.vim/swapfiles//,
$VIM/vimfiles/swapfiles//,
$VIMRUNTIME/swapfiles//,
$VIM/vimruntime/after/swapfiles//,
$HOME/.vim/after//
and on Windows
$HOME/vimfiles/swapfiles//,
$VIM/vimfiles/swapfiles//,
$VIMRUNTIME/swapfiles//,
$VIM/vimfiles/after/swapfiles//,
$HOME/vimfiles/after/swapfiles//
I agree, the after directories are unwanted, but vim will pick the first directory that exists and allows file creation so if you don't create the swapfiles sub-directory they won't be touched.
You might want to consider prepending these to the default value instead of replacing it so the defaults are available as a fallback if none of the directories exist.
I don't understand why you have the auto commands you mention. The default settings of runtimepath with filetype plugin on should take care of that for you.
Of course you always have the option of explicitly checking the platform and using different settings as in
if has("win32")
" settings for windows
elif has("win32unix")
" settings for cygwin
elif has("unix")
" settings for unix
elif has("macunix")
" settings for macosx
endif
If you want to avoid an error if a file does not exist then you can use the following definitions in your vimrc
func! Source(file)
if filereadable(a:file)
exec "source " . fnameescape(a:file)
endif
endfunction
com! -nargs=1 -complete=file Source call Source(<f-args>)
and change source to Source when the file might not exist.
First of all, vim translates all forward slashes to backward on windows thus it won’t hurt having slashes. Just in case you think it can be a source of trouble.
Second, it is not impossible to have ~/.vim and all other directories on windows, just some programs don’t want to work with names that start with a dot. You may just add this to runtimepath as it is not there by default on windows and move all user configuration there.
Third, in most places you have a filename you may use $ENV_VAR. It includes setting &rtp, &directory and using :source. So the solution may be the following:
if has('win16') || has('win95') || has('win32') || has('win64')
let $MYVIM=$HOME.'/vimfiles'
else
let $MYVIM=$HOME.'/.vim'
endif
set directory=$MYVIM/swapfiles
autocmd FileType python :source $MYVIM/after/ftplugin/python.vim
(though I agree with #Geoff Reedy that there should be no need in using the last line).
And last, modifying and storing something in C:\Program Files is not the best idea, neither for you nor for the program itself (by the way, vim won’t modify or store something there unless you told it to). It is to be modified by installation, update and uninstallation processes, not by anything else.
I fully agree with Geoff Reedy that the autocmd shouldn't be necessary. In other cases, you can use :runtime instead of :source. It will automatically search all (user and system directories in 'runtimepath'.

Can I recover my code lost during my last change in vim?

I am very sad I deleted wrong function without commit to SVN server by using vim
After I compiled it I found I made the mistake. I 'make' the file also via vim.
Now I haven't closed the file and it has .swp file.
I tried to use 'u' command to restore my deletion but failed. vim said it's the latest changes. sigh.... Anyway I can restore my function?
Million thanks.
To make Drasils pointer a lot more explicit:
:undolist
g- to 'go back in time'
g+ to 'go forward in time'
Vim 7.3+ has undo 'branches': meaning that it will save state snapshots, even if linear history was overwritten (so it isn't reachable by simple u and )
Vim usually saves the previous version of any file edited as a backup with a ~ appended -- you could check to see whether that file is there and if so, whether it's got the right contents.
There are a couple of ways to recover text that you may have unwittingly lost due to a crash or because you closed your program unintentionally.
Use persistent-undo. Persistent undo provides almost all the features provided by swap/backup file option in points #2 and #3, along with some other options such as granular history traversal.
a. Set persistent-undo on:
Put this in your .vimrc:
set undofile
set undodir=~/.vim/undodir
b. Create the undodir
mkdir ~/.vim/undodir
c. To undo a change, use either of the following options
1) g+ in normal mode to go forward in history
2) g- in normal mode to go backward in history
3). :earlier 20s to go back in time by 20s or earlier 10m to go back in time by 10min etc
4) :later 20s to go forward in time by 20s or later 10m to go forward in time by 10min etc
5). Use :undolist to get a list of undo changes
d. To get a visualization of your undo-branches, you can use plugins like gundo.vim: http://bitbucket.org/sjl/gundo.vim/ to visualize the branches
Use backup files
a. Use this in your .vimrc
set backup
b. Set up the backup directory by putting this in your .vimrc
set backupdir=~/tmp/
c. Set up the backup file name to be added to the backup file by setting this in your .vimrc
set backupext=string
Use swap files
a. Use this in your .vimrc
set swapfile
b. Set up the swap directory by putting this in your .vimrc. This may not be a good idea, because it will prevent you from having two files with the same names, or cause conflicts in swap file names.
set directory=~/tmp/
A better option is to provide multiple paths, so if vim encounters a conflict it can then save it to the directory that it can write to using
set directory=,~/tmp/
In this case, it will try to write the swap file to the current directory. If it can't, then it will attempt to write it to the ~/tmp directory
c. Set up the backup file name to be added to the backup file by setting this in your .vimrc
set backupext=string
TL;DR Use persistent-undo. It provides almost all features of swap and backup, and provides additional features such as granular undo which is not provided by backup and swap file options.
References
1. ftp://ftp.vim.org/pub/vim/doc/book/vimbook-OPL.pdf
I don't know if you can recover something here, but for the future, if you user vim 7.3, you should active these options I explain in my previous comment.
I must say that the savevers plugin has saved me a lot of hours ;-)

How to switch between multiple vim configurations with a command or local vimrc files?

I work in several groups, each of which has its own tab/indentation/spacing standards in C.
Is there a way to have separate selectable VIM configurations for each so, when I edit a file, either:
I do something like set group=1 to select a configuration
a local .vimrc that lives in the working directory is used to set the configuration automatically
I have this in $HOME/.vimrc:
if filereadable(".vim.custom")
so .vim.custom
endif
This allows me to put a .vim.custom file in every directory to load commands and options specific to that directory. If you're working on multiple projects that have deep directory structures you might need something more sophisticated (e.g. walk up the directory tree until a .vim.custom is found), but the same basic idea will work.
UPDATE:
I now do something like this in order to read a .vim file from the same directory as the file I'm editing, regardless of what the current directory is.
let b:thisdir=expand("%:p:h")
let b:vim=b:thisdir."/.vim"
if (filereadable(b:vim))
execute "source ".b:vim
endif
In Summary
There are a few ways to do this, of which most have been suggested, but I thought I'd summarise them with two extra ones:
Per-directory vimrc - has the disadvantage that Vim must be started in the right directory: if your project is in ~/project1 and you have ~/project1/.vim.custom and do cd ~ ; vim project1/file.c, the custom settings won't be found.
Modelines - very effective, but has the disadvantage of needing to add them to all files (and remember to add them to new files)
Directory specific autocommands - this is very effective
Scan for a specific header in the file (see below) - this is the one I've used most in the past where working for different companies or on clearly named projects
Per-directory vimrc that's checked when the file is opened (see below). Another fairly easy one to implement, especially if your project code is all in one place.
Scanning for a Header
In a lot of organisations, there's a standard header (with a copyright notice and project name etc) at the top of every source file. If this is the case, you can get Vim to automatically scan the first (e.g.) 10 lines of the file looking for a keyword. If it finds it, it can change your settings. I've modified this to make it simpler than the form I use (which does lots of other things), but create a ~/.vim/after/filetype.vim (if you don't have one yet) and add something like this:
au FileType * call <SID>ConfigureFiletypes(expand("<amatch>"))
" List of file types to customise
let s:GROUPNAMETypes = ['c', 'cpp', 'vhdl', 'c.doxygen']
func! <SID>CheckForGROUPNAMECode()
" Check if any of the first ten lines contain "GROUPNAME".
" Read the first ten lines into a variable
let header = getline(1)
for i in range(2, 10)
let header = header . getline(i)
endfor
if header =~ '\<GROUPNAME\>'
" Change the status line to make it clear which
" group we're using
setlocal statusline=%<%f\ (GROUPNAME)\ %h%m%r%=%-14.(%l,%c%V%)\ %P
" Do other customisation here
setlocal et
" etc
endif
endfunc
func! <SID>ConfigureFiletypes(filetype)
if index(s:GROUPNAMETypes, a:filetype) != -1
call <SID>CheckForGROUPNAMECode()
endif
endfunc
Whenever a file of any type is opened and the file type is set (the au FileType * line), the ConfigureFiletypes function is called. This checks whether the file type is in the list of file types associated with the current group (GROUPNAME), in this case 'c', 'cpp', 'vhdl' or 'c.doxygen'. If it is, it calls CheckForGROUPNAMECode(), which reads the first 10 lines of the file and if they contain GROUPNAME, it does some customisation. As well as setting expandtabs or whatever, this also changes the status bar to show the group name clearly so you know it's worked at a glance.
Checking for Configuration When Opening
Much like JS Bangs' suggestion, having a custom configuration file can be useful. However, instead of loading it in vimrc, consider something like this, which will check when a .c file is opened for a .vim.custom in the same directory as the .c file.
au BufNewFile,BufRead *.c call CheckForCustomConfiguration()
function! CheckForCustomConfiguration()
" Check for .vim.custom in the directory containing the newly opened file
let custom_config_file = expand('%:p:h') . '/.vim.custom'
if filereadable(custom_config_file)
exe 'source' custom_config_file
endif
endfunction
You can also put autocommands in your .vimrc which set specific options on a per-path basis.
au BufRead,BufNewFile /path/to/project1/* setl sw=4 et
au BufRead,BufNewFile /path/to/project2/* setl sw=3 noet
Plugin doing the right thing:
http://www.vim.org/scripts/script.php?script_id=441
“This plugin searches for local vimrc files in the filesystem tree of the currently opened file. By default it searches for all ".lvimrc" files from the file's directory up to the root directory and loads them in reverse order. The filename and amount of loaded files is customizable through global variables.”
Assuming your fellow developers won't complain about it, you can always add vim settings to each file in the comments.
/*
* vim:ts=4:sw=4:expandtab:...
*/
int main(int argc, char **argv)
{
...
I created an open-sourced tool for just this purpose. Forget the headers, scanning, configurations, and local vimrc files.
Try swim.
Swim
swim is a quick tool for switching vimrc files and creating convenient aliases. Here's a short usage list. See the Github repo for a walkthrough gif and download instructions:
Usage
swim add ~/dotfiles/myVimrc favorite #Add new swim alias
swim ls #Show available swim aliases
swim add https://raw.githubusercontent.com/dawsonbotsford/swim/master/exampleVimrcs/vimrcWikia.vim example
swim with favorite #Set alias favorite as primary .vimrc
swim with main #Set alias main as primary .vimrc
Read More
https://github.com/dawsonbotsford/swim
After trying out the localvimrc plugin suggested by the previous poster, I very much like having non-futzy per-project control over vim settings.
It does ask confirmation before loading a .lvimrc file by default but there is a setting to automatically load .lvimrc files. Some might see this as a security hole, but it works as advertised.
I chose to .gitignore the .lvimrc files. Alternatively you can check them in as a form of shared settings (tab/space expansion, tabstops, other project-specific settings).
As mentioned by sledge the usage of that plug-in is the best option I have seen and use. jerseyboy commented that the utility recommended ask for confirmation before loading (ie. after opening every file). To avoid this just set at your main .vimrc the list of local .lvimrc files:
let g:localvimrc_whitelist='/development/kernel/.lvimrc'
Here's a variation on jamessan's
function! ConditionalLoad()
let cwd = getcwd()
if getcwd() =~ $HOME . "/src/mobile"
so $HOME/.vim.mobile
endif
endfunction
autocmd VimEnter * call ConditionalLoad()
I will frequently launch vi without a specific file that I'm jumping to so this enables loading config conditionally based on the current working directory. Downside is that the config isn't applied based on file but off of working directory.
I work in several groups, each of which has its own tab/indentation/spacing standards in C.
I work with all sorts of open source, all at the same time. It's not practical to be creating separate .vimrc files and reconfiguring the formatting standards. More than a decade ago, I finally got tired of dealing with the editor configuration and wrote a program called autotab to handle it.
When autotab is set up with Vim suggested, each time you load a file into Vim, autotab is invoked on it, and the Vim settings output autotab are passed to a :set command.
autotab reads several thousand lines from the file, analyzes them and determines the settings for the expandtab, tabstop and shiftwidth parameters.
It figures out whether the file uses hard tabs or just spaces for indentation, and it figures out the indentation size. If the file is indented with tabs, it figures out the right tab size, based on rendering the file sample using various tab sizes and judging it according to heuristics like line-over-line alignment of internal elements.
It works well enough that I stopped tweaking the algorithm years ago. If it gets confused, it's almost always because the file has formatting issues, such as the use of multiple conventions at the same time.
It is also "agnostic" of the file type and works well with a variety of different languages. I use it not only over C, but shell scripts, Lisp, Makefiles, HTML, and what have you.
Note that it doesn't handle other parameters of formatting that may be project-specific, like for instance, in C files, whether case labels in a switch statement are indented or not, or whether wrapped function argument lists are simply indented, or aligned to the opening parenthesis of the argument list. Vim does have settings for that sort of thing, and so the program could be plausibly extended to analyze the style and output those parameters.
Looking for mostly the same issue I also found the Sauce plug-in: http://www.vim.org/scripts/script.php?script_id=3992
It claims:
Sauce is a lightweight manager for multiple vimrc files, which can be used to load different settings for different environments. In short, you can maintain lots of different vim settings files and only load the one(s) you need when you need them.
I find it particularly interesting that it keeps it configuration all in its data directory instead of expecting the user to sprinkle dotfiles across the filesystem. This though often rather a metter of personal taste.
I have yet to test it though.
You can use stow for switching configuration (any dotfiles, not only .vimrc)
Install stow:
$ apt install stow
Create multiple directories for each configurations:
~$ ls -d ~/dotfiles/vim*
vim-all vim-webdev vim-go
Put different .vimrc's in them:
$ find ~/dotfiles -name .vimrc
/home/username/vim-golang/.vimrc
/home/username/vim-webdev/.vimrc
/home/username/vim-all/.vimrc
Now you can instantinate vim-golang config with this command (should be run inside dotfiles directory):
~$ cd ~/dotfiles
dotfiles$ stow -v vim-golang
LINK: .vimrc => dotfiles/vim-golang/.vimrc
Now it's linked:
$ cd ~ && ls -l .vimrc
.vimrc -> dotfiles/vim-golang/.vimrc
If you need to switch config, just re-stow it:
~$ cd dotfiles
dotfiles$ stow -v -D vim-golang
UNLINK: .vimrc
dotfiles$ stow -v vim-webdev
LINK: .vimrc => dotfiles/vim-webdev/.vimrc
$ cd ~ && ls -l .vimrc
.vimrc -> dotfiles/vim-webdev/.vimrc
More reading of it here: Managing dotfiles with GNU stow
Pros: pretty simple, no vim plugin dependencies, can be used for managing all dotfiles, not only .vimrc.
Cons: configs are independent of each other, you need to manage/update each of them separately (if you dont switch/update you configs too often - it'll not be the issue).

Resources