How can one detect stdin input in .vimrc?
I have the following command in my ~/.vimrc:
autocmd BufWinEnter * silent loadview
to open a file with a cursor at the last line position. However, if I use vim on stdin, I get the following error message:
Error detected while processing BufWinEnter Autocommands for "*":
E32: No file name
Press ENTER or type command to continue
How can one detect that vim is used on stdin in .vimrc to suppress execution of the command in such cases?
Thank you for your help!
v:argv is a list that begins with the complete path of the program, and contains each argument, if any.
If you call Vim like this:
$ vim
:echo v:argv outputs something like:
['/path/to/vim']
If you call Vim like this:
$ vim foo.txt bar.json
:echo v:argv outputs something like:
['/path/to/vim', 'foo.txt', 'bar.json']
If you call Vim like this:
$ echo 'foo bar baz' | vim -
:echo v:argv outputs something like:
['/path/to/vim', '-']
Therefore, you can condition the execution of :loadview to the content of v:argv[1]. Note that we use get() because the index 1 may not exist:
autocmd BufWinEnter * if get(v:argv, 1, '') != '-' | silent loadview | endif
Reference:
:help :get()
:help v:argv
Related
It is easy to use vimscript to determine if a filename was specified to vim by using argc(). Is there a way to determine if the - flag was given to specify piped input was given to vim? It doesn't count piped input as a filename and argc() is empty.
Edit
Thanks to the wonderful accepted answer below, I have a way to open NerdTree if there are no filenames and stndin is not being used.
let wmuse_nt = 0
autocmd StdinReadPost * let wmuse_nt = 1
autocmd vimenter * if !argc() && wmuse_nt == 0 | NERDTree | endif
You could use an autocmd to run something before or after vim reads from stdin with the StdinReadPre or StdinReadPost events. The help is copied below.
StdinReadPost
StdinReadPost After reading from the stdin into the buffer,
before executing the modelines. Only used
when the "-" argument was used when Vim was
started --.
StdinReadPre
StdinReadPre Before reading from stdin into the buffer.
Only used when the "-" argument was used when
Vim was started --.
I just started learning Vimscript.
I want to write a function that opens the output of a bash function in a split.
If I do something like :call OutputScript("echo 'hello'"), I want a new buffer to open that has "hello" in it.
I tried the following code:
function! OutputScript(cmd)
if winbufnr(2) == -1
silent vsplit output
else
silent wincmd l
endif
silent normal ggdG
read! a:cmd
endfunction
If I :call OutputScript("echo 'hello'"), my output window looks like this:
bash: a:cmd: command not found
What syntax do I need to use cmd as a parameter for read?
Juste replace read! a:cmd by:
exe "read! ".a:cmd
The read command, as most of vim commands, don't expect vim variables. In order to use variables with common commands, you have to "encapsulate" it into an exe command, which can understand any vim expression.
The . is the vim operator for concatenating two strings.
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>
I usually open many files in tabs with vim -p. Is it possible to check if any of the files was changed outside of Vim since editing started?
Add these lines to your .vimrc:
au FocusGained,BufEnter * :silent! checktime
au FocusLost,WinLeave * :silent! w
Basically, check for and reload (or discard) external changes when Vim or the current buffer gains focus, and optionally, auto-save when leaving focus.
Source: Vim Wiki.
I came across an interesting find related to this question today...
Hidden in /usr/share/vim/vim71/vimrc_example.vim there is this command:
" Convenient command to see the difference between the current buffer and the
" file it was loaded from, thus the changes you made.
command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
\ | wincmd p | diffthis
It will open a vimdiff-like window with the current buffer and the underlying file highlighting all of the changes between the two.
vim usually warns me automatically if it detects an external change to a file; however, from perusing the documentation it looks like you can invoke that check manually with :checktime
Unfortunately I don't know how to disable that aforementioned automatic check to test and see if checktime does the right thing, so this answer might be completely off-base.
Use :edit
:help :edit for more info.
You can find out if the buffer in the active window is modified by running the command:
:set mod?
If it returns nomodified, then the contents of the buffer match those of the corresponding file. If it returns modified, then the buffer has unsaved changes.
By default, the status-line shows a [+] symbol if the current buffer has been modified. The status line is generally only visible if you have split windows. If you want to show the status line, even when you have just a single window, run:
:set laststatus=2
There's a good article about customizing your status line on Vim Recipes.
let s:pid=system("ps -p $$ -o ppid=")+0
if !exists('g:watches')
let g:watches={}
else
finish
endif
function! ModWatch(fname, match)
let fname=fnamemodify(a:fname, ':p')
if has_key(g:watches, fname)
return
endif
let shellscript=
\"while true ; do".
\" inotifywait ".shellescape(fname)." ; ".
\" kill -WINCH ".s:pid." ; ".
\"done"
echo shellscript
echo shellescape(shellscript)
let pid=system("sh -c ".shellescape(shellscript)." &>/dev/null & echo $!")+0
call extend(g:watches, { fname : pid })
augroup ModWatch
execute "autocmd! BufWipeOut ".a:match
execute "autocmd BufWipeOut ".a:match.' call DeleteWatch("'.
\escape(fname, '\"|').'")'
augroup END
endfunction
function! DeleteWatch(fname)
call system("kill ".g:watches[a:fname])
unlet g:watches[a:fname]
endfunction
augroup ModWatch
autocmd!
autocmd VimResized * checktime
autocmd BufNew * call ModWatch(expand("<afile>"), expand("<amatch>"))
augroup END
I finally decided to try out Vim, as I am getting increasingly frustrated by GUI editors. So far, I'm loving it, but I can't find any help for a issue I'm having...
I am trying to map the command :Pyrun to :!python % in Vim using cmap. The mapping shows up fine if I type :cmap. However, on typing :Pyrun, I get this error message:
Not an editor command: Pyrun.
Here is what I'm trying in .vimrc:
:autocmd FileType python :cmap Pyrun<cr> !python %<cr>
:autocmd FileType python :cmap Intpyrun<cr> !python -i %<cr>
What can I do to solve this problem?
I would try something like this in your .vimrc or your ftplugin/python_ft.vim
command Pyrun execute "!python %"
command Intpyrun execute "!python -i %"
Then :Pyrun and :Intpyrun should work
You could then map a function key to each
map <F5> :Pyrun<CR>
map <F6> :Intpyrun<CR>
I personally prefer another approach. First create a function receiving the command arguments and then create a command to call the function:
fun! DoSomething( arg ) "{{{
echo a:arg
" Do something with your arg here
endfunction "}}}
command! -nargs=* Meh call DoSomething( '<args>' )
So it would be like
fun! Pyrun( arg ) "{{{
execute '!python ' . expand( '%' )
endfunction "}}}
command! -nargs=* Pyrun call Pyrun( '<args>' )
But, there's a better way to do it in Vim. Use makeprg:
makeprg=python\ %
Just type :make to run your current Python file. Use :copen to show error list.
G'day,
Similar to karoberts answer, I prefer the more direct:
:map <F9> :!python %<CR>
If my script is creating some output I also like to capture it in a temp file and then autoread that files content into another buffer, e.g.
:map <F9> :!python % 2>&1 \| tee /tmp/results
I then set autoread by entering :set autoread and opening the results file in another buffer
:split /tmp/results<CR>
Then I can easily see the results of the run in the buffer that auto refreshes when the results file is updated by running the script under development.
HTH
cheers,
With new LUA api:
vim.api.nvim_create_user_command('Hello', 'echo "Hello World!"', {})
vim.api.nvim_create_user_command('HelloLua', function ()
print('Hello LUA!')
end, {})
NeoVIM API reference