I'm trying to implement a custom regexp string to be used by matchit.vim for identifying matching keywords that can be jumped between with %.

I found a utility from FileExchange (in the ftplugin folder when downloaded and unzipped), but it is not perfect in that

  1. It detects for, if, etc. in comment lines (the % character in Matlab)

  2. It incorrectly tries to match end with something for certain formats of array indexing (e.g. MyArray(1,end,2) uses end to return a scalar slice, but since it is separated by commas the original tried to match it with something)

  3. It only matches starting/ending pairs (e.g. no elseif or else)

I've tried making a modified version that fixes these, but I'm getting errors. One is E51: Too many \(, which means too many groups or something, right? Not sure how that's possible. Also when I include an escaped comma \, in the \(\)\@! and \(\)\@<! blocks the error changes which suggests to me the string is not getting parsed properly between un-escaped commas (disparate keyword groups) and colons (keywords in each keyword group). But really not sure.

Anyway, was hoping for some ideas on what could be wrong here. The original and modified regexps are below. Thanks!

Edit: Here is the matchit documentation.

It appears that comma separation works (e.g. a simple if:end,for:end) but when I try more than one line I get the errors:

E872: (NFA regexp) Too many '(' E51: Too many \(

This is in addition to the error when I include \, in the [].

Can either be circumvented somehow? It appears my problem has to do with limitations in terms of numbers of regular expressions, and also for some reason matchit tried to parse on the escaped comma.

Original b:match_words

let s:conditionalEnd = '\([-+{\*\:(\/]\s*\)\@<!\<end\>\(\s*[-+}\:\*\/)]\)\@!'
let b:match_words = '\<classdef\>\|\<methods\>\|\<events\>\|\<properties\>\|\<if\>\|\<while\>\|\<for\>\|\<switch\>\|\<try\>\|\<function\>:' . s:conditionalEnd

Modified b:match_words

let s:conditionalEnd = '\(%\+.*\|[\,-+{\*\:(\/]\s*\)'.'\@<!'.'\<end\>'.'\(\s*[\,-+}\:\*\/)]\)'.'\@!'
let s:noComment = '\(%\+.*\)\@<!'
let b:match_words = s:noComment.'\<if\>' .':'. s:noComment.'\<elseif\>' .':'. s:noComment.'\<else\>' .':'. s:conditionalEnd .','.
\ s:noComment.'\<switch\>' .':'. s:noComment.'\<case\>' .':'. s:noComment.'\<otherwise\>' .':'. s:conditionalEnd .','.
\ s:noComment.'\<classdef\>\|\<properties\>\|\<methods\>\|\<events\>\|\<enumeration\>' .':'. s:conditionalEnd .','.
\ s:noComment.'\<for\>\|\<parfor\>\|\<while\>' .':'. s:noComment.'\<continue\>' .':'. s:noComment.'\<break\>' .':'. s:conditionalEnd .','.
\ s:noComment.'\<function\>' .':'. s:noComment.'\<return\>' .':'. s:conditionalEnd
  • Simplify b:match_words first. Try it with if...endif first and get that right before worrying about everything else. You can also try making (:) or (:\%(else\|elseif\):) the first pair to make matchit prioritize that.
    – Tommy A
    Jul 12, 2016 at 15:54
  • Well I tried classdef and end just now (that's just a single pair), and it's the same deal. E51: Too many \( with the \, in the [] group, and E16: Invalid range without. Turning off comment detection doesn't do anything either.
    – Luke Davis
    Jul 12, 2016 at 16:07


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.