How do you call a Vim built-in function? - vim

In section 4 of the Vim reference manual, it lists a number of builtin functions:
4. Builtin Functions *functions*
See |function-list| for a list grouped by what the function is used for.
(Use CTRL-] on the function name to jump to the full explanation.)
USAGE RESULT DESCRIPTION ~
abs({expr}) Float or Number absolute value of {expr}
acos({expr}) Float arc cosine of {expr}
add({object}, {item}) List/Blob append {item} to {object}
and({expr}, {expr}) Number bitwise AND
append({lnum}, {text}) Number append {text} below line {lnum}
How do I call these functions? How do I for example get the absolute value of a number?

You can call a built-in function like so, with the call command, or in an expression:
let x = abs(-2)
" or, for functions where you're not interested in the return value:
:call clearmatches()

The reference manual is borderline useless without the foundations provided by the user manual.
Functions are introduced in chapter 41 of the user manual:
:help usr_41.txt

First, note there is no visible difference between user functions and built-in functions from a usage point of view.
Functions that return nothing are meant to be called with :call -- note, that they will still always return 0.
The other functions return expressions. These expressions can be
used to build more complex expressions
as they are passed around to other functions
as they concatenated, added, multiplied...
as they are used as index getline('.')[col('.')-1]
passed to vim ex-commands that could be used to
:echo an expression
assign an expression into a variable with :let
:execute another vim ex-command, .e.g :exe line('$')/2

Related

Vim substitute() function flags order changes its behavior?

I have the following line made of tab separated strings ; I have sometimes multiple sequential <Tab>:
zer<Tab><Tab>abc<Tab>def<Tab><Tab>iop<Tab><Tab>
I want to insert the 'null' string between 2 consecutive <Tab> ; I run the following command:
:s/\t\(\t\)\#=/\tnull/eg
which give me as I expected:
zer<Tab>null<Tab>abc<Tab>def<Tab>null<Tab>iop<Tab>null<Tab>
The equivalent substitute function to the above command is (I echoed its result):
:echo substitute(getline('.'),'\t\(\t\)\#=','\tnull','eg')
which insert a <Tab> only between the first two <Tab>s:
zer<Tab>null<Tab>abc<Tab>def<Tab><Tab>iop<Tab><Tab>
whereas if I change the order of the substitute flags in the substitute function call ('eg' replaced by 'ge'):
:echo substitute(getline('.'),'\t\(\t\)\#=','\tnull','ge')
Then I get the expected result:
zer<Tab>null<Tab>abc<Tab>def<Tab>null<Tab>iop<Tab>null<Tab>
It seems that the order of the flags in the substitute() function change its behavior while it has no effect for the substitute command.
Does anyone have an idea why that ?
From my limited understanding of C, it looks like Vim only cares about the {flags} argument if its first character is g:
do_all = (flags[0] == 'g');
[…]
if (!do_all)
break;
This may explain the fact that :help substitute() only mentions g when explaining {flags}:
When {flags} is "g", all matches of {pat} in {expr} are
replaced. Otherwise {flags} should be "".
The :substitute command can take many flags, but the substitute() function only supports the g flag. Flags like c (for interactivity) or e (for error suppression) do not apply to the low-level function.

Vim Custom Replace Function

Note: I'm currently using Neovim v0.2.2 (But I believe this shouldn't change anything related this post)
I'm currently attempting to create a function within vim that allows for easily replacing text.
I understand I can create a shortcuts and macros and all that, but ideally I just want to give 2 args, and not think about what specifics go where as this can interupt my thought process.
So I decided to just have a simple wrapper disguised as a function (Which I will create a command wrapper for as well, once I figure out what I did wrong here)
function! VisualReplace(query, replacement)
" Example = '<,'>s/query\%V/replacement/g
'<,'>s/a:query\%V/a:replacement/g
endfunction
As you can see, it's a very simple function that just applies the args in it's respective position, Yet, this fails even when called as a function using : call VisualReplace('some_query', 'some_replacement'
Alternatively, if you simply use the Example I have commented out directly, there's no issue, So I was hoping someoen could enlighten me on a potential fix
If need be, I could possibly look into string building & build it incrementally
Error msg:
Pattern not found: a:query\%V
General theory
Vimscript is evaluated exactly like the Ex commands typed in the : command-line. There were no variables in ex, so there's no way to specify them. When typing a command interactively, you'd probably use <C-R>= to insert variable contents:
:sleep <C-R>=timetowait<CR>m<CR>
... but in a script, :execute must be used. All the literal parts of the Ex command must be quoted (single or double quotes), and then concatenated with the variables:
execute 'sleep' timetowait . 'm'
Your function
In order to get the a:query and a:replacement arguments into :substitute, use :execute and either string concatenation or printf():
function! VisualReplace(query, replacement)
execute "'<,'>s/" . a:query . '\%V/' . a:replacement . '/g'
endfunction
Additional critique
Passing a range to a function is so common, there's special syntactic sugar for it: The range attribute to :function, and a:firstline and a:lastline implicit arguments. Read more about it at :help function-range-example. While your use case here seems to be specifically for visual mode, in general it's useful to keep the scope of functions as broad as possible.
#Ingo Karkat answered perfectly. However, I feel like there might be some workflow alternatives which might help. (Assuming you aren't trying to script this behavior)
Visual Star
It looks like you are build a search based on a visual section. You may want to consider using a visual-star plugin to simplify the process. Here is a an example of a visual star mapping:
xnoremap * :<c-u>let #/=#"<cr>gvy:let [#/,#"]=[#",#/]<cr>/\V<c-r>=substitute(escape(#/,'/\'),'\n','\\n','g')<cr><cr>
This mapping will allow you to visually select text and then execute * to make it a search pattern. Similar to how * works in normal mode on the current word.
Search refining
I get the impression that you are trying to refine your search pattern. Vim has a nice way of doing this with q/ or pressing <c-f> while searching with /. See :h q/. This will bring up the command-line window which will allow you to edit the query/command-line with all your normal Vim keys.
Search and Replace with gn motion
Sometimes doing a substitution is just overkill or doesn't quite fit the situation right. You can mimic a search and replace by using the gn motion to operate on a search pattern. By using an operator and the gn motion together you can use the dot command, ., to repeat the action easily.
Example:
/foo
cgnbar<esc>
Now you can use . to repeat the foo -> bar replacement. Use n to skip. You can use other operators as well, e.g. gU to uppercase.
See :h gn and :h operator for more help.
Related Vimcasts episodes:
Refining search patterns with the command-line window
Operating on search matches using gn
Search for the selected text

When to use vim.eval and when to use vim.command in python-vim?

From vim doc:
vim.command(str) *python-command*
Executes the vim (ex-mode) command str. Returns None.
vim.eval(str) *python-eval*
Evaluates the expression str using the vim internal expression
evaluator (see |expression|). Returns the expression result as:
- a string if the Vim expression evaluates to a string or number
- a list if the Vim expression evaluates to a Vim list
- a dictionary if the Vim expression evaluates to a Vim dictionary
Dictionaries and lists are recursively expanded.
I am having trouble to distinguish these two, perhaps it's because I don't understand the difference between expression and command in the first place. An explanation with some examples is very very welcome.
TL;DR: Use command() to execute a Vim command for its side effects, and eval() to get back a value computed by a Vimscript function.
Like other programming languages, Vim(script) distinguishes between a procedure (which you just invoke, but get nothing back; the interesting thing is the actions it performs), and a function (that returns a value, and can optionally also perform actions like a procedure).
Example
With :split foo.txt, you invoke this to open a file in a window split. The command returns nothing, but its effects can be easily observed (another window opens, a file being edited in there). You'd use vim.command() for that.
With :echo winnr('$'), you query the number of open windows. The :echo prints that value, but if you wanted that in Python, you'd use vim.eval("winnr('$')"). (But note that certain Vim properties are already exposed by the Python integration in Vim; you'd only use this for stuff that's not available in Python yet.)
assume you have two strings:
"5d"
and
"5+5"
if you call command() on those, it is same as in vim press :, then input command.
"5d" -> remove the 5th line
"5+5" -> move cursor to 10th line
if you call eval(), vim evaluates the string as vim expression
"5d" -> error
"5+5" -> 10

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.

Using Vim, how do you use a variable to store count of patterns found?

This question was helpful for getting a count of a certain pattern in Vim, but it would be useful to me to store the count and sum the results so I can echo a concise summary.
I'm teaching a class on basic HTML to some high schoolers, and I'm using this script to be quickly check numbers of required elements throughout all their pages without leaving Vim. It works fine, but when students have more than 10 .html files it gets cumbersome to add up the various sections by hand.
Something like:
img_sum = :bufdo %s/<img>//gen
would be nice. I think I'll write a ruby script to check the pages more thoroughly and check for structure, but for now I'm curious about how to do this in Vim.
The problem can be solved by a counter separate from the one built-in into the
:substitute command: Use Vim-script variable to hold the number of pattern
matches. A convenient way to register every match and modify a particular
variable accordingly, is to take advantage of the substitute with an
expression feature of the :substitute command (see :help sub-replace-\=).
The idea is to use a substitution that evaluates an expression increasing
a counter on every occurrence, and does not change the text it is operating
on.
The first part of the technique cannot be implemented straightforwardly
because it is forbidden to use Ex commands in expressions (including \=
substitute expressions), and therefore it is not possible to use the :let
command to modify a variable. Answering the question "gVim find/replace
with counter", I have proposed a simple trick to overcome that limitation,
which is based on using a single-item list (or dictionary containing a single
key-value pair). Since the map() function transforms a list or a dictionary
in place, that only item could be changed in a constrained expression context.
To do that, one should call the map() function passing an expression
evaluating to the new value along with the list containing the current value.
The second half of the technique is how to avoid changing text when using
a substitution command. In order to achieve that, one can make the pattern
have zero-width by prepending \ze or by appending \zs atoms to it (see
:help /\zs, :help /\ze). In such a way, the modified pattern captures
a string of zero width just before or after the occurrence of the initial
pattern. So, if the replacement text is also empty, substitution does not
cause any change in the contents of a buffer. To make the substitute
expression evaluate to an empty string, one can just extract an empty
substring or sublist from the resulting value of that expression.
The two ideas are put into action in the following command.
:let n=[0] | bufdo %s/pattern\zs/\=map(n,'v:val+1')[1:]/ge
I think that answer above is hard to understand and more pretty way to use external command grep like this:
:let found=0
:bufdo let found=found+(system('grep "<p>" '.expand('%:p') . '| wc -l'))
:echo found

Resources