Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass arguments from :command to function?

Tags:

vim

I want to write a command, this command would have this format:

[range]MyCMD[!] [count] [oneArg] [flags]

or

[range]MyCMD[!] [oneArg] [count] [flags]

similiar to

:[range]P[rint] [count] [flags]

or

:[range]d[elete] [x] {count}

The command MyCMD eventually will call a function to do some work. I wrote this line (won't work)

command! -nargs=+ -range -bang -count=0  MyCMD <line1>,<line2>call MyFUNC(<q-args>, "<bang>","<count>", .... ..)

Here the problem is, how to handle those arguments:

  • problem 1 I read about the help, -range and -count cannot not be used at same time, but I need them both. I also took a look some vim commands, like :delete, :print, when we use those commands, we could give both range and count. Also I found that vim doc has two entries of same command if a {count} or [count] is available. like:

    :[range]d[elete] [x]    
    :[range]d[elete] [x] {count}
    

    or

    :[range]p[rint] [flags]
    :[range]p[rint] {count} [flags]
    

    why is that? why not just with [count] ? (this would be another small question)

  • problem 2 from my design, all those arguments are optional, they have default values(see the table below). How can I pass those arguments to function (I checked <q-args> and <f-args>) and how can I distinguish which user-inputs are for which argument? for example user gives

    :MyCMD 5 g

    • 5 is count? or arg?
    • g is arg or flag?
    • or '5 g' is arg?  

    here is the default values for args:

    argName | Default value | description
    -------------------------------------
    range   | current line  | this could be get by function xxx ( ) range
    count   | 0             | this could be get by <count>
    bang    | ""            | this is easy too, with <bang>
    arg     | " "           | this argument could have space
    flags   | ""            | no space allowed for flags
    -------------------------------------
    

thanks.

like image 855
Kent Avatar asked Apr 05 '13 22:04

Kent


2 Answers

For your complex custom command, you cannot rely solely on Vim's limited parsing options; you can have it handle the range with -range, but have to parse your combination of arguments yourself.

:command! -nargs=* -range -bang MyCMD <line1>,<line2>call MyFUNC(<bang>0, <q-args>)

Inside MyFUNC (which should probably be defined with :function MyFUNC( ... ) range to be invoked only once), split() the arguments on whitespace. Alternatively, you could define the function to use a variable number of arguments and use <f-args>, but note that the number of function arguments is limited (to 20 IIRC).

The <bang>0 is a nice trick to transform the bang into a boolean, which is usually what you need.

like image 28
Ingo Karkat Avatar answered Oct 03 '22 08:10

Ingo Karkat


Have to ask tough questions. I don't really have any solutions but here are my findings.

:command! -range -bang -nargs=* MY echo [<bang>0, <line1>, <line2>, <count>, <q-args>]

After running the following scenarios:

:MY
[0, 3, 3, -1, '']
:MY!
[1, 3, 3, -1, '']
:%MY
[0, 1, 10, 10, '']
:%MY 4
[0, 1, 10, 10, '4']
:MY 4
[0, 3, 3, -1, '4']
:%MY flag
[0, 1, 10, 10, 'flag']
:MY flag
[0, 3, 3, -1, 'flag']
:%MY 4 flag
[0, 1, 10, 10, '4 flag']

Now with -count instead of -range

:command! -count -bang -nargs=* MY echo [<bang>0, <line1>, <line2>, <count>, <q-args>]

Results:

:MY
[0, 3, 1, 0, '']
:MY!
[1, 3, 1, 0, '']
:%MY
[0, 1, 10, 10, '']
:%MY 4
[0, 1, 4, 4, '']
:MY 4
[0, 3, 4, 4, '']
:%MY flag
[0, 1, 10, 10, 'flag']
:MY flag
[0, 3, 1, 0, 'flag']
:%MY 4 flag
[0, 1, 4, 4, 'flag']

As you can see it doesn't easy. My suggestion would be to use -range with your command. And then parse the <q-args> looking for a number via \d\+.

like image 165
Peter Rincker Avatar answered Oct 03 '22 07:10

Peter Rincker