How do I configure vim to open a default file (in my case, ~/Desktop/now.md) if the vim command is invoked without arguments on the command-line?
Add the following to your .vimrc:
au VimEnter * if eval("#%") == "" | e ~/Desktop/now.md | endif
This tells vim that whenever you launch vim (VimEnter) with any filetype (*) to run the following ex command:
if eval("#%") == "" | e ~/Desktop/now.md | endif
This is pretty straight-forward. The register '%' holds the name of the file you are editing, so we evaluate it and see if it's empty. If it is, tell vim to open the specified file.
Recommended reading: autocommands
Might be simpler handle this in your shell instead of vim.
You can add something like this to your .bash_profile / .zshrc:
alias vim='if [ $# -eq 0 ]; then command vim ~/Desktop/now.md; else command vim "$#"; fi;'
$# is the number of parameters passed to the command
"$#" lists all parameters passed to the command
To avoid recursively calling the vim alias, we prepend the vim command with the command keyword, which avoids aliases.
Related
I am trying to create a simple mapping in vim to execute a shell command. The command I want to execute is this:
ruby -e "Dir.glob('./spec/*_spec.rb').each {|f| require f}"
which works fine when I run it at the command line.
However, if I run the following in vim:
nmap ,t :!ruby -e "Dir.glob('./spec/*_spec.rb').each {|f| require f}"<cr>
I get the error:
E492: Not an editor command: require f}"<cr>
Note: I'm on windows, if that's relevant.
What am I doing wrong?
Bonus: How can alter the above command so that it does not depend on the current file being in the directory containing "spec"? Ideally, if the current file's directory did not contain "spec", it would check the parent directory, and so on, recursively, until it found a directory containing "spec". At that point it would run the command with "." replaced by the directory it found in my code above.
Final Solution
Based on Ingo's answer, my final solution was this:
nnoremap ,tt :call RunAllMinitestSpecs()<cr>
function! RunAllMinitestSpecs()
let l:dir = finddir('spec', '.;')
let l:dir = substitute(l:dir, '\', '/', 'g') " so it works on windows
let l:ruby_cmd = "\"Dir.glob('" . l:dir . "/*_spec.rb').each {|f| require f}\""
exe('!ruby -e ' . l:ruby_cmd)
endfunction
The | separates Vim commands; for Vim, the mapping ends at the first |, and Vim tries to interpret the remainder as a command (which obviously fails). You need to either escape via \ or (better) use the special <Bar> notation in mappings:
:nnoremap ,t :!ruby -e "Dir.glob('./spec/*_spec.rb').each {<Bar>f<Bar> require f}"<cr>
Tips
You should use :noremap; it makes the mapping immune to remapping and recursion.
Bonus answer
You can get an upward directory search (:help file-searching) via finddir(), then pass the result to glob(). See
:echo finddir('spec', '.;')
(I would then move the implementation into a :function, and invoke that from the mapping. This would have also avoided the | escaping problem.)
I've written a few macros in my .vimrc for the version control system I'm using (Perforce) (please don't suggest the perforce plugin for vim, I tried it and I don't like it). They all work fine except the revert macro, which breaks due to a confirmation prompt (which I need so I don't accidentally fat-finger my changes away). It currently looks like this:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
This causes bash to complain when vim tries to load the file:
bin/bash: -c: line 0: syntax error near unexpected token `('
Looking at the buffer bash sees, it looks like the error is that vim sends it everything after the first pipe, not just the part meant for bash. I tried a few alternatives but I can't seem to make it work. I've got it to show confirm dialog correctly when I removed the pipes and endif (using shorthand if), but then vim complains after the user gives a response.
I think you want something along these lines:
:map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.
Building it up a piece at time, from the inside out:
There's a shell command you sometimes want to run.
That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
If that works, put the mapping in your .vimrc.
Use of the pipe to string multiple vim commands together is not particularly well-defined, and there are numerous eccentricities. Critically, (see :help :bar) it can't be used after a command like the shell command :! which sees a | character as its argument.
You might find it easier to use the system() function.
E.G.
:echo system("p4 revert " . shellescape(expand("%:p")))
The shellescape() wrapper is useful in case you have characters like spaces or quotes in the filename (or have cleverly named it ; rm -rf ~ (Don't try this at home!)).
In the interest of creating more readable/maintainable code, you may want to move your code into a function:
function Revert()
if confirm('Revert to original?', "&Yes\n&No", 1)==1
return system("p4 revert " . shellescape(expand("%:p")))
endif
endfunction
which you would access by using the :call or :echo command in your macro.
I have a bash script that runs (something like) the following command:
vim -E <<EOT
call Myfunc()
EOT
where Myfunc() is defined in my .vimrc. I've discovered that using the heredoc (but not simply calling it with -E and entering commands manually) causes vim to skip loading my .vimrc, consequently setting compatible mode (causing other problems down the road).
I can load my .vimrc manually if I have to, but I'm assuming I don't know a priori where it is, so I'd like to let vim do the work.
Does using the heredoc make vim set some other option (-u NORC, say), which I can just unset to get normal behaviour?
I'm in Vim 7.3, if it matters.
Giving arguments to vim through a heredoc is equivalent to taking input from stdin:
vim -E -
call Myfunc()
qa!
This starts vim in silent mode (see :help -s-ex) and only loads plugins specified by the -u argument. To load all plugins, write the ex command to a file and use that file for input:
cat <<EOT > input.vim
call Myfunc()
qa!
EOT
vim -E input.vim
(I added qa: to force vim to exit after running Myfunc().)
I'd like to set up my .vimrc so that NERDTree is open whenever vim (or MacVim) is called from the command line with a directory argument, but closed when vim is called with a file argument. I looked through the list of vim's built-in variables but couldn't find anything that looked promising.
Looked up arglist per Alligator's advice. Ended up with the following:
if argc() > 0 && isdirectory(argv(0))
autocmd VimEnter * silent NERDTree
endif
TextMate has a nice feature that allows you to execute a script from within the current context and shows you the output in a separate window. This lets you write and test code on the go. I'm almost certain there is a similar feature with MacVim/gVIM, but I'm not sure what it is. Currently I save my buffers to disk, then go to the command line and execute the script in that respect. How do I improve that workflow with vim?
You can do this in vim using the ! command. For instance to count the number of words in the current file you can do:
:! wc %
The % is replaced by the current filename. To run a script you could call the interpreter on the file - for instance if you are writing a perl script:
:! perl %
vim tutorial: Mapping keys in Vim
You can map keys so perl executes current script as suggested by jts above.
map <C-p> :w<CR>:!perl %<CR>
will map Ctrl+P to write file and run it by perl
imap <C-p> <Esc>:w<CR>:!perl %<CR>
lets you call the same in insert mode.
You should have .vimrc (_vimrc for Windows) file in your vim/home folder. It has instructions on how vim should behave.
map <C-p> :w<CR>:!perl %<CR> is just instruction to map Ctrl+p to:
a) write current the file :w
b) run command (perl) using % (currently open file) as parameter :!perl %
<CR> after each command stands for "carriage return": an instruction to execute specific command. imap does the same as map but listens Ctrl+p while in insert mode.
You could run it right from vim:
:!./script.sh
All suggestions here merely showcased :!{cmd} %, which passes current buffer to the shell cmd.
But there is another option :write !{cmd}
For example, the effect of the :write !sh command is that each line of the current buffer is executed in the shell.It is often useful, when for instance you've added a couple of lines to you buffer, and want to see execution result immediately without saving the buffer first.Also it is possible to execute some range, rather than whole content of the buffer::[range]write !{cmd}
save the file and call the script using an interpreter
eg.:
:!python %
It sounds like you're looking for !:
:!{cmd} Execute {cmd} with the shell.
You can use % to denote the current filename, if you need to pass it to the script:
!proofread-script %
You can also use ! with a range, to use the command as a filter:
!{motion}{filter} " from normal mode
:{range}!{filter} " from command mode
(In the first case, as with many other commands, when you type the motion, it'll pass you into command mode, converting the motion into a range, e.g. :.,.+2!)
And finally, if you don't actually need to pass input from your file, but want the output in your file, that's essentially a trivial filter, and the fastest way to do it is !!{cmd}. This will replace the current line with the output of the command.
To execute the current executable script, use
:!./%
! executes a shell command, % is the current filename and ./ adds the current dir in front.
Put this small snippet in your .vimrc to execute the current file with one keystroke (like F5) and display the result in a new split-pane buffer.
:! is okay but you need to switch to your terminal to see the result.
While you can do that with ctrl-z and bring vim back with fg it still means you need to switch context a lot.
The way this snippet works is by first guessing the executable based on the filetype and then running it with the current file as its argument.
Next a handy utility method takes the output and dumps it into a new buffer.
It's not perfect, but really fast for common workflows.
Here's the snippet copied below:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"""""""""""""""""""""""""" RUN CURRENT FILE """""""""""""""""""""""""""""
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Execute current file
nnoremap <F5> :call ExecuteFile()<CR>
" Will attempt to execute the current file based on the `&filetype`
" You need to manually map the filetypes you use most commonly to the
" correct shell command.
function! ExecuteFile()
let filetype_to_command = {
\ 'javascript': 'node',
\ 'coffee': 'coffee',
\ 'python': 'python',
\ 'html': 'open',
\ 'sh': 'sh'
\ }
let cmd = get(filetype_to_command, &filetype, &filetype)
call RunShellCommand(cmd." %s")
endfunction
" Enter any shell command and have the output appear in a new buffer
" For example, to word count the current file:
"
" :Shell wc %s
"
" Thanks to: http://vim.wikia.com/wiki/Display_output_of_shell_commands_in_new_window
command! -complete=shellcmd -nargs=+ Shell call RunShellCommand(<q-args>)
function! RunShellCommand(cmdline)
echo a:cmdline
let expanded_cmdline = a:cmdline
for part in split(a:cmdline, ' ')
if part[0] =~ '\v[%#<]'
let expanded_part = fnameescape(expand(part))
let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '')
endif
endfor
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded Form: ' .expanded_cmdline)
call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. expanded_cmdline
setlocal nomodifiable
1
endfunction
Well it depends on your OS - actually I did not test it on M$ Window$ - but Conque is one of the best plugins around there: http://code.google.com/p/conque/
Actually, it can be better, but works. You can embed a shell window in a vim "window".