tags:

views:

77

answers:

3

I'd like to write a function in vimscript that finds the last open parenthese or bracket in a line. This isn't necessarily an easy problem, because it needs to be able to handle all of the following:

function(abc
function(abc, [def
function(abc, [def], "string("
function(abc, [def], "string(", ghi(

As you can see, nested parenthesis, differing symbols, and string tokens all need to be handled intelligently. Is this even possible? Are there tools with vimscript regexes to do context-aware searches that know the difference between unclosed parentheses and parenthesis in strings?

Given that you can syntax highlight unbalanced brackets, it should be possible to find the last unclosed parenthese/bracket on a line. How can this be done?

+1  A: 

I don't have any direct answer for you, but you may want to check out the code in the matchparen.vim plugin, which is a standard plugin included in Vim installs (in the plugin directory). That plugin is the one used for highlighting of matching parens, if you have that function enabled. The code is more general than what you need, since it matches across lines, but you may be able to work with it and test whether it finds a match on same line, or at least get some ideas from its code.

Herbert Sitz
+1  A: 

Use [( and ]):

[(          go to [count] previous unmatched '('.
])          go to [count] next unmatched ')'.

For curly braces: [{ and [}.

Jeet
Interesting. How is this implemented? Is there any equivalent for finding unmatched square brackets? Is there any easy way I can use this in a vimscript function without actually moving the cursor?
Nate
Look up `searchpair()` in the help/documentation.
Jeet
+2  A: 

So, basicly, you have to find the last parenthese which is not in comment and not in string.

I am not sure what this syntax is so I placed those lines in a buffer and did

:set ft=javascript

to get strings highlighting

function(abc
function(abc, [def
function(abc, [def], "string("
function(abc, [def], "string(", ghi(

Now put your cursor to the 3rd line open parenthese and issue the following command:

:echo synIDattr(synID(line('.'), col('.'), 0), 'name') =~? '\(Comment\|String\)'

It'll echo you '1' and it means that character under the cursor is in comment or in a string.

If you place the cursor to the last col of the last line and do the same command you'll get '0'.

Now you can iterate backwards over parenthesis and test them against 'comment' and 'string' and get the last open parenthese.

You can check http://habamax.ru/blog/2009/02/lisp-balance-unmatched-parenthesis-in-vim/ to see how to close unmatched parenthesis using vimscript.

Maxim Kim
Thanks! It's still a bit more complex than that (consider a line ending in "function( abc, def(), ghi", the last parenthese is not the last unmatched parenthese), but synIDattr is exactly what I needed to be able to do the rest of the work.
Nate