I have a string (as a result of another function, but for now let's store it in s for sake of simplicity) and I want to write it out, through a pipe to a bash command. (It has to be a pipe, the command does not accept this kind of input as an argument.)
So the question is, how should I invoke mycommand, that is, what goes to ...?
function! MyFunc()
let s = "my string"
execute ... !mycommand --flag
endfunction
Via here string:
:let s = "my string"
:set shell=/bin/bash
:exe "!cat <<< " . shellescape(s)
Output
my string
Via pipe:
:exe "!echo " . shellescape(s) . " | cat "
Could you try this
:execute "!\"".s."\" | mycommand"
Related
I have some specific parts of files with unformated xml code. I need to write a vimscript function that selects the text and calls xmllint over it.
I know I can do this on the command line :'<,'>!xmllint --format -
But I really need to do the same in a vimscript function and I don't know how to make something like normal! call for visual.
I tried this but it does not work correctly :
function! MyFormat()
... stuff done here
let startl = line("'<")
let endl = line("'>")
let line = getline(startl, endl)
let r = system('echo "' . join(line, "") . '" | xmllint --format -')
call setline('.', r)
endfunction
Every line in a Vim script is an Ex command. Since you already have a working Ex command, you might as well use it.
function! MyFormat()
" ... stuff done here
'<,'>!xmllint --format -
" ... more stuff done here
endfunction
But, again, data is missing so this might work… or not, be sufficient… or not, etc.
So I want to be able to type something like:
:hello
in vim normal mode and then have it echo out 'hello sir'.
I made the below vimscript into a plugin, and I get the error:
Not an editor command
What am I doing wrong?
vimscript
if exists("g:hello_world") || &cp || v:version < 700
finish
endif
let g:hello_world=1 " your version number
let s:keepcpo = &cpo
set cpo&vim
fun! s:hellosir()
echo 'hello sir'
endfun
command hello call hellosir()
steffen's answer is correct, but here is an example with an argument:
" a highlight color must be set up for the function to work
highlight blue ctermbg=blue guibg=blue
function! Highlight(text)
:execute "match blue /" . a:text . "/"
endfunction
:command! -nargs=1 Highlight :call Highlight(<q-args>)
To run it and highlight all occurrences of a regex:
:Highlight foobar
Note that I try not to abbreviate commands/functions in .vimrc. Save abbreviations for when you're typing on the command line.
Define your function (note the uppercase letter for user-defined functions):
:fun! Hellosir()
: echo 'hello sir'
:endfun
Now call it:
:call Hellosir()
hello sir
It is also possible to define your own ex command:
:command Hello :call Hellosir()
:Hello
hello sir
EDIT
You can combine both: Make the function script-local and access it with your (global) ex command:
fun! s:hellosir()
echo 'hello sir'
endfun
command Hello call s:hellosir()
What is wrong relates with this line:
command hello call hellosir()
First, from :h user-cmd-ambiguous
All user defined commands must start with an uppercase letter, to avoid
confusion with builtin commands. Exceptions are these builtin commands:
:Next
:X
They cannot be used for a user defined command. [...]
Second, that you have to call your function with the s: prefix in that command.
How can I access the arguments that were given to Vim on the command line under Windows?
I'm looking for the the equivalent to argv[] in C.
Under linux you can read /proc/self/cmdline.
Example:
vim -c ":echo split( readfile( \"/proc/self/cmdline\", 1 )[0], \"\n\" )"
print
[
'vim',
'-c',
':echo split( readfile( "/proc/self/cmdline", 1 )[0], "\n" )'
]
argc() and argv() don't work. They just return number of files.
Example:
vim -c ':echo "argc:" . argc() . ", argv:" . string( argv() )' file1 file2
print
argc:2, argv:['file1', 'file2']
:help argc()
:help argv()
:help argidx()
And maybe also :help argument-list, just to be sure.
Simple example:
for arg in argv()
echo arg
endfor
In the specific case of needing argv[0] (i.e., the name vim was called by), you can use v:progname.
I have a line in one of my functions
silent! exec "r!sh myScript '" . a.1 "'
this prints the output of myScript to the current buffer.
myScript outputs a single filename. Instead of printing the filename to the buffer I'd like to open that file.
I've tried things like
silent! exec "open!sh myScript '" . a.1 "'
silent! exec "new!sh myScript '" . a.1 "'
let l:file = silent! exec "sh myScript '" . a.1 "'
new l:file
but none seem to work.
Am I missing something obvious?
I would suggest using the system() function in this way:
let path=system("myScript ... ")
let path=substitute(path,"\n","","g")
exec "edit" path
Note that the intermediate substitute command may be necessary to remove erroneous newline characters. If it isn't necessary, don't worry about it. Of course, instead of edit you can use split or vsplit etc to suit your needs.
How can I redirect or pipe the output of an ex command into my current buffer or a file?
For example, I want to read the contents of all the registers into the current buffer, which in ex mode is shown using :registers.
:redir >name_of_registers_file
:registers
:redir END
:r name_of_registers_file
:help redir
The last command is very useful, since there are lots of options for redirection: to variables, to registers, how to append, further cornucopia.
I still find it weird and annoying that it uses END that way, but since everything else that can follow redir has to start with a non-word-character, at least it's not ambiguous.
PS AFAIK (which is pretty far in this case) there's no way to read it directly into the buffer: you have to store it in a register or a variable first. Check the help for the various options of how to do that.
PPS If you do want to do this using a variable —maybe to encapsulate it in a function and avoid clobbering registers or global variables— you'll have to convert the multiline string that gets written to the variable into a list. EG
:call append( '.', split(variable_you_redirected_to, "\n") )
Otherwise (if you just do append('.',var)) you end up with ^#'s (nulls) instead of newlines, since that's what vimscript uses to represent newlines in String variables.
edit: as #Bill Odom mentions, using :put =variable_you_redirected_to is a lot easier than the complicated append() expression. Thanks, Bill!
PPPS
I've written a snippet to make this stuff more convenient. It declares a function Redir(command, target) and a command R.
The command parses the last series of non-space characters as a redirection target and passes that to the function, which does the boilerplate to redirect the command output to the redirection target.
The command is everything after R and before the last space.
EG
" Store the vim buffer list in buffer_list.txt
:R ls >buffer_list.txt
" Store error messages emitted by a function being debugged
" in the 'unnamed register'
:R call FunctionBeingDebugged() #">
There are a few limitations with this: for example you won't be able to write to a filename that contains a space. The upside to this is that you don't have to quote your command. I've got it posted on gist.github.com, and I'll try to keep it updated if I end up improving it. Or you can fork it yourself</noeuphemism>!
Anyway the snippet is available here. It can be dropped into a .vimrc file or into a file in ~/.vim/plugins.
#intuited is right; the redir command is what you want. A one-liner like this will insert the output of :registers into the current buffer:
redir => m | silent registers | redir END | put=m
That's not something you'll want to type very often, however, and it's not exactly amenable to a key map. I found myself doing this fairly often, so I wrote a function and a handful of commands to make it easier. As a bonus, I can now send command output to a new window or new tab as easily as inserting it into the current buffer. Here's the code (with a few command examples at the very end):
" redir_messages.vim
"
" Inspired by the TabMessage function/command combo found
" at <http://www.jukie.net/~bart/conf/vimrc>.
"
function! RedirMessages(msgcmd, destcmd)
"
" Captures the output generated by executing a:msgcmd, then places this
" output in the current buffer.
"
" If the a:destcmd parameter is not empty, a:destcmd is executed
" before the output is put into the buffer. This can be used to open a
" new window, new tab, etc., before :put'ing the output into the
" destination buffer.
"
" Examples:
"
" " Insert the output of :registers into the current buffer.
" call RedirMessages('registers', '')
"
" " Output :registers into the buffer of a new window.
" call RedirMessages('registers', 'new')
"
" " Output :registers into a new vertically-split window.
" call RedirMessages('registers', 'vnew')
"
" " Output :registers to a new tab.
" call RedirMessages('registers', 'tabnew')
"
" Commands for common cases are defined immediately after the
" function; see below.
"
" Redirect messages to a variable.
"
redir => message
" Execute the specified Ex command, capturing any messages
" that it generates into the message variable.
"
silent execute a:msgcmd
" Turn off redirection.
"
redir END
" If a destination-generating command was specified, execute it to
" open the destination. (This is usually something like :tabnew or
" :new, but can be any Ex command.)
"
" If no command is provided, output will be placed in the current
" buffer.
"
if strlen(a:destcmd) " destcmd is not an empty string
silent execute a:destcmd
endif
" Place the messages in the destination buffer.
"
silent put=message
endfunction
" Create commands to make RedirMessages() easier to use interactively.
" Here are some examples of their use:
"
" :BufMessage registers
" :WinMessage ls
" :TabMessage echo "Key mappings for Control+A:" | map <C-A>
"
command! -nargs=+ -complete=command BufMessage call RedirMessages(<q-args>, '' )
command! -nargs=+ -complete=command WinMessage call RedirMessages(<q-args>, 'new' )
command! -nargs=+ -complete=command TabMessage call RedirMessages(<q-args>, 'tabnew' )
" end redir_messages.vim
:redir #a
:registers
:redir END
"ap
:redir #a redirects all messages from here on to a register named a. You follow this with your command whose output you want to capture (:registers in your case). :redir END ends the redirection. "ap means, "a uses the register named a and p puts the contents of the selected register into the current buffer.
See Capture ex command output at Vim Tips Wiki for more information :-)
In addition, :h :redir:
...To get the output of one command the |execute()| function can be used.
e.g.
put = execute('scriptnames')
put = execute('filter /vimfiles/ scriptnames')
It is not necessary to use a temporary variable as long as you can save the current buffer and are ok with appending the messages to the end of the current file.
From the Vim documentation:
:redi[r] >> {file} Redirect messages to file {file}. Append if {file}
already exists. {not in Vi}
http://vimdoc.sourceforge.net/htmldoc/various.html#:redir
So, to append the messages from :registers to the bottom of the current file, do this:
:write | redir >> % | silent registers | redir END | edit
:write the file so that any changes won't be lost
Begin redirecting output to %, the name of the current file.
Silently run the :registers command.
END redirecting to the file.
:edit the file to see the new changes.
You can also forcefully truncate the current file and replace it with the output messages:
:redir! > % | silent registers | redir END | edit!
But that is probably not what you want to do.
Unfortunately I have no rep, so I cannot add this as a comment to 'Francis Niu'.
The execute() function looks like the easiest way to accomplish this, and it was added in vim 8 .
Listed in the new/extended features on vim's github. version8.txt