vis: improve `:<` command implementation
[vis.git] / vis-text-objects.c
blob446ac6dc7c7cd7f82717c6c145a8fa96bb540780
1 #include "vis-core.h"
2 #include "text-objects.h"
3 #include "util.h"
5 int vis_textobject_register(Vis *vis, int type, void *data, VisTextObjectFunction *textobject) {
7 TextObject *obj = calloc(1, sizeof *obj);
8 if (!obj)
9 return -1;
11 obj->user = textobject;
12 obj->type = type;
13 obj->data = data;
15 if (array_add_ptr(&vis->textobjects, obj))
16 return LENGTH(vis_textobjects) + array_length(&vis->textobjects) - 1;
17 free(obj);
18 return -1;
21 bool vis_textobject(Vis *vis, enum VisTextObject id) {
22 if (id < LENGTH(vis_textobjects))
23 vis->action.textobj = &vis_textobjects[id];
24 else
25 vis->action.textobj = array_get_ptr(&vis->textobjects, id - LENGTH(vis_textobjects));
26 if (!vis->action.textobj)
27 return false;
28 vis_do(vis);
29 return true;
32 static Filerange search_forward(Vis *vis, Text *txt, size_t pos) {
33 Filerange range = text_range_empty();
34 Regex *regex = vis_regex(vis, NULL);
35 if (regex)
36 range = text_object_search_forward(txt, pos, regex);
37 text_regex_free(regex);
38 return range;
41 static Filerange search_backward(Vis *vis, Text *txt, size_t pos) {
42 Filerange range = text_range_empty();
43 Regex *regex = vis_regex(vis, NULL);
44 if (regex)
45 range = text_object_search_backward(txt, pos, regex);
46 text_regex_free(regex);
47 return range;
50 static Filerange object_unpaired(Text *txt, size_t pos, char obj) {
51 char c;
52 bool before = false;
53 Iterator it = text_iterator_get(txt, pos), rit = it;
55 while (text_iterator_byte_get(&rit, &c) && c != '\n') {
56 if (c == obj) {
57 before = true;
58 break;
60 text_iterator_byte_prev(&rit, NULL);
63 /* if there is no previous occurrence on the same line, advance starting position */
64 if (!before) {
65 while (text_iterator_byte_get(&it, &c) && c != '\n') {
66 if (c == obj) {
67 pos = it.pos;
68 break;
70 text_iterator_byte_next(&it, NULL);
74 switch (obj) {
75 case '"':
76 return text_object_quote(txt, pos);
77 case '\'':
78 return text_object_single_quote(txt, pos);
79 case '`':
80 return text_object_backtick(txt, pos);
81 default:
82 return text_range_empty();
86 static Filerange object_quote(Text *txt, size_t pos) {
87 return object_unpaired(txt, pos, '"');
90 static Filerange object_single_quote(Text *txt, size_t pos) {
91 return object_unpaired(txt, pos, '\'');
94 static Filerange object_backtick(Text *txt, size_t pos) {
95 return object_unpaired(txt, pos, '`');
98 const TextObject vis_textobjects[] = {
99 [VIS_TEXTOBJECT_INNER_WORD] = {
100 .txt = text_object_word,
102 [VIS_TEXTOBJECT_OUTER_WORD] = {
103 .txt = text_object_word_outer,
105 [VIS_TEXTOBJECT_INNER_LONGWORD] = {
106 .txt = text_object_longword,
108 [VIS_TEXTOBJECT_OUTER_LONGWORD] = {
109 .txt = text_object_longword_outer,
111 [VIS_TEXTOBJECT_SENTENCE] = {
112 .txt = text_object_sentence,
114 [VIS_TEXTOBJECT_PARAGRAPH] = {
115 .txt = text_object_paragraph,
117 [VIS_TEXTOBJECT_OUTER_SQUARE_BRACKET] = {
118 .txt = text_object_square_bracket,
119 .type = TEXTOBJECT_DELIMITED_OUTER,
121 [VIS_TEXTOBJECT_INNER_SQUARE_BRACKET] = {
122 .txt = text_object_square_bracket,
123 .type = TEXTOBJECT_DELIMITED_INNER,
125 [VIS_TEXTOBJECT_OUTER_CURLY_BRACKET] = {
126 .txt = text_object_curly_bracket,
127 .type = TEXTOBJECT_DELIMITED_OUTER,
129 [VIS_TEXTOBJECT_INNER_CURLY_BRACKET] = {
130 .txt = text_object_curly_bracket,
131 .type = TEXTOBJECT_DELIMITED_INNER,
133 [VIS_TEXTOBJECT_OUTER_ANGLE_BRACKET] = {
134 .txt = text_object_angle_bracket,
135 .type = TEXTOBJECT_DELIMITED_OUTER,
137 [VIS_TEXTOBJECT_INNER_ANGLE_BRACKET] = {
138 .txt = text_object_angle_bracket,
139 .type = TEXTOBJECT_DELIMITED_INNER,
141 [VIS_TEXTOBJECT_OUTER_PARANTHESE] = {
142 .txt = text_object_paranthese,
143 .type = TEXTOBJECT_DELIMITED_OUTER,
145 [VIS_TEXTOBJECT_INNER_PARANTHESE] = {
146 .txt = text_object_paranthese,
147 .type = TEXTOBJECT_DELIMITED_INNER,
149 [VIS_TEXTOBJECT_OUTER_QUOTE] = {
150 .txt = object_quote,
151 .type = TEXTOBJECT_DELIMITED_OUTER,
153 [VIS_TEXTOBJECT_INNER_QUOTE] = {
154 .txt = object_quote,
155 .type = TEXTOBJECT_DELIMITED_INNER,
157 [VIS_TEXTOBJECT_OUTER_SINGLE_QUOTE] = {
158 .txt = object_single_quote,
159 .type = TEXTOBJECT_DELIMITED_OUTER,
161 [VIS_TEXTOBJECT_INNER_SINGLE_QUOTE] = {
162 .txt = object_single_quote,
163 .type = TEXTOBJECT_DELIMITED_INNER,
165 [VIS_TEXTOBJECT_OUTER_BACKTICK] = {
166 .txt = object_backtick,
167 .type = TEXTOBJECT_DELIMITED_OUTER,
169 [VIS_TEXTOBJECT_INNER_BACKTICK] = {
170 .txt = object_backtick,
171 .type = TEXTOBJECT_DELIMITED_INNER,
173 [VIS_TEXTOBJECT_OUTER_ENTIRE] = {
174 .txt = text_object_entire,
176 [VIS_TEXTOBJECT_INNER_ENTIRE] = {
177 .txt = text_object_entire_inner,
179 [VIS_TEXTOBJECT_OUTER_LINE] = {
180 .txt = text_object_line,
182 [VIS_TEXTOBJECT_INNER_LINE] = {
183 .txt = text_object_line_inner,
185 [VIS_TEXTOBJECT_INDENTATION] = {
186 .txt = text_object_indentation,
188 [VIS_TEXTOBJECT_SEARCH_FORWARD] = {
189 .vis = search_forward,
190 .type = TEXTOBJECT_NON_CONTIGUOUS|TEXTOBJECT_EXTEND_FORWARD,
192 [VIS_TEXTOBJECT_SEARCH_BACKWARD] = {
193 .vis = search_backward,
194 .type = TEXTOBJECT_NON_CONTIGUOUS|TEXTOBJECT_EXTEND_BACKWARD,