How to set numeric variables in vim functions - vim

I'm trying to write a function that calls setlocal to set some variables to the param(s) that I pass in. But I'm getting the error Number required after =: tabstop=...
function! MyFunction(param)
setlocal tabstop=param
setlocal tabstop=a:param
endfunction
Both lines will fail. Is there some sort of variable interpolation I'm missing?

You need to define the option as an &option variable. For example:
fun! MyFun(param)
let &l:tabstop = a:param
endfun
See :help let-&. The &l: is listed a little below that tag showing that it is for the equivalent of setlocal. Basically, when you want to set an option to an expression instead of a defined value then you need to use let &option= instead of set option=. Use let &l:option= instead of setlocal option=. There is also &g:option to set the option globally.

Related

Display the current status of `expandtab` in statusline in macvim

I am currently using vim-airline in my macvim and I want to display the status of expandtab whether it is set or not in the statusline.
I can find out the status of expandtab by running the following command :set expandtab?. From the vim-airline documentation I found that I can use something like this
let g:airline_section_b = '%{getcwd()}'
I modified it to
let g:airline_section_b = '%{expandtab?}'
but I am getting the error undefined variable: expandtab.
Can someone kindly tell how I can retrieve the status of expandtab and then show it in the status line. Thanks.
:set does not access variables, so you cannot use the question mark to query variables.
You are trying to access the variable expandtab variable, which doesn't exists. You actually want to access an option setting and those are accessed using the & prefix.
Sou you should add:
let g:airline_section_b = '%{&expandtab}'
Note, the quesion mark is not necessary and has no special meaning for VimL.
See :h expr-option for the details.
Update
This will only display 1 (expandtab set) or 0 (expandtab not set). What should work however is something like this:
let g:airline_section_b = '%{&expandtab?"et":"noet"}'
Which will display 'et' when expandtab is set or 'noet' when expandtab is not set. This uses the <cond>?<true>:<false> expression to display a certain string depening on the value of the <cond> condition. This is explained in the help below :h expr1
Vim options can be accessed live variables if prefixed with &. Example:
let g:airline_section_b = '%{&expandtab}'
See :h :let-& for more

Why can't a variable be passed into the MacVim :colorscheme function?

I'd like to set a mapping to loop through a list of colorschemes in MacVim.
Ideally, I'd have an array of color schemes like this:
let s:schemes = ['zellner','ron','morning','murphy','peachpuff','torte']
And in a function set the colorscheme to an index of this array:
colorscheme s:schemes[s:schemeindex]
However this above line does not work. Why?
Instead, I use a workaround which works fine:
function SwitchScheme()
if s:schemeindex == 0
colorscheme zellner
s:schemeindex = 1
elseif s:schemeindex == 1
colorscheme ron
s:schemeindex = 2
...
endif
endfunction
My question is, is there a cleaner way to do this? I'd like to pass a variable to the colorscheme setter function but this doesn't seem to be working.
Are these scheme names constants and if so how do you assign them to a variable?
Many thanks.
:colorscheme is just limited, like some others such as :source, in that it takes the rest of the line literally, i.e. it can't use a VimL expression as argument. This limitation is generally worked around by using :execute, e.g.
execute 'colorscheme '.s:mycolors[current]
This comes from a a color scheme switcher posted at the Vim Tips wiki.

How to set an option, using let, for the current buffer (vim)?

In vimlanguage, you can set options for the current buffer only using setlocal.
However, I need to set a more complex expression than just a literal, which isn't possible with setlocal.
I currently have let &formatprg=s:prgpath." ".a:args, but this sets the formatprg for all buffers, which is not what I want.
How would I set the formatprg like above, only for the current buffer?
Use let &l:option instead of let &option to only change the local value, like setlocal option. Similarly, let &g:option would only set the global value, like setglobal option. See :help :let-option for more information.
Note that formatprg in particular is global (no "local to buffer" in its help).
Making a global option buffer-local requires changes to Vim's source code. Alternatively, I've just published the GlobalOptions plugin that uses autocmds to work around this, and turns any global option into a buffer- or window-local one.

Vim: What's the difference between let and set?

What's the difference between let and set in the vim editor?
I've always wondered why both of them exist?
Also, I'd be interested to hear its historical background.
:set is for setting options, :let for assigning a value to a variable.
It happens that the value for an option is linked to the name of the option prepended by a & (the &option-name construct then behaves very similar to "ordinary" variables). So, the following are equivalent:
:set tw=40
:let &tw=40
But, for example, assigning 50 to the global variable foo (:let g:foo=50) cannot be achieved with a :set command (because g:foo is a variable and not an option).
Some options are boolean like. When setting these, no value is needed (as in :set noic and the opposite :set ic).
Set is a more user-friendly interface specialized for options
E.g.
:verbose set
to display all options in effect.
:set tw=40
Will work as a shorthand for set textwidth=40
:set wrap&
Will set the default value for option wrap
:set nowrap
Will unset the option
:set wrap!
Will toggle the option
Most importantly,
:setTab # to get tab completion!
Few of the above can (easily) be achieved with let.
:set only works with options, and sehe's answer showcases some good usage examples.
:let on the other hand can do almost everything that :set can do, plus more. It can assign a value to
a variable, e.g. let vi = 'vim'
an option, e.g. let &tw = 40
a register, e.g. let #a = $HOME . '/vimfiles'
an environment variable, e.g. let $NOTHING = 'NOTHING'
Another major difference is that the right hand side of :let is an expression, meaning you can do things like string concatenation (as seen in my register example above) and arithmetic operations (e.g. let &tw = 40 + 60). This also means that you have to quote the value if it's a string. :set on the other hand reads the value verbatim.
It's easier to use :set with options even though :let can also do most of it, Here are some comparison using sehe's examples ("n/a" means no way to do it with :let)
:verbose set vs n/a (don't think there's another way to list all options)
:set tw=40 vs :let &tw = 40 (yes, you can use the same shorthand in let too)
:set wrap& vs n/a
:set nowrap vs :let &wrap = 0 (for boolean options, 0 is false and 1 is true)
:set wrap! vs :let &wrap = !&wrap
A few more examples
print the value of an option: :set formatoptions? vs :echo &formatoptions (let doesn't print values, unlike set)
assigning to multiple options at the same time:
:set et sw=4 sts=4
vs
:let [&et, &sw, &sts] = [0, 4, 4]
set global option: setglobal et vs let &g:et = 1
set local option: setlocal et vs let &l:et = 1
See :h :set and :h :let for more details
tl;dr
:set only works with options but the syntax is much simpler. :let works with not just options but also variables, registers, and environment variables. Unlike :set, the right hand side of :let is an expression.
Expanding on what people have written about :let, I've noticed that it can be used to assign a value in a variable to an option, something :set can't do. For example, this function uses let to assign the value in the global variable orig_tw to the textwidthoption:
" Toggle Autowrap
" Default of 72 but can be overridden by tw settings in other vimrc files
let g:orig_tw = 72
function Toggle_autowrap_mode()
if &textwidth == 0
" Must use let instead of set here in order for g:orig_tw to be
" evaluated properly
let &textwidth = g:orig_tw
echo "Autowrap mode on tw=" . &textwidth
else
let g:orig_tw = &textwidth
set textwidth=0
echo "Autowrap mode off tw=" . &textwidth
endif
endfunction
noremap _A :call Toggle_autowrap_mode()<CR>
It's very simple.
As people have said set is for options and works better because of the limitation. Also set is the historical command that all versions of vi use to set their options. Most (all?) other versions of vi don't have let.
But possibly most important is that set works on all versions of vim, the let command can be omitted when you compile vim. The standard tiny and small builds do this.
If it's missing let gives you the error:
E319: Sorry, the command is not available in this version
Note: if and endif are not implemented either in vim.tiny but in this case the commands do not give an error, instead everything between the two commands is skipped INCLUDING else.

How to use variable when setting makeprg in vim?

I am creating a method called SetLaunchingComponent which is used to set the makeprg with the variable passed in.This is how the script look like now.
function! SetLaunchingComponent(path)
set makeprg=$path
endfunction
Obviously the function isn't working as i wished. As vim resolve the path environment as the system variable but not a:path. So what should i do?
To set a option you should use the following syntax:
let &makeprg=a:path
command! -n=1 SL call SetLanuchingComponent(<arg>)
it will make you easy to use the function.

Resources