vim: multiple "sessions" in the same instance? - vim

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.

Related

Give vimdiff some hints

I've got two c++ files that I want to diff with vimdiff. One of them has a lot more function definitions at the start, before both have a common function that I'm actually interested in. However, vimdiff seems incapable to ignore all the function defs before the common one (perhaps because of different arguments).
Is there any way I can give a hint to vimdiff that, say, line xxx in file1.cxx is equals to line yyy in file2.cxx?
I'm open for alternative solutions without vimdiff, but they must be on linux and very preferably command line, since I'm ssh-ing and any graphical interface is a bit uncomfortable.
Vim just delegates the actual work of comparing the files to the external diff utility, cp. :help diff-diffexpr. The help page also shows how a different utility can be used. Unfortunately, I'm not aware of any more "intelligent" or configurable diff tool that would help in your situation.
A workaround might be (temporarily) removing the excess functions that you're not interested in, anyway. With the BlockDiff plugin, you don't actually need to modify the files. Just select the interesting lines in both windows and execute :[range]BlockDiff on them. Only those sections will then be diffed in a separate tab page. (The plugin mentions this requires a GUI, but Vim in a terminal supports tab pages just as well.)

How to get add folder to Projects (like Sublime Text) in VIM?

I just switched from Sublime Text to GVIM (on Windows). I am still debating whether I should continue ST or move completely to VIM. One feature that I desperately need (or miss) are
Ctrl+P to go to any file that I want in my list of folders.
Ctrl+Shift+f to find (and replace) any text in those list of folders.
I had added number of folders using Add Folders to Project feature in Sublime Text 3. It was really helpful. Now, I know that CtrlP plugin for VIM can do similar thing, but I can't figure out how to make it search the folders that I want, and not the root directory of current file.
I played around a bit with setting path in my vimrc file without much success.
Can you please help. If it is a repeated question, please excuse me.
Thanks.
AFAIK, ctrlp plugin only searches within one directory (and its descendants). Use the Unix features: make a directory with links to out-of-project directories you are interested in. This way, the association with out-of-project directories is not just something the editor knows about, but something recorded in the actual project.
Search and replace is a bit stickier thing. You want to work with all the files you are interested in, then repeat the replace command through all of them. For example, if you want to do the search for foo and replace with bar on all C files here and under,
:args **/*.c
:argdo %s/foo/bar/g
Ctrl+P to go to any file that I want in my list of folders.
The :find command can be used to "find" a file in the directories specified in the 'path' option:
set path+=/some/arbitrary/path
set path+=/another/one
:find *foo
I find these two mappings very handy:
nnoremap <key> :find * " search in every directory
" in 'path'
nnoremap <key> :find <C-R>=expand('%:p:h').'/**/*'<CR> " start from the directory
" of the current file
Ctrl+Shift+f to find (and replace) any text in those list of folders.
What amadan said above.
Good switch! So you’ve discovered CtrlP. It has extensive documentation built in. Use :h ctrlp to see the full vimdocs explaining the various options. It’ll explain some important settings for working dirs, which are pretty important for a good experience with it. Take for example some of the settings I use:
" The one you really care about...
" Set root to CWD. Another good option is 'r' for VCS mode.
" You should start vim in the root of your project tree
let g:ctrlp_working_path_mode = 0
" You _can_ switch dirs
let g:ctrlp_extensions = ['dir']
" Avoid big/unimportant project areas
set wildignore+=*/node_modules/*,*/build/*,*/components/*,*/_public/*,*/tmp/*,*/vendor/*
" Cache -- get used to pressing F5 on tree changes/additions
let g:ctrlp_use_caching = 1
let g:ctrlp_clear_cache_on_exit = 0
" Somewhat self-explanatory
let g:ctrlp_show_hidden = 1
let g:ctrlp_switch_buffer = 2
let g:ctrlp_max_depth = 6
let g:ctrlp_max_height = 50
" Open *h*orizontally and *j*ump to first win.
let g:ctrlp_open_multiple_files = 'hj'
" Use <C-d> to toggle
"let g:ctrlp_by_filename = 1
For further control of where to look for files outside your working tree, consult g:ctrlp_user_command. There is a Windows example using dir. You’d use that, but with your desired extra paths.
You might also want to add NerdTree, a nice complement to CtrlP. It is reminiscent of ST’s sidebar. Use its ? to get help. It has a menu that lets you quickly add files and dirs, maybe like you’re wanting out of “Add folders to project”.
For search-and-replace, look at ag.vim. I map it to <leader>g (meaning “grep”).
Those mentioned are some of my favorites, but you should explore the world of Vim plugins to decide which others are worth adopting. I recommend trying one at a time while you’re new, rather than a sometimes-opaque “distribution”. Tools to make plugin management easier are Vundle / Pathogen (choose one).
Eureka...!!!!!
After searching tirelessly for days (and sleepless nights), I found my answer (please read on).
First some foolosophy though
I was so keen not to give up on Vim. But this issue was just eating me from inside, and was disruptive in my work flow. I have many project folders in windows that I want vim to search through. Ctrl+p for some reason never really worked. I had some not-so-nice thoughts of giving up on Vim. and then I found this!
My Answer
This is a little different from what I expected. But the answer is Everything (by VoidTools). It allows to search from anywhere and gives results in a fraction of sec. It is by far the best filename search tool in Windows. It supports Regex. (though it is not text search tool). It has a command line interface called
es.exe
using Vim's FindEverything.vim plugin (FindEverything), I was able to search not only through my project folders, but pretty much anywhere. It returns the results in the vim buffer.
Thanks Y'all for your help. I know that not everyone may agree with this solution. But on Windows, this is by far the best solution, I found! Hopefully, it is useful for others why are in same boat!!!

Making AutoComplPop search entire project (or open buffers)?

I started using AutoComplPop for automatic code completions. It works great on the single file I am editing, but if file1 is making a reference to a method defined in file2, it doesn't find it.
The docs don't specify if there is a way to make it search a whole project directory, or even just all open buffers, so I can't tell if this is simply not something the plugin does, or if I need to enable something.
I was testing it out on two Ruby files, if that's relevant. Thanks!
Looks like that the cause of the problem is that ACP set the complete option for its purposes to .,w,b,k (see line #125 in autocomplpop/plugin/acp.vim),
call l9#defineVariableDefault('g:acp_completeOption', '.,w,b,k')
while the default value that is used when pressing \<C-n> is .,w,b,u,t,i. And it appears that the very last letter i actually makes the difference: for some reason vim would not use word from an include file opened in a buffer to complete words in another buffer. So, b option is not enough, i must also be included. Adding the following line into my .vimrc helped
let g:acp_completeOption = '.,w,b,u,t,i'
At least it worked for C++ files, but I'm not sure it fixes the problem for the case of Ruby scripts.
Depending on what is on the left of the cursor, ACP (like all the alternatives) decides what completion mechanism to use.
But ACP only uses Vim's default completion mechanisms: if <C-x><C-o> and <C-n>/<C-p> don't provide what you are looking for, ACP won't help. Try them out first.
Oh cool, this plugin looks a lot like neocomplcache but maybe cleaner...looks a little old. Little concerning that there are so many open tickets on that project and no updates in two years.
Anyway, according to the documentation it doesn't...really...say. Very likely its one of the following things:
Your pwd. If the root directory for your source is some/path then that should also be your current working directory. Try typing :cd some/path to see if that makes a difference.
The runtime path rtp. See if adding the directory with your source files to &rtp does the trick.
The path. Same deal as the &rtp setting.
Very likely this plugin is just falling back on the built in ruby omni completion functions bundled with vim. Try help ft-ruby-omni.
I just had the same problem, and I actually found a solution for this.
Apparently you have to set in your .vimrc file the following:
let g:acp_behaviorKeywordCommand = "\<C-x>\<C-i>"
This will make acp look in every file included by your source for completions, as if you were actually typing <C-p>. However, it is slow, after trying it I decided to revert using <C-p> when there are no matches and default behaviour in the other cases.

Search tags only in current file

I am using ":ta " to jump to a method.
For example i got two classes named A.java and B.java. They both have a foo() method and B.java have another method called fooBar(). Then i open A.java and input :ta foo then press TAB then i will got two completion : foo and fooBar. But what i want to jump now is just tag in current file, i don't like tag in other file to display.
And i found tagslist does very good in this job. So if i can use the tag generated by taglist to search from, it will be very nice.
Depending on how many times you call your methods a couple of * may be enough.
Without using tags, gd can be used to go to the local declaration of the method under your cursor. I tend to choose the most low-tech solution usually, so I would go with this one.
But ctags is also able to generate tags for a single file only or for an arbitrary selection of files. It can be done in a few steps but it's definetely not as straightforward as what you are accustomed to do…
Create a file with the name(s) of the file(s) you want to scan. Let's say it's called files.txt and it's located at the root of your working directory.
Generate your tags file using the -L <file> argument: ctags -L files.txt.
At this point you should have a tags file containing only the tags present in the file(s) specified at step 1.
Generating different tags files for the whole project and for single files may be useful, here. A short script generating a tags file named after the current file and making it the sole tags source may make the whole thing easier.
EDIT
Actually, TagList and TagBar don't generate tags files. The output of the ctags <options> command they run is used internally and parsed with all kinds of regexp to filter by scope or filename or whatever.
Unfortunately this cannot be done using ctags. Ctags does not respect context, it is a pure list of all possible "functions". Try to open a tag file with an editor (e.g. vim) and you will see it is just a list of "functions" (in case of Java they are "methods"). Example:
getDesc src/com/redhat/rhn/internal/doclet/Handler.java /^ public String getDesc() {$/;" m class:Handler
getDoc src/com/redhat/rhn/internal/doclet/ApiCall.java /^ public String getDoc() {$/;" m class:ApiCall
Vim just search the file "as is" without giving it any context - it just search for a "function". It is able to search for files, classes, methods, enums etc. Tags format is described in more detail here: http://ctags.sourceforge.net/FORMAT
In Vim you have few possibilities. There are several plugins that gives Vim some context sensitivity, but you cannot use tags for that. Vim itself has a feature called OmniComplete and there are few plugins dedicated for Java. Then you can use Ctrl-X Ctrl-O to start a completition. I recommend you to map this to a different key (maybe Ctrl-Space if you like). More info about Java OmniComplete plugins here:
Vim omnicompletion for Java
Eclim (http://eclim.org/) is very comperhensive, but difficult to setup (you need to run Eclipse in the background). JDE script is easier and also robust (http://www.vim.org/scripts/script.php?script_id=1213). And please note IntelliJ IDEA Community Edition (free) also has a very nice Vim plugin that is free to use. But I understand you - Vim is Vim.
Good luck!
Not exactly an answer to your question, but it seems like there's no way to do exactly what you need, so, i would recommend you the following: for your Java development in Vim, try eclim.
This tool helps you to use your favorite text editor Vim with power of an Eclipse (IDE).
I can't find analogue for tab-completion of :ta, but i know a smart analogue for g] : this is a command :JavaSearchContext. You can map it to something.
For example, if you have two classes A and B, and you have method foo() in each class, then g] will ask you every time you want to jump to foo(), but :JavaSearchContext will always jump to the proper declaration of foo().
Of course, there are many other features.

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