0

I have a function that builds my status line by appending values with statusline+= depending on the context. Everything works, except that if I try to call a function in the following form:

setlocal statusline=%{MyFunction(a:my_parameter)}

It fails with

E121: Undefined variable a:my_parameter

E116: Invalid arguments for function MyFunction

E15: Invalid expression: MyFunction(a:my_parameter)

Of course I checked that a:my_parameter is in scope and I can echo its value just before the function call. What is more, if I use a local variable instead (i.e. l:my_parameter) it fails in the same way, but I can pass hardcoded values without problem. I think it may be a limitation of %{}, but I cannot find anything in the documentation.

So, is it possible to pass variables to functions inside %{} somehow?

1

it is possible, at least I do pass variables:

    set statusline=%{misc#unicode_number(winnr())}

I am not sure what is set local statusline though. Did you mean setlocal?

Btw, a: variables implies you set statusline from the function? Bear in mind that statusline is evaluated quite often and it calls functions being bound to it without knowing local scoped parameters (no closures I guess?). So it literally calls MyFunction(a:my_parameter) in a context where a:my_parameter is unknown.

Not 100% sure but you can try to pass your parameter as real evaluated value:

exe 'set statusline=%{MyFunction("' . a:parameter . '")}'

PS, indeed this doesn't work. I believe (?) in statusline context there is just no way to access local variables and functions. You can pass parameter to a function used in statusline if that parameter is global/autoloaded function call or a buffer/global variable. Take this info with a grain of salt, I don't know for sure :)

This stupid exmaple works

func! MyFunc(value) abort
    return a:value * 3
endfunc
func! MyOtherFunc(value) abort
    return a:value . " WORLD!!!"
endfunc

set statusline=%{MyFunc(123)}
set statusline+=%{MyOtherFunc('hello')}
set statusline+=%{MyFunc(10)}

And this also works:

func! Test(parameter)
    return "hello world " . a:parameter
endfunc
func! MyStatus(value) abort
    let &statusline="%{Test('". a:value ."')}"
endfunc
call MyStatus("value for my status")

| improve this answer | |
  • Yeah, setlocal, damn autocorrector. execute also fails :( With the double quotes around the variable it raises E119: Not enough arguments for function, and without them it raises E540: Unclosed expression sequence. At least now I understand what is happening, thanks! – Tae Apr 10 at 9:04
  • 2
    I think intended way is to either use global functions or "persistent" variables as parameters (b:var, g:var or MyFunc()). Anything else is just not available for the function being called from within statusline. – Maxim Kim Apr 10 at 10:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.