1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 | int
count_unescaped_chars(Application_Links *app, int pos, int until, char find, char forward, char uninterrupted)
{
View_Summary view = app->get_active_view(app);
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id);
Stream_Chunk chunk;
char chunk_size[(1 << 10)];
if (!init_stream_chunk(&chunk, app, &buffer, pos, chunk_size, sizeof(chunk_size)))
{
return 0;
}
int i = pos;
int count = 0;
char at_cursor = 0;
char before_cursor = 0;
for (;;)
{
// Check streams etc at the start of the loop if we are searching backwards
// This ensures that the character at the cursor is not included in the search
if (!forward)
{
if (--i == chunk.start && !backward_stream_chunk(&chunk)) break;
if (i <= chunk.start) break;
if (until >= 0 && i <= until) break;
}
at_cursor = chunk.data[i];
before_cursor = i > chunk.start ? chunk.data[i - 1] : 0;
if (uninterrupted && count && at_cursor != find) return count;
if (at_cursor == find && before_cursor != '\\') ++count;
// Check streams etc at the end of the loop if we are searching forwards
// This ensures that the character at the cursor is included in the search
if (forward)
{
if (++i == chunk.end && !forward_stream_chunk(&chunk)) break;
if (i >= chunk.end) break;
if (until >= 0 && i >= until) break;
}
}
return count;
}
int
seek_char(Application_Links *app, int pos, char find, char forward)
{
View_Summary view = app->get_active_view(app);
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id);
Stream_Chunk chunk;
char chunk_size[(1 << 10)];
if (!init_stream_chunk(&chunk, app, &buffer, pos, chunk_size, sizeof(chunk_size)))
{
return 0;
}
int i = pos;
for (;;)
{
// Check streams etc at the start of the loop if we are searching backwards
// This ensures that the character at the cursor is not included in the search
if (!forward)
{
if (--i == chunk.start && !backward_stream_chunk(&chunk)) break;
if (i <= chunk.start) break;
}
if (chunk.data[i] == find) return i;
// Check streams etc at the end of the loop if we are searching forwards
// This ensures that the character at the cursor is included in the search
if (forward)
{
if (++i == chunk.end && !forward_stream_chunk(&chunk)) break;
if (i >= chunk.end) break;
}
}
return 0;
}
int
seek_matching_char_pos(Application_Links *app, int pos, char find, char opposite, char forward)
{
View_Summary view = app->get_active_view(app);
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id);
Stream_Chunk chunk;
char chunk_size[(1 << 10)];
if (!init_stream_chunk(&chunk, app, &buffer, pos, chunk_size, sizeof(chunk_size)))
{
return 0;
}
int i = pos;
int nest_count = 0;
int newline_left = 0;
int newline_right = 0;
int char_count_left = 0;
int char_count_right = 0;
int left_char_pos = 0;
int right_char_pos = 0;
int pos_found = 0;
char at_cursor = 0;
char before_cursor = 0;
char in_str_lit = 0;
char in_char_lit = 0;
char in_multi_comment = 0;
char in_single_comment = 0;
for (;;)
{
// Check streams etc at the start of the loop if we are searching backwards
// This ensures that the character at the cursor is not included in the search
if (!forward)
{
if (--i == chunk.start && !backward_stream_chunk(&chunk)) break;
if (i <= chunk.start) break;
}
at_cursor = chunk.data[i];
before_cursor = i > chunk.start ? chunk.data[i - 1] : 0;
if ((at_cursor == find || at_cursor == opposite) && before_cursor != '\\')
{
in_str_lit = 0;
in_char_lit = 0;
in_multi_comment = 0;
in_single_comment = 0;
newline_left = seek_char(app, i, '\n', 0);
newline_right = seek_char(app, i, '\n', 1);
if (!in_single_comment)
{
// Check for single line comment
char_count_left = count_unescaped_chars(app, i, newline_left, '/', 0, 1, &pos_found);
if (char_count_left >= 2)
{
// Check for string literal
char_count_left = count_unescaped_chars(app, pos_found, newline_left, '"', 0, 0);
char_count_right = count_unescaped_chars(app, pos_found, newline_right, '"', 1, 0);
char_count_left = char_count_left ? char_count_left % 2 : char_count_left;
char_count_right = char_count_right ? char_count_right % 2 : char_count_right;
in_str_lit = char_count_left % 2 && char_count_left % 2 ;
// Check for character literal
char_count_left = count_unescaped_chars(app, pos_found, newline_left, '\'', 0, 0);
char_count_right = count_unescaped_chars(app, pos_found, newline_right, '\'', 1, 0);
char_count_left = char_count_left ? char_count_left % 2 : char_count_left;
char_count_right = char_count_right ? char_count_right % 2 : char_count_right;
in_char_lit = char_count_left % 2 && char_count_left % 2 ;
if (!in_str_lit && !in_char_lit)
{
in_single_comment = 1;
}
in_char_lit = 0;
in_str_lit = 0;
}
}
if (!in_single_comment)
{
// Check for multi-line comment
left_char_pos = seek_char(app, i, '*', 0);
right_char_pos = seek_char(app, i, '*', 1);
in_multi_comment = 0;
if (left_char_pos < right_char_pos &&
seek_char(app, left_char_pos, '/', 0) == (left_char_pos - 1) &&
seek_char(app, right_char_pos, '/', 1) == (right_char_pos + 1))
{
in_multi_comment = 1;
}
}
if (!in_multi_comment)
{
// Check for string literal
char_count_left = count_unescaped_chars(app, i, newline_left, '"', 0, 0);
char_count_right = count_unescaped_chars(app, i, newline_right, '"', 1, 0);
char_count_left = char_count_left ? char_count_left % 2 : char_count_left;
char_count_right = char_count_right ? char_count_right % 2 : char_count_right;
in_str_lit = char_count_left % 2 && char_count_left % 2 ;
}
if (!in_str_lit)
{
// Check for character literal
char_count_left = count_unescaped_chars(app, i, newline_left, '\'', 0, 0);
char_count_right = count_unescaped_chars(app, i, newline_right, '\'', 1, 0);
char_count_left = char_count_left ? char_count_left % 2 : char_count_left;
char_count_right = char_count_right ? char_count_right % 2 : char_count_right;
in_char_lit = char_count_left % 2 && char_count_left % 2 ;
}
if (!in_str_lit && !in_char_lit && !in_single_comment && !in_multi_comment)
{
if (at_cursor == opposite) ++nest_count;
if (at_cursor == find && !nest_count) return i;
if (at_cursor == find) --nest_count;
}
}
// Check streams etc at the end of the loop if we are searching forwards
// This ensures that the character at the cursor is included in the search
if (forward)
{
if (++i == chunk.end && !forward_stream_chunk(&chunk)) break;
if (i >= chunk.end) break;
}
}
return 0;
}
CUSTOM_COMMAND_SIG(lucas_select_bracket_contents)
{
View_Summary view = app->get_active_view(app);
int curly = seek_matching_char_pos(app, view.cursor.pos, '{', '}', 0);
int round = seek_matching_char_pos(app, view.cursor.pos, '(', ')', 0);
int square = seek_matching_char_pos(app, view.cursor.pos, '[', ']', 0);
int matching = 0;
if (curly > round && curly > square)
{
matching = seek_matching_char_pos(app, view.cursor.pos, '}', '{', 1);
app->view_set_cursor(app, &view, seek_pos(curly + 1), 1);
app->view_set_mark(app, &view, seek_pos(matching));
}
else if (round > curly && round > square)
{
matching = seek_matching_char_pos(app, view.cursor.pos, ')', '(', 1);
app->view_set_cursor(app, &view, seek_pos(round + 1), 1);
app->view_set_mark(app, &view, seek_pos(matching));
}
else if (square > curly && square > round)
{
matching = seek_matching_char_pos(app, view.cursor.pos, ']', '[', 1);
app->view_set_cursor(app, &view, seek_pos(square + 1), 1);
app->view_set_mark(app, &view, seek_pos(matching));
}
}
bind(context, 'E', MDFR_CTRL, lucas_select_bracket_contents);
|