vimvim-registers

how to query the highest digit in a search?


Searching for the pattern /{{c\d, I'd like to get the highest digit found and use it in a macro.

For context, I'm using Anki (flashcard tool) and its cloze card type, and recently started creating my cards within vim.

Example card:

## Front
reading: 
{{c1::A::reading A}}
B
{{c2::C::reading C}}
{{c1::D::reading D}}
E


## Back
...

In that example, given I'm positioned above E, I'd like to execute a macro that'll figure out that the highest cloze digit is 2 (in {{c2::C::reading C}}) and create a new cloze with highest digit incremented by one as {{c3::E::reading E}}

My macro currently looks like this:

:registers
"c   ysiw}wysiw}wyiwic3::^OP::reading

Solution

  • You can use a :%s command with the [/n] flag, which doesn't execute the substitution but only counts the matches.

    Use that together with a \= expression on the replacement side, just for the side effects of the expression.

    You can use that to append the cloze numbers to a list and then find the maximum after you've collected them all.

    function! NextCloze()
        let nums = [0]
        let view = winsaveview()
        silent %s/\m{{c\zs\d\+\ze::/\=add(nums, submatch(0))/egn
        call winrestview(view)
        return 1 + max(nums)
    endfunction
    

    The function is also saving and restoring the view around the %s operation, since that operation will move the cursor and we want to keep it in place.

    To insert it in the middle of a mapping you can use something like:

    i{{c<C-R>=NextCloze()<CR>::
    

    Though there are probably other ways you can put that result in your buffer. For instance, if you'd like a mapping that takes the current word under the cursor and replaces it with the {{cN::...::reading ...}} block, consider these:

    nnoremap <Leader>c ciW{{c<C-R>=NextCloze()<CR>::<C-R>"::reading <C-R>"}}<Esc>
    xnoremap <Leader>c c{{c<C-R>=NextCloze()<CR>::<C-R>"::reading <C-R>"}}<Esc>
    

    In Normal mode, it will act on the Word (sequence of non-white space symbols) under the cursor. In Visual mode, it will act on the visual selection. These are closer to your original @c macro.