[bim] Paren matching

This commit is contained in:
K. Lange 2018-08-28 16:36:35 +09:00
parent 48e43d5c95
commit f95f495b54

View File

@ -3483,6 +3483,82 @@ void search_next(void) {
draw_search_match(line, env->search, 0);
}
/**
* Find the matching paren for this one.
*
* This approach skips having to do its own syntax parsing
* to deal with, eg., erroneous parens in comments. It does
* this by finding the matching paren with the same flag
* value, thus parens in strings will match, parens outside
* of strings will match, but parens in strings won't
* match parens outside of strings and so on.
*/
void find_matching_paren(void) {
if (env->col_no > env->lines[env->line_no-1]->actual) {
return; /* Invalid cursor position */
}
/* TODO: vim can find the nearest paren to start searching from, we need to be on one right now */
int paren_match = 0;
int direction = 0;
int start = env->lines[env->line_no-1]->text[env->col_no-1].codepoint;
int flags = env->lines[env->line_no-1]->text[env->col_no-1].flags;
int count = 0;
/* TODO what about unicode parens? */
char * p = "()[]{}<>";
for (int i = 0; p[i]; ++i) {
if (start == p[i]) {
direction = (i % 2 == 0) ? 1 : -1;
paren_match = p[(i % 2 == 0) ? (i+1) : (i-1)];
break;
}
}
if (!paren_match) return;
/* Scan for match */
int line = env->line_no;
int col = env->col_no;
do {
while (col > 0 && col < env->lines[line-1]->actual + 1) {
/* Only match on same syntax */
if (env->lines[line-1]->text[col-1].flags == flags) {
/* Count up on same direction */
if (env->lines[line-1]->text[col-1].codepoint == start) count++;
/* Count down on opposite direction */
if (env->lines[line-1]->text[col-1].codepoint == paren_match) {
count--;
/* When count == 0 we have a match */
if (count == 0) goto _match_found;
}
}
col += direction;
}
line += direction;
/* Reached first/last line with no match */
if (line == 0 || line == env->line_count + 1) {
return;
}
/* Reset column to start/end of line, depending on direction */
if (direction > 0) {
col = 1;
} else {
col = env->lines[line-1]->actual;
}
} while (1);
_match_found:
env->line_no = line;
env->col_no = col;
place_cursor_actual();
}
/**
* Handle mouse event
*/
@ -4372,6 +4448,9 @@ int main(int argc, char * argv[]) {
redraw_all();
}
break;
case '%':
find_matching_paren();
break;
case '$':
env->col_no = env->lines[env->line_no-1]->actual+1;
break;