VimScript: pass value of local variable to edit command - vim

I have written a simple function to invoke edit command with a path followed by the given filename.
However it looks like edit l:path invokes edit for file named "l:path" instead of l:path variable value. I guess this is a trivial issue, but it's hard to get search results for calling edit command in function, not from the vim editor.
Following code show the proper value of l:path when I change edit to echon.
command! -nargs=1 E call EditAtCurrentPath(<f-args>)
function! EditAtCurrentPath(filename)
let l:path=expand('%:p:h').'/'.a:filename
edit l:path
endfunction

You have to use :execute to pass variables to commands:
execute 'edit' l:path
There are some good examples in :help :execute.

Related

paste in "vimL normal execution" the string located in a register memory

How do I execute a command which involves a register data inside a vimL function?
say (as an example test case) I want to open a file whose direction string is in register z. During normal execution I could hit the keys:
:e <c-r>z<CR> # CR is "carret return", <c-r>z is "paste registry z"
In vimL it gets complicated. I tried the following options and are not working.
fun! OpenFileInBrackets()
exe 'normal! :e \<c-r>z'."\<cr>"
exe 'normal! :e <c-r>z'."\<cr>"
norm! :e <c-r>z<CR>
endfun
What are the options?
thank you!
Moving my comment to an answer.
My suggestion would be to use functions inside of vim scripts rather than their normal mode equivalents. In this case, to get the value from a register, use getreg().
Here's a quick example:
function OpenRegZ()
let filename = getreg("z")
execute "edit " . fnameescape(filename)
endfunction
A list of available functions can be found at :help function-list.
Edit: Added fnameescape() per the suggestion of :help execute.

Vim How to automatically return from user defined command

I defined the following command to export file selection into html file and then use Google Chrome to open it for printing
command! -range WebPrint <line1>,<line2>call Print()
function! Print()
:'<,'>TOhtml
:wq
:!/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome %:p.html
endfunction
One annoying thing is that every time I execute the command, the vim section is gone and I have to type Ctrl-c to go back (hitting <Enter> weirdly execute the command once again). If there a way to automatically return to vim section after the command is run?
From :help call:
When a range is given and the function doesn't handle it
itself, the function is executed for each line in the range,
Your Print function is defined without range, so it is invoked multiple times, once for each line in the selected range.
If that's not what you want, remove <line1>,<line2>.
See also :help function-range-example.

vimscript - edit another file from a custom command

I'd like to create, move around and append to other_file.py after calling a custom command from within this_file.py.
So for instance, I'd like to write several lines of text to a range of lines in the other file.
Is there some way I can basically enter :edit mode in other_file.py from this function? This would allow me to move around, search and append to other_file as though I were in it.
Here's a run through of where I'm at:
I am in this_file.py, and I have called:
:MyComm other_file:line_1/line_2/line_3
This activates the following vimscript:
function MyFunc(param_string)
let param_split = split(a:param_string,":")
let file_name = param_split[0] . ".py"
let lines = split(class_split[1],"/")
call system("touch " . file_name)
" Here is where I want to loop through the lines and use them in other_file.py
endfunction
:command -nargs=1 MyComm :call MyFunc(<f-args>)
alternative A
You can continue going through the external commands, as you've started with touch. So, you could use sed or awk to replace / append lines to the other file. With Vim's system() command, you can pass stdin input, too. For example, if you want to copy lines from the current buffer, grab them with getline() and pass them to system(), either as a List or a String.
alternative B
However, I would recommend avoiding external commands, and do the text editing tasks inside Vim. For that you just need to :execute 'split' other_file, and do the edits just as you would interactively, using Ex commands or :normal. Note that there are some special Ex commands (like :wincmd w replacing <C-w>w normal mode commands) that can make this more readable.

Vim: Issue normal-mode commands in user-defined command

I'm certain this will have been asked somewhere, but I can't for the life of me find it, and it's not in the Defining command-line commands section of the Vim documentation.
I want to create a user-defined command which will insert the word foo before the current word.
(Note: I want it to be a function because I don't trust myself to remember yet another shortcut key. I know how to do it with noremap...)
In my .vimrc I add:
command AddFoo bifoo<esc>w
But when I type :AddFoo I get Not an editor command: bifoow.
Is it possible to have a function which issues normal mode commands?
The :normal Ex command allows to issue arbitrary normal mode commands.
command AddFoo normal! bifoo<esc>w
If you want to interpolate expressions etc., you need to use :execute; I'll just show your example again with the use of :help key-notation:
command AddFoo execute "normal! bifoo\<esc>w"
The ! after :normal prevents the use of custom mappings, like :noremap (vs :map).
Please make sure you get the difference between a command and a function.
The right hand side of a command definition is supposed to be at least one Ex command like write or bnext:
command! Foo update | tabnext
You can call a function:
command! Bar call Bar()
or execute a normal mode macro:
command! Baz normal ciw"<C-r>""
See :help :normal.
Should be simple to get what you want, you just need to switch to normal mode to make your changes:
command AddFoo normal bifoo<esc>w

How to use Ctrl-R_= with :execute

I'm trying to get an expression on a variable expanded on a :execute command. I've guessed this could be achieved by using Ctrl-R_=, but it is not clear how the special characters should be inserted. None of the following worked:
exec 'echo ^R=1+1^M'
exec "echo <ctrl-r>=1+1<cr>"
The purpose is set a global variable used as an option in a plugin to select how to show the results. It is used on an :execute command, and works fine for 'vsplit' or 'split'. But the choice between vertical or horizontal split sometimes depends on the window layout. In order to do this without adding extra complexity to the plugin I've thought of something like the following:
let var = '<ctrl-r>=(winwidth(0) > 160 ? "vsplit" : "split")<cr>'
Edit
Currently the plugin has something like the following:
exec 'pluginCommands' . g:splitCmd . ' morePluginCommands'
The g:splitCmd is a plugin option, which works for when set with "split", "vsplit", "tabe", etc. My intent is to change this fixed behavior, setting g:splitCmd in such a way that it represents an expression on the execute above, instead of a fixed string.
Now that I'm understanding the issue better, I think a dynamic re-evaluation inside the config var is impossible if the variable's value is inserted in an :execute g:pluginconf . 'split' statement. To achieve that, you'd need another nested :execute, or switch to command-line mode via :normal! :...; both approaches will fail on the appended . 'split', because you can't add quoting around that.
The way I would solve this is by prepending a :help :map-expr to the plugin's mapping; change
:nmap <Leader>x <Plug>Plugin
to
:nnoremap <expr> <SID>(PluginInterceptor) PluginInterceptor()
:nmap <Leader>x <SID>(PluginInterceptor)<Plug>Plugin
Now, you're get called before the mapping is executed, and can influence the plugin config there:
fun! PluginInterceptor()
let g:plugconf = winwidth(0) > 160 ? "vsplit" : "split"
return ''
endfun
If modifying the plugin mapping is for some reason difficult, you could also trigger the PluginInterceptor() function via :autocmd; for this particular case e.g. on WinEnter events.
With :execute, you already have a way to evaluate expressions; just move them out of the static strings to get them evaluated:
exec 'echo ' . 1+1
The <C-R> only works in command-line mode (and insert mode), so only within a :cnoremap ... command (or with :normal). (And even there, you can use :map <expr>, which often gives you simpler code.)
I think that what you want is simply
:let var = (winwidth(0) > 160) ? "vsplit" : "split"
It seems to me like
exec 'pluginCommands' . eval(g:splitCmd) . ' morePluginCommands'
should work just fine, and is a simple solution to this problem.

Resources