0

I often need to delineate "sections" of source code files using a comment character to create horizontal lines. For example if I wanted to draw such a line in a python file I could do

:Hline # 79

where the first argument is the character and the second character is the number of times it is to be repeated to create a line. The thing I could come up with is this:

command! -nargs=1 Hline let b:horiz_line = repeat('<args>', 79) <bar>
    \ exe "norm i" . b:horiz_line

Which allows me to say :Hline #.

  1. I can't thing of a way to specify both the arguments
  2. Would it be possible to specify default values ? Like for example, the first argument could be set to the commentstring and the second argument could be set to the textwidth? Or if not set defaults to - and 79 characters.
First User
  • 391
  • 1
  • 8
  • 1
    Gonna be a lot easier with a function (called by your command). That okay? – B Layer Jul 20 '21 at 13:46
  • yes of course. I would still like to call it using an easy command name. I just cant figure out to handle multiple values with defaults. – First User Jul 20 '21 at 13:48
  • Yeah, can keep the same command syntax...but handling optional arguments will be a whole lot easier if it's backed by a function. – B Layer Jul 20 '21 at 13:49

1 Answers1

3

Here's the general idea...

func! MakeHLine(...) abort
    " Default delim char and width
    let l:ch = '#'
    let l:tw = 78
&quot; Override defaults per given parameters
if a:0
    let l:ch = a:1
    if a:0 == 2
        let l:tw = a:2
    endif
endif

&quot; Do the actual work
eval repeat(l:ch, l:tw)-&gt;append(line(&quot;.&quot;))

endfunc

" -nargs=* means as many args as you want. I'm not checking " for invalid numbers of params. A good thing for you to add " to the function. command! -nargs=* Hline call MakeHLine(<f-args>)

I'm simply adding the text on a line following the line the cursor is on.

One issue, though, is that due to the way optional arguments work you can't specify only the width. You can do no args or just the character or both character and width (or that can be flipped if you want to be able to specify just the width).

Certainly, it's possible to do but it'll require code that does a deeper parse of the parameter list.

Bonus

Here's one way you could allow full flexibility with the parameters, i.e. if you pass a single param it can either be a number/width or a non-number/delimiter-char. Also, with two params the position doesn't matter. Put width before char or vice-versa.

func! MakeHLine(...) range
    let l:ch = '#'
    let l:tw = 28
if a:0
    &quot; Use regexes to determine what's in each param
    for l:arg in a:000
        if l:arg =~ '^\d\+$'
            let l:tw = l:arg + 0
        elseif l:arg =~ '^[^0-9]\+$'
            let l:ch = l:arg
        else
            throw &quot;Invalid parameter &quot; . l:arg
        endif
    endfor
endif

eval repeat(l:ch, l:tw)-&gt;append(line(&quot;.&quot;))

endfunc

command! -nargs=* Hline call MakeHLine(<f-args>)

B Layer
  • 19,834
  • 2
  • 30
  • 57