Search code examples
vimkeywordkeyword-argumentvim-macros

Macro to map keyword arguments to google doc strings


I am trying to write my first vim macro. The goal is to map a line containing a keyword to google doc string format.

So the input is:

'keyword' : value,

and desired output would be:

keyword (value) :

So I assume the easiest way would be to define a macro. In console mode I used wdwwD from the beginning of the line to successfully delete everything around my keyword. But binding it to a macro (with additionally adding j0 to get a new line) yields the following output : keyword' : value

I've also tried f'r f'Dj0 but it resulted in the same output. So it seems like I am doing something wrong but repeating the sequence yields my desired output, but not binding it to a macro even though thats what it supposed to do, right?

My example is

Battery_config = {
        'charging_efficiency' : 0.8, 
        'discharging_efficiency' : 0.99,
        'hourly_self_discharge': 0.005
}

Solution

  • So I assume the easiest way would be to define a macro

    You mean normal mode sequence. But there's a problem: your line may or may not end with "comma". So at first it's tempting to do something like this:

    nnoremap <Leader>d ^"ayi'$"byBS<C-R>a<Space>(<C-R>b)<Space>:<Esc>
    

    Explanation:

    1. ^ --- go to the first non-blank char
    2. "ayi' --- yank keyword into reg 'a' (yank inside quotes)
    3. $ --- go to the end of line
    4. "byB --- yank value into reg 'b' (yank WORD backward)
    5. S --- clear line and switch into insert mode (also needs set autoindent to preserve line indent)
    6. <C-R>a (<C-R>b) : --- finally type keyword (value) :
    7. <Esc> --- get back to normal mode

    However, it fails on 'hourly_self_discharge': 0.005 and it's not so easy to fix it (well, of course, you can do ^"ayi'$"byiW:let @b=trim(@b,',')<CR>S<C-R>a<Space>(<C-R>b)<Space>:<Esc>, but it's even uglier than before).

    Another point is that we'd like to be able to work over an arbitrary visual selection without corrupting other data. So it seems much more profitable to go with regexps in Ex mode:

    noremap <Leader>d :s/\v'(\w+)'\s*:\s*([0-9.-]+),?/\1 (\2) :/<CR>
    

    Explanation:

    1. noremap ... --- now it should work both in normal and visual mode without any effort!
    2. :s/\v.../.../<CR> --- substitute using 'very magic' mode
    3. '(\w+)' --- capture the keyword into the 1st submatch
    4. \s*:\s* --- match colon with optional space around
    5. ([0-9.-]+) --- (hopefully) capture the value into the 2nd submatch
    6. ,? --- optional comma
    7. \1 (\2) : --- compose output string from submatches

    Now try ggVG<Leader>d to process the whole file at once.