One of the primary distinction betweeen vi (vim) and emacs, is emacs is designed and supposed to be run at times without quitting, where as given the quick load time of vim, it is easier to quit and start for editing tasks. I read that it has become a cultural difference between these two editor users.
I tend to think that keeping the editor running at all times, kind of helps in productivity as you know that, something is in progress and you need not start again. What is best tricks and plugins that you have found to run a single vim session and do all your tasks from there?
For e.g, I edit Python programs, then quit to run the appengine appcfg and go back. Sometimes quit current file to open another file. I have not yet gotten used to concept of buffers and tabs, but rather run vim in my screen sessions, if I want to edit multiple files.
So you're running one file Vim per screen session? That sounds pretty bad man. You don't really need any special plugins to use multiple files in Vim easily. Just do
:e /home/project/myfile.py
I have set autochdir in my .vimrc which automatically changes current working directory to whatever buffer is currently active. So once you have that file open you can just do
:e myfile2.py
:e myfile3.py
etc. BTW opening any files in Vim can be completed with tab completion so make sure you are doing that. Once you have a bunch of buffers open to switch between I just do
:b myfile1.py
which you can also use tab completion for you can just type :b 1 and hit tab and it will figure out you want myfile1.py open so it is super quick if you can remember the general file name and if there is more than one similar match it will give you a list that you can tab through. For that I would also advise taking a look at the wildmode and wildmenu settings to see what you prefer they will give you enhanced tab completion menus. If at any time you start getting lost with what buffers are open and what you want to look at you can just do
:ls
and it will show you everything open.
Also remember you can run external commands by preceding a command with !
:!ls
for example. Hope some of this helps or at least gets you looking in the right direction.
Everything the others said plus three:
With set hidden you can open a new buffer in place of the current one, even if it's not saved. You can open dozens of buffers like that, no need to close Vim! See :help windows or the Vim wiki.
Supposing Vim is compiled with the correct flag (+clientserver) you can have a single Vim running as a "server" (in a terminal window A) and open all your files in that single Vim (from terminal window B). It's done in two steps:
$ vim --servername WHATEVER to start Vim
$ vim --remote file.js to open a file
Your file is opened in Vim in terminal window A and you still have your prompt in terminal window B.
Don't touch tabs. They are terribly wrongly named and don't work like tabs at all.
You can even drop down to a shell using :sh, and then get back to Vim using exit in the shell. For editing multiple files in the same Vim, you can use :vsplit filename or :split filename (for vertical and horizontal splits), and then use Esc+Ctrl+w+arrow keys to navigate between the different splits. This way you don't need tabs. Works especially well if you're working with small pieces of code.
Just use the :! command to run stuff in a shell. It mixes great with :cd and % expansion
bash> vim path/to/ex.c
...
:cd %:h. " move to path/ex/
:!gcc -o %:r % && %:r " compile ex.c into ex and run it
You can also mix it with :read if you want to put the output of a command in the current buffer:
:read !ls " read in the names of all the files in the current directory
Here's good video tutorial that helps with workflow of how and why to use a single Vim session to manage all your edits:
http://www.derekwyatt.org/vim/vim-tutorial-videos/vim-intermediate-tutorial-videos/#onevim
If I'm running vim from console (which I do on linux because I use ssh exclusively), then I often use CTRL-z to suspend vim. Then do my shell stuff and fg to return to vim.
Using ctags in vim is incredibly useful -- help tags for more info.
I use a perforce plugin that is quite powerful: http://www.vim.org/scripts/script.php?script_id=240. The diff support is amazing because you can cycle through all opened files or look at file history and diff between 2 older versions. Try :PVDiff, :PFilelog and :POpened.
I define a lot of macros for things like search and buffer windows manipulation. I have some interesting macros/functions listed here that help me live in vim.
Clipboard:
let mapleader=","
" put from clipboard
nmap ,p "*p
" yank to clipboard
nmap ,y "*y
Tags:
" jump to tag in other window
map t :call TagJumpOtherWindow()<cr>
function! TagJumpOtherWindow()
let cw = expand("<cword>")
winc p
exec "tjump " . cw
let #/ = cw
normal z.
winc p
endfunction
Scratch:
let mapleader=","
nmap ,x0 :e e:/work/scratch0.txt<CR>
nmap ,x1 :e e:/work/scratch1.txt<CR>
nmap ,x2 :e e:/work/scratch2.txt<CR>
nmap ,x3 :e e:/work/scratch3.txt<CR>
nmap ,x4 :e e:/work/scratch4.txt<CR>
nmap ,x5 :e e:/work/scratch5.txt<CR>
nmap ,x6 :e e:/work/scratch6.txt<CR>
nmap ,x7 :e e:/work/scratch7.txt<CR>
nmap ,x8 :e e:/work/scratch8.txt<CR>
nmap ,x9 :e e:/work/scratch9.txt<CR>
IDE:
function! GetMsdevFile(line)
let mx = '^\s*\([a-zA-Z_/\.0-9:\- ]*\)'
let line = matchstr( a:line, mx )
let file = substitute( line, mx, '\1', '' )
let file = substitute( line, '\\', '/', '' )
return file
endfunction
function! GetMsdevLineNumber(line)
let mx = '^\s*\([a-zA-Z_/\.0-9:\- ]*\)(\(\d\+\))'
let line = matchstr( a:line, mx )
let linenumber = substitute( line, mx, '\2', '' )
return linenumber
endfunction
function! GetMsdevFile2(line)
let file = expand("%:p:h") . "/" . GetMsdevFile(a:line)
let file
return file
endfunction
function! GetMsdevFile2(line)
let file = expand("%:p:h") . "/../" . GetMsdevFile(a:line)
let file
return file
endfunction
function! GotoMsdevMake( thiswin, version )
exec "cd ".$DIRECTORY."\\.."
let l = getline(".")
if a:version==0
let file = GetMsdevFile(l)
let linenumber = GetMsdevLineNumber(l)
elseif a:version==1
let file = GetMsdevFile2(l)
let linenumber = GetMsdevLineNumber(l)
else
let file = GetMsdevFile3(l)
let linenumber = GetMsdevLineNumber(l)
endif
if a:thiswin==1
winc p
endif
exec "e +" . linenumber. " " . file
exec "cd -"
endfunction
function! GetGCCFile(line)
let mx = '^\([a-zA-Z_/\.0-9:\- ]*\):[0-9]\+: .*'
let line = matchstr( a:line, mx )
let file = substitute( line, mx, '\1', '' )
let file = substitute( file, '\\', '/', '' )
return file
endfunction
function! GetGCCLineNumber(line)
let mx = '^\([a-zA-Z_/\.0-9:\- ]*\):\([0-9]\+\):.*'
let line = matchstr( a:line, mx )
let linenumber = substitute( line, mx, '\2', '' )
return linenumber
endfunction
function! GotoGCCMake()
exec "cd ".$DIRECTORY."\\.."
let l = getline(".")
let file = GetGCCFile(l)
let linenumber = GetGCCLineNumber(l)
winc p
exec "e +" . linenumber. " " . file
exec "cd -"
endfunction
function! MakeOut( filename )
exec ":e " . a:filename
call MakeBuffer()
normal zz
endfunction
" use the current buffer into a Visual Studio build output buffer to jump to errors
function! MakeBuffer()
normal! gg
exec "/).*error\\|failed"
nnoremap <buffer> <cr> :call GotoMsdevMake(1, 0)<cr>
nnoremap <buffer> :call GotoMsdevMake(1, 1)<cr>
nnoremap <buffer> o :call GotoMsdevMake(1, 1)<cr>
" nnoremap <buffer> :call GotoMsdevMake(0, 0)<cr>
endfunction
" use the current buffer into a GCC build output buffer to jump to errors
function! MakeGCCErr()
normal! gg
exec "/: error:"
nnoremap <buffer> <cr> :call GotoGCCMake()<cr>
nnoremap <buffer> :call GotoGCCMake()<cr>
nnoremap <buffer> o :call GotoGCCMake()<cr>
endfunction
function! MakeGCCOut( filename )
exec ":e " . a:filename
call MakeGCCErr()
endfunction
nmap ,mr :call MakeOut( "e:/perforce/branch/obj/release/BuildLog.htm" )<cr>
nmap ,md :call MakeOut( "e:/perforce/branch/obj/debug/BuildLog.htm" )<cr>
nmap ,mm :call MakeBuffer()<CR>
nmap ,mq :call MakeGCCErr()<cr>
I keep a single vim window open for days at a time. split windows work really nicely on large screens.
I also like tabs; I cluster my splits for a single project in a tab, but keep other tabs around for my day plan, my vim wiki, scratch notes for when I'm interrupted. I find tabs easier to use than multiple windows.
Related
I'm using GVim 8.1 on Windows 10 with no external plugins.
I have the following set up in my .gvimrc file:
let g:build_file_abs_path = fnamemodify(findfile("windows-build.bat", ";."), ":p:h")
" This build script is a basic wrapper for 'clang.exe file.c -o file.exe' style invocation
let &makeprg=g:build_file_abs_path . "\\windows-build.bat"
nnoremap <silent> <C-B> :cd <C-R>=g:build_file_abs_path<CR> <bar> make! <bar> copen <bar> redraw <bar> cd -<CR>
Now, this automatically opens a quickfix window with the correct compiler output. However, when I press ENTER over the error, the cursor jumps to the buffer for the affected file, yet it is completely blank with a single line. Furthermore, this occurs as I use :cn and :cp commands inside the quickfix window. e.g:
Images showing these two states:
before
after
Please note that:
:verbose nmap <CR> returns no mappings, so there is not conflict there.
I would appreciate it if someone could provide some insight as to how to avoid the buffer becoming empty and actually jump to the error in the appropriate file. Many thanks.
Thanks to Christian Brabandt's comment, I was able to solve the issue. I was misunderstanding the distinction between the working directories of vim and the build script. I made the following changes:
let &makeprg="cd " . g:build_file_abs_path . " && windows-build.bat"
nnoremap <silent> <C-B> :make! <bar> copen <bar> redraw <CR>
Let me jump right in.
What I'm trying to do is simply print out the file path of any open buffer when I exit vim. This is useful because I often open other files in vim buffers with a vim script I wrote that can search through my codebase for a specific function call.
I figure I can set up an autocommand, either for when I open a file or when I leave vim, and use the output from :ls to list all currently open buffers. The problem that I'm having is that I can't get any output to show up in terminal. I have tried various combinations of :!echo in my function, but to no avail. I have been trying something like the following in my .vimrc
function! PrintFileName()
:!echo "hello"
:exec "!echo world"
"... etc
endfunction
au BufRead * call PrintFileName()
Both :!echo foobar and :call PrintFileName() work for me if I do it from the command line. I also figure I might have to use some form of silent/redraw! so I don't have to hit enter to continue.
Really the main problem here is that I can't see a way to get output to stdout from inside my function and called by an autocommand.
Thanks for any help.
Okay, so I've found this solution, which works as long as I enter vim from the last line of my terminal. Otherwise this prints out a line below the current line and will get overwritten when you press enter. If anyone knows how to fix that let me know, otherwise I will use this.
function! PrintBuffers()
redir => files
:ls
redir END
" Regex to strip out everything from :ls but the buffer filenames
let files = substitute(files, '^[^"]*"', '', 'g')
let files = substitute(files, '"[^"]*\n[^"]*"', '\n', 'g')
let files = substitute(files, '"[^"]*$','','g')
" This is the magic line
exe '!echo; echo ' . shellescape(&t_te . files)
endfunction
au VimLeave * call PrintBuffers()
*Note - As I'm writing this, I realize that this won't display the right path if you did a :cd at some point. So I guess its pretty fragile, but it does the job.
Is there a way to search the list of recently used file in Vim? The list can be displayed using
browse old
but / does not work. I am aware of some plugins (e.g. MRU) but would prefer to not use a plugin.
Here's a short scriptlet that opens the file list in a scratch buffer. As a bonus, it defines a local <Enter> mapping to :edit the current file. With this, you can search with all built-in commands like /:
:new +setl\ buftype=nofile | 0put =v:oldfiles | nnoremap <buffer> <CR> :e <C-r>=getline('.')<CR><CR>
If you really want to avoid a plugin:
:new The old files will be printed into this buffer
:redir #X where X is a temporary register`
:silent echo(v:oldfiles) 'Silent' is there to not actually print onto your screen
:redir END
"Xp paste the temporary register
(optional) Do some regex-fu to put each file on its own line.
Put the above into a function and voila. Also :help redir
It's actually not very hard to write a simple (simplistic?) MRU command with completion that works like :edit or :split:
" this is our 'main' function: it couldn't be simpler
function! MRU(arg)
execute 'edit ' . a:arg
endfunction
" the completion function, again it's very simple
function! MRUComplete(ArgLead, CmdLine, CursorPos)
return filter(copy(v:oldfiles), 'v:val =~ a:ArgLead')
endfunction
" the actual command
" it accepts only one argument
" it's set to use the function above for completion
command! -nargs=1 -complete=customlist,MRUComplete MRU call MRU(<f-args>)
Here is a .vimrc version of code above. Just add following lines to .vimrc and map to desired keys (in my case it is 'o). In addition define patterns to remove "junk" files. Also cursor is placed at the top for convenience.
Most hard thing is to map an Enter inside nested nmap. ^V is the result of doubled Ctrl-V. ^R is the result of Ctrl-V+Ctrl-R. ^M is the result of Ctrl-V+Enter. You need manually repeat those symbols - not just Copy/Paste. Spent hours to understand this magic - so I'm glad to share. This technology lets you add own macroses in .vimrc.
" Browse Old Files
nnoremap <silent> 'o :enew<CR>:set buftype=nofile<CR>:set nobuflisted<CR>:exe "0put =v:oldfiles"<CR>:nmap <buffer> ^V^V^M :e ^V^V^R=getline('.')^V^V^M^V^V^M<CR>:g/\v(stdout\|nerd\|fugitive)/d<CR>:0<CR>
This is my take on Ingo's answer above for my .vimrc:
Opens the old files in either a vertical split or tab, then maps enter to open file under cursor! magic!
" open old files list and map enter to open line
" vertical split
noremap <leader>vv :vnew +setl\ buftype=nofile <bar> 0put =v:oldfiles <bar> nnoremap <lt>buffer> <lt>CR> :e <lt>C-r>=getline('.')<lt>CR><lt>CR><CR><CR>
" in new tab
noremap <leader>vt :tabnew +setl\ buftype=nofile <bar> 0put =v:oldfiles <bar> nnoremap <lt>buffer> <lt>CR> :e <lt>C-r>=getline('.')<lt>CR><lt>CR <CR><CR>
This is a followup (but a distinct question) to this question, which I'll reiterate here for completion.
I have a Vim mapping to start searching (ack-grep with ack.vim plugin) for a pattern from the directory that is the current directory (so the result after :pwd). This mapping works when I'm looking at a buffer.
I want to use the same mapping while I'm in netrw. But, I want to change the current directory (:pwd) to the directory netrw is showing me, so the search will be started from the directory I'm looking at. I know I can do this with the netrw c command. How do I give the c command from within a function?
I've tried:
function! StartAckSearch()
" If we're in netrw change the current directory to the directory we're
" viewing
if &ft ==# 'netrw'
echo 'in netrw'
c
endif
endfunction
nnoremap <Leader>a :call StartAckSearch()<CR>
And:
I've tried:
function! StartAckSearch()
" If we're in netrw change the current directory to the directory we're
" viewing
if &ft ==# 'netrw'
echo 'in netrw'
execute 'c'
endif
endfunction
nnoremap <Leader>a :call StartAckSearch()<CR>
But they both don't work.
Question
How do I call a netrw command using Vimscript? (If my question can be rephrased to be clearer, please go ahead)
I think you can use norm c to call it.
Another way is exe 'norm c'
I'm editing an XML file in Vim, and then I want to transform it a plain-text file with xsltproc, which by default outputs to a stdout (something like : !xsltproc TXTRULE.XSL %). Is it possible to redirect that xsltproc output to a new tab in Vim without creating any intermediate files?
(I've tried to read :help redir and some wiki notes, but still can't get it. would be greateful for some kind of simple example.)
You can use read like in the following:
:read !ls
Obviously you should change ls with your command. If you want to open a new tab prepend tabnew with a bar to the command like:
:tabnew|read !ls
To expand on lucapette's answer, you could create a map like this:
:map ,x :tabnew<Bar>read !xsltproc TXTRULE.XSL #
# expands to the previously opened buffer, which is the file you were editing, while % would expand to the new buffer opened by :tabnew.
<Bar> has to be used instead of |, because otherwise, the :map command would end at the |.
I am using the following to view my program outputs (very useful for a makefile with a make run rule)
It opens a new tab next to current one only if one was not already opened before for that purpose:
fu! RedirStdoutNewTabSingle(cmd)
let a:newt= expand('%:p') . ".out.tmp"
tabnext
if expand('%:p') != a:newt
tabprevious
exec "tabnew" . a:newt
else
exec "%d"
endif
exec 'silent r !' . a:cmd
set nomodified
endfunc
au FileType xml noremap <buffer> <F6> :call RedirStdoutNewTabSingle("xsltproc")<CR>