vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit 73176e416238c284511d01a93fd83cff8ef86c5e
parent 36003332259c710670c0c04cd2c2128e858db4c7
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Sat, 20 Aug 2016 15:42:58 +0200

vis: improve unpaired text objects

For unpaired text objects delimited by ", ' or ` if there is no preceding
symbol on the same line, advance starting position to first occurence on
the same line.

As a result ci" can be used to change the inner quotes on the same line
even if the cursor is currently to the left of the opening quote.

If the line contains no such symbol at all then the text objects will
will continue to match across line boundaries. This behavior is different
in vim where for example a ci" command on a line without any quotes has
no effect.

Close #358

Diffstat:
Mvis-text-objects.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 54 insertions(+), 6 deletions(-)

diff --git a/vis-text-objects.c b/vis-text-objects.c @@ -48,6 +48,54 @@ static Filerange search_backward(Vis *vis, Text *txt, size_t pos) { return range; } +static Filerange object_unpaired(Text *txt, size_t pos, char obj) { + char c; + bool before = false; + Iterator it = text_iterator_get(txt, pos), rit = it; + + while (text_iterator_byte_get(&rit, &c) && c != '\n') { + if (c == obj) { + before = true; + break; + } + text_iterator_byte_prev(&rit, NULL); + } + + /* if there is no previous occurence on the same line, advance starting position */ + if (!before) { + while (text_iterator_byte_get(&it, &c) && c != '\n') { + if (c == obj) { + pos = it.pos; + break; + } + text_iterator_byte_next(&it, NULL); + } + } + + switch (obj) { + case '"': + return text_object_quote(txt, pos); + case '\'': + return text_object_single_quote(txt, pos); + case '`': + return text_object_backtick(txt, pos); + default: + return text_range_empty(); + } +} + +static Filerange object_quote(Text *txt, size_t pos) { + return object_unpaired(txt, pos, '"'); +} + +static Filerange object_single_quote(Text *txt, size_t pos) { + return object_unpaired(txt, pos, '\''); +} + +static Filerange object_backtick(Text *txt, size_t pos) { + return object_unpaired(txt, pos, '`'); +} + const TextObject vis_textobjects[] = { [VIS_TEXTOBJECT_INNER_WORD] = { .txt = text_object_word }, [VIS_TEXTOBJECT_OUTER_WORD] = { .txt = text_object_word_outer }, @@ -63,12 +111,12 @@ const TextObject vis_textobjects[] = { [VIS_TEXTOBJECT_INNER_ANGLE_BRACKET] = { .txt = text_object_angle_bracket, .type = INNER }, [VIS_TEXTOBJECT_OUTER_PARANTHESE] = { .txt = text_object_paranthese, .type = OUTER }, [VIS_TEXTOBJECT_INNER_PARANTHESE] = { .txt = text_object_paranthese, .type = INNER }, - [VIS_TEXTOBJECT_OUTER_QUOTE] = { .txt = text_object_quote, .type = OUTER }, - [VIS_TEXTOBJECT_INNER_QUOTE] = { .txt = text_object_quote, .type = INNER }, - [VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE] = { .txt = text_object_single_quote, .type = OUTER }, - [VIS_TEXTOBJECT_INNER_SINGLE_QUOTE] = { .txt = text_object_single_quote, .type = INNER }, - [VIS_TEXTOBJECT_OUTER_BACKTICK] = { .txt = text_object_backtick, .type = OUTER }, - [VIS_TEXTOBJECT_INNER_BACKTICK] = { .txt = text_object_backtick, .type = INNER }, + [VIS_TEXTOBJECT_OUTER_QUOTE] = { .txt = object_quote, .type = OUTER }, + [VIS_TEXTOBJECT_INNER_QUOTE] = { .txt = object_quote, .type = INNER }, + [VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE] = { .txt = object_single_quote, .type = OUTER }, + [VIS_TEXTOBJECT_INNER_SINGLE_QUOTE] = { .txt = object_single_quote, .type = INNER }, + [VIS_TEXTOBJECT_OUTER_BACKTICK] = { .txt = object_backtick, .type = OUTER }, + [VIS_TEXTOBJECT_INNER_BACKTICK] = { .txt = object_backtick, .type = INNER }, [VIS_TEXTOBJECT_OUTER_ENTIRE] = { .txt = text_object_entire, }, [VIS_TEXTOBJECT_INNER_ENTIRE] = { .txt = text_object_entire_inner, }, [VIS_TEXTOBJECT_OUTER_FUNCTION] = { .txt = text_object_function, },