2

I am working on a VIM plugin that will require a certain level of complexity for handling arguments passed to a command.

:MyCommand -item=banana -command=ls\-ltra -pattern=./*

However, I am not sure how to handle this situation. I am aware of how arguments work in vimL, with the a:0 and a:000 and the <f-args> bits. But not sure how to do the splitting and filtering of the strings etc.

Ideally, I will be constructing a dictionary out of my arguments:

{
    'item':'banana',
    'command':'ls -ltra',
    'pattern':'./*',
}

Of course, there are other plugins out there that I can peak into and see how they have solved this issue to certain extend, yet still, any suggestions would be at a great help.

--- EDIT(1) ---

Here is a prototype:

function! MyCommand(...) abort
    " Total argument count.
    echo 'a:0 -> ' . a:0

    " Iterative lookup.
    " echo 'a:1   -> ' . a:1
    " echo 'a:2   -> ' . a:2
    " ... etc.
    let l:limit = a:0
    let l:counter = 1
    while l:limit >= l:counter
        exec 'echo ' . '"a:' . l:counter . '"' . '"->"' . 'a:' . l:counter
        let l:counter += 1
    endwhile

    " All arguments as a list.
    echo 'a:000:' 
    echo a:000
endfunction

And this when run as:

:MyCommand -stage=build -task=do -command=ls\-ltr -pattern=./* -working-directory=/path/to/my/project

Produces the following output:

a:0 -> 5
a:1 -> -stage=build
a:2 -> -task=do
a:3 -> -command=ls\-ltr
a:4 -> -pattern=./*
a:5 -> -working-directory=/path/to/my/project
a:000:
['-stage=build', '-task=do', '-command=ls\-ltr', '-pattern=./*', 'working-directory=/path/to/my/project']

So, I guess, the rest would be regex based checks and string processing to extract the right bits of information. Anything more efficient that should be done on the function and arguments handling side?

4

You should be able to do this simply by splitting the arg on an = and going through a for loop. Something like the following should work.

command! -nargs=+ MyCommand :call MyFunction(<f-args>)
let s:dictionary = {}

function! MyFunction(...)
   for arg in a:000
      let myList = split(arg, '=')
      let s:dictionary[myList[0]] = myList[1]
   endfor
endfunction
  • -nargs=+: Function must have at least one argument
  • <f-args>: Will pass white-space split arguments to MyFunction().
  • split(arg, '='): Splits each argument up on an = sign.

You also have some interesting substitution going on but I'll leave that as an exercise to the reader as I'm not sure exactly how you want it done. Suffice it to say you should be able to do these with the substitute() function.

See :help :command-nargs, :help <f-args>, :help split(), and :help substitute() for more info.

  • Yes. Thanks. So anything else such as checking if the arguments are constructed correctly, should be done with a series of regex/substitution style testing, right? For example, if the argument is constructed as -item=component and NOT as --item="component". – mbilyanov Apr 18 '17 at 15:55
  • I'm not the definitive resource on this, but that would be approach I would take. Some =~ test to make sure the inputs are correct as defined by you. – Tumbler41 Apr 18 '17 at 16:04
  • The constructed dictionary should not be a script variable unless necessary. In this case, it seems more appropriate to use a local variable. IMHO, of course. – Karl Yngve Lervåg Apr 19 '17 at 6:30
1

Merging back parameters like --foo="foo bar" requires manual work. Vim doesn't provide us anything to solve this issue.

I remember having started an experiment on the subject. Unfortunately, this is nothing more than that: an incomplete experiment: lh#command#Fargs2String()

  • 1
    Luc, this library of yours, it looks amazing! I did not have a chance to peak into it in great detail, but I can see so much work has been done around it. Thanks for sharing this. – mbilyanov Apr 19 '17 at 9:16

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.