Petr Skocik
Petr Skocik

Reputation: 60107

Triple (n-state) variable toggle in vim

What's the best way to do triple state toggling in vim? Can I do something like? (C):

void toggle(void)
{
    static int var = 3-1;
    var=(var+1)%3;
    printf("%d\n", var);
}
int main()
{
    toggle(); //0
    toggle(); //1
    toggle(); //2
    toggle(); //0
    toggle(); //1
    toggle(); //2

}

I tried

fun! Toggle()
    let l:var=0
    let l:var+=1
    echom l:var
endfun

But this always prints 1.

Upvotes: 1

Views: 59

Answers (2)

Luc Hermitte
Luc Hermitte

Reputation: 32966

The closest equivalent to C static variables are the script local s:variables. As the name suggests, they are not local to functions but to scripts.

On a side note, I provide a function for this purpose in my library plugin: lh#menu#def_toggle_item().

My associated unit tests are over there.

What it does:

  • It permits to cycle through a series of possible values thanks to :Toggle MenuSubmenuVariable [value] -- completion is supported
  • works with text and numeric value
  • hook/action can be associated when changing state, or when going into a new state
  • a menu is also produced to change the state of the variable
  • it will update a variable that can be manipulated by the end user

For instance, this is a complex example which triggers events:

let Data4 = {
      \ "variable": "yesno",
      \ "values": [ 1, 2, 3 ],
      \ "text": [ "No", "Yes", "Perhaps" ],
      \ "actions": [ function("s:No"), function("s:Yes"), function('s:Perhaps') ],
      \ "menu": { "priority": '42.50.20', "name": '&LH-Tests.&TogMenu.&yesno'}
      \}
call lh#menu#def_toggle_item(Data4)

which permits to toggle/cycle with:

:Toggle LHTestsTogMenuyesno    " to go to the next state
:Toggle LHTestsTogMenuyesno no " to force a value
:echo g:yesno                  " -> 1 (associated to "no")

Upvotes: 0

James Lawson
James Lawson

Reputation: 8618

Your variable is local (hence the l in l:var) and so every time you call Toggle() it "resets itself" to zero. You can use a global variable by using the prefix g.

let g:var=0
fun! Toggle()
    let g:var = (g:var + 1) % 3
    echom g:var
endfun

And then inside vim:

:call Toggle()
0
:call Toggle()
1
:call Toggle()
2
:call Toggle()
0

I'd recommend prefixing your global variable with some identifier (e.g. let g:pskocik_toggle_count) to prevent collisions with plugins and other scripts.

Upvotes: 2

Related Questions