Various ways to execute a function in vim - vim

I've been doing some trial-and-error on how functions can be called, and it seems like the following is my understanding:
From the command line, typing in :call MyFunction()
From the command line, typing in :call execute('call MyFunction'), where execute essentially performs a string escape (if that's the correct term?) to pass back to the first call param.
From within a function or vim file, typing in call MyFunction(). In other words, each line in a vim function/file acts like the command-line.
From within a function or vim file, typing in call execute('call MyFunction')
Is that a correct understanding of the various ways to call a function? Are there any other possible ways to do it?

I don't really understand what you are doing, but if you ask if there are other ways to call a function, yes, there are.
For example,
the eval(...) can call another function
echo getline('.') or something like this
:s/../\=getline(...)
in expr mappings
...
Simply put, in almost any place when a vimscript can be evaluated, a function can be called.

Related

How to get the arguments during a custom defined command?

I have this custom command that I want to define. But I can't manage to get the arguments separately:
:command -nargs=2 :%s/<args1>/<args2>/gc // <args1> <args2> dont work
Anyone has some solution for this?
<args1> and <args2> doesn't exist. You invented this yourself. The easiest way to do this is to use a function wrapper and <f-args>:
fun! s:sub(search, replace)
execute ':%s/' . a:search . '/' . a:replace . '/gc'
endfun
command! -nargs=+ Replace call s:sub(<f-args>)
<f-args> splits the the command arguments at whitespace and adds proper quoting and commas, in order to pass it to a function.
Using a function wrapper also has the added benefit of resetting the #/ register after its finished running. If you don't want this, then explicitly assign it with let #/ = a:search.
Other than this, almost everything about your :command call is wrong:
-nargs=2 isn't supported − see :help :command-nargs
You forgot to fill in the command name.
// isn't used to denote comments in VimScript; " is used for that.
See :help :command for a full description of the syntax.

how to understand these vim scripts

I have two question about understand those vim script. please give some help,
Question 1:
I download a.vim plugin, and i try to read this plugin, how to understand the below variable definition? the first line I can understand, but the second line, I don't know exactly "g:alternateExtensions_{'aspx.cs'}" means.
" E.g. let g:alternateExtensions_CPP = "inc,h,H,HPP,hpp"
" let g:alternateExtensions_{'aspx.cs'} = "aspx"
Question 2:
how to understand "SID" before the function name, using like below function definition and function call.
function! <SID>AddAlternateExtensionMapping(extension, alternates)
//omit define body
call <SID>AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC")
call <SID>AddAlternateExtensionMapping('H',"C,CPP,CXX,CC")
thanks for you kindly help.
let g:alternateExtensions_{'aspx.cs'} = "aspx"
That is an inline expansion of a Vimscript expression into a variable name, a rather obscure feature that is rarely used since Vim version 7. See :help curly-braces-names for details. It is usually used to interpolate a variable, not a string literal like here ('aspx.cs'). Furthermore, this here yields an error, because periods are forbidden in variable names. Newer plugins would use a List or Dictionary variable, but those data types weren't available when a.vim was written.
To avoid polluting the function namespace, plugin-internal functions should be script-local, i.e. have the prefix s:. To invoke these from a mapping, the special <SID> prefix has to be used instead of s:, because <SID> internally gets translated into something that keeps the script's ID, whereas the pure s:, when executed as part of the mapping, has lost its association to the script that defined it.
Some plugin authors don't fully understand this unfortunate and accidental complexity of Vim's scoping implementation either, and they put the <SID> prefix also in front of the function name (which works, too). Though it's slightly more correct and recommended to write it like this:
" Define and invoke script-local function.
function! s:AddAlternateExtensionMapping(extension, alternates)
...
call s:AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC")
" Only in a mapping, the special <SID> prefix is actually necessary.
nmap <Leader>a :call <SID>AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC")
<SID> is explained in :help <SID>:
When defining a function in a script, "s:" can be prepended to the name to
make it local to the script. But when a mapping is executed from outside of
the script, it doesn't know in which script the function was defined. To
avoid this problem, use "<SID>" instead of "s:". The same translation is done
as for mappings. This makes it possible to define a call to the function in
a mapping.
When a local function is executed, it runs in the context of the script it was
defined in. This means that new functions and mappings it defines can also
use "s:" or "<SID>" and it will use the same unique number as when the
function itself was defined. Also, the "s:var" local script variables can be
used.
That number is the one you see on the left when you do :scriptnames, IIRC.

How to expand function arguments in Vim command line?

Vim's Utl plugin offers a convenient way for doing web queries from within the editor. When called directly from the command line, a dictionary lookup can be done like this:
:Utl ol http://dict.leo.org/?search=my+search+term
What's the correct way for defining a custom command with the same purpose (my+search+term being user input)? I can't seem to get <f-args> right with this one:
command -nargs=1 SearchLeo :exe ":Utl ol http://dict.leo.org/?search=" . expand("<f-args>")
What's the correct way of defining function arguments here? Or should I turn this into a more complete function? Thanks!
You probably don't need expand() here; it's just for expanding globs (like *.txt) or the special variables like % for the current file.
You're quoting the argument twice, once through <f-args> (<q-args> would be slightly more correct, though it only matters with a variable number of arguments), once literally.
Use this:
command -nargs=1 SearchLeo :exe ":Utl ol http://dict.leo.org/?search=" . <q-args>

How to distinguish between line-address and line-range in vim?

This is a simple user-defined function:
fun! Foo() range
echo a:firstline a:lastline
endfun
:5call Foo() and :5,5call Foo() give me the same result.
However, :5j and :5,5j give me different results.
Can I write a function which behave like join?
How does join distinguish between line address and line range?
By defining a custom :command, the -range and -count attributes allow you better control over how the range is consumed. However, I think even that won't allow you to exactly duplicate the behavior of :join. The interface for custom Vim commands is not as rich as what is available to built-in commands.
As a workaround, you could use histget('cmd', -1) to get the command-line that invoked your command, and parse the exact command invocation, including the original range (which can then be re-used by passing it to another command, but doing line arithmetic with it is problematic, since it's the raw range, not the actual line numbers). The workaround will only work for interactive commands, is brittle, and demands some effort. Maybe you can avoid the issue altogether by defining two different commands instead.

Vim search and highlighting control from a script

I'm writing a script in which I want to control searches programmatically, and get them highlighted. The search() function results are not highlighted (I think), so using that function is not of use to me.
What I want to do is use the 'normal /' command to search for a variable, but that doesn't seem to be straightforward. I can script the command:
execute 'normal /' . my_variable . '\<CR>'
(or other variations as suggested in the vim tip here: http://vim.wikia.com/wiki/Using_normal_command_in_a_script_for_searching )
but it doesn't do anything. I can see the correct search term down in the command line after execution of the script line, but focus is in the document, the search register has not been altered, and the cursor has not done any search. (It seems as though the < CR > isn't getting entered, although no error is thrown -- and yes, I have tried using the literal ^M too.)
I can at least control the search register by doing this:
execute 'let #/ ="' . a:term .'"'
and then the obvious thing seems to be to do a:
normal n
But that 'normal n' doesn't do anything if I run it in a script. Setting the search register does work, if I manually press 'n' after the scrip terminates the search happens (and highlighting appears, since hlsearch is on). I don't even care if the cursor is positioned, I just want the register pattern to be highlighted. But various combinations of 'set hlsearch' in the script don't work either.
I know I could use 'match()', but I want to get it working with regular search highlighting, and I wonder what I'm doing wrong. It must be something simple but I'm not seeing it. Thanks for any help.
run:
let #/ = a:searchStr
from inside your function then run
normal n
from outside your function (inside it does nothing) eg.
command -nargs=* Hs call MySearch() | normal n
or you can use:
set hlsearch
instead of normal n if you don't want the cursor to move
(I cannot work out another way of doing this without having something outside the function.)
If your script is using functions, then this quote from :help function-search-undo is relevant:
The last used search pattern and the redo command "."
will not be changed by the function. This also
implies that the effect of :nohlsearch is undone
when the function returns.
Vim usually tries to reset the search pattern (and a few other things) when a function ends, often you can get around this by adding the n (next search) to the end of a mapping, or using :map <expr> and having your function return the key sequence to be executed.
On closer inspection, it seems \<CR> is not picked up inside single quotes. Try using this instead:
execute 'normal /' . my_variable . "\<CR>"

Resources