Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <stdlib.h> | ||
2 | #include <string.h> | ||
3 | #include <sys/stat.h> | ||
4 | #include "buffer.h" | ||
5 | #include "editor.h" | ||
6 | #include "encoding.h" | ||
7 | #include "file-option.h" | ||
8 | #include "filetype.h" | ||
9 | #include "syntax/state.h" | ||
10 | #include "util/intern.h" | ||
11 | #include "util/path.h" | ||
12 | #include "util/xmalloc.h" | ||
13 | #include "util/xstring.h" | ||
14 | |||
15 | 127 | void buffer_set_display_filename(Buffer *buffer, char *name) | |
16 | { | ||
17 | 127 | free(buffer->display_filename); | |
18 | 127 | buffer->display_filename = name; | |
19 | 127 | } | |
20 | |||
21 | /* | ||
22 | * Mark line range min...max (inclusive) "changed". These lines will be | ||
23 | * redrawn when screen is updated. This is called even when content has not | ||
24 | * been changed, but selection has or line has been deleted and all lines | ||
25 | * after the deleted line move up. | ||
26 | * | ||
27 | * Syntax highlighter has different logic. It cares about contents of the | ||
28 | * lines, not about selection or if the lines have been moved up or down. | ||
29 | */ | ||
30 | 476 | void buffer_mark_lines_changed(Buffer *buffer, long min, long max) | |
31 | { | ||
32 | 476 | buffer->changed_line_min = MIN3(min, max, buffer->changed_line_min); | |
33 | 476 | buffer->changed_line_max = MAX3(min, max, buffer->changed_line_max); | |
34 | 476 | } | |
35 | |||
36 | 4 | const char *buffer_filename(const Buffer *buffer) | |
37 | { | ||
38 | 4 | const char *name = buffer->display_filename; | |
39 |
2/2✓ Branch 0 (2→3) taken 3 times.
✓ Branch 1 (2→4) taken 1 times.
|
4 | return name ? name : "(No name)"; |
40 | } | ||
41 | |||
42 | 58 | void buffer_set_encoding(Buffer *buffer, const char *encoding, bool utf8_bom) | |
43 | { | ||
44 | 58 | if (DEBUG_ASSERTIONS_ENABLED) { | |
45 | 58 | const char *nenc = encoding_normalize(encoding); | |
46 | 58 | BUG_ON(encoding != nenc); | |
47 | } | ||
48 | |||
49 |
2/2✓ Branch 0 (5→6) taken 55 times.
✓ Branch 1 (5→10) taken 3 times.
|
58 | if (interned_strings_equal(buffer->encoding, encoding)) { |
50 | return; | ||
51 | } | ||
52 | |||
53 | 55 | EncodingType type = lookup_encoding(encoding); | |
54 |
1/2✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 55 times.
|
55 | buffer->bom = (type == UTF8) ? utf8_bom : encoding_type_has_bom(type); |
55 | 55 | buffer->encoding = encoding; | |
56 | } | ||
57 | |||
58 | 82 | Buffer *buffer_new(PointerArray *buffers, const GlobalOptions *gopts, const char *encoding) | |
59 | { | ||
60 | 82 | static unsigned long id; | |
61 | 82 | Buffer *buffer = xcalloc(1, sizeof(*buffer)); | |
62 | 82 | list_init(&buffer->blocks); | |
63 | 82 | buffer->cur_change = &buffer->change_head; | |
64 | 82 | buffer->saved_change = &buffer->change_head; | |
65 | 82 | buffer->id = ++id; | |
66 | 82 | buffer->crlf_newlines = gopts->crlf_newlines; | |
67 | |||
68 |
2/2✓ Branch 0 (4→5) taken 55 times.
✓ Branch 1 (4→6) taken 27 times.
|
82 | if (encoding) { |
69 | 55 | buffer_set_encoding(buffer, encoding, gopts->utf8_bom); | |
70 | } | ||
71 | |||
72 | // Note that using sizeof(CommonOptions) may cause this memcpy() to | ||
73 | // overwrite some LocalOptions-specific members with padding bytes. | ||
74 | // Thus, all LocalOptions members that are not also in CommonOptions | ||
75 | // *must* be explicitly initialized after this memcpy() and the fact | ||
76 | // they were originally zeroed by xcalloc() cannot be relied upon. | ||
77 | 82 | static_assert(sizeof(*gopts) >= sizeof(CommonOptions)); | |
78 | 82 | memcpy(&buffer->options, gopts, sizeof(CommonOptions)); | |
79 | 82 | buffer->options.brace_indent = 0; | |
80 | 82 | buffer->options.filetype = str_intern("none"); | |
81 | 82 | buffer->options.indent_regex = NULL; | |
82 | |||
83 | 82 | ptr_array_append(buffers, buffer); | |
84 | 82 | return buffer; | |
85 | } | ||
86 | |||
87 | 49 | Buffer *open_empty_buffer(PointerArray *buffers, const GlobalOptions *gopts) | |
88 | { | ||
89 | 49 | Buffer *buffer = buffer_new(buffers, gopts, encoding_from_type(UTF8)); | |
90 | |||
91 | // At least one block required | ||
92 | 49 | Block *blk = block_new(1); | |
93 | 49 | list_insert_before(&blk->node, &buffer->blocks); | |
94 | |||
95 | 49 | return buffer; | |
96 | } | ||
97 | |||
98 | 82 | void free_blocks(Buffer *buffer) | |
99 | { | ||
100 | 82 | ListHead *item = buffer->blocks.next; | |
101 |
2/2✓ Branch 0 (4→3) taken 112 times.
✓ Branch 1 (4→5) taken 82 times.
|
194 | while (item != &buffer->blocks) { |
102 | 112 | ListHead *next = item->next; | |
103 | 112 | Block *blk = BLOCK(item); | |
104 | 112 | free(blk->data); | |
105 | 112 | free(blk); | |
106 | 112 | item = next; | |
107 | } | ||
108 | 82 | } | |
109 | |||
110 | 82 | static void buffer_unlock_and_free ( | |
111 | Buffer *buffer, | ||
112 | ErrorBuffer *ebuf, | ||
113 | const FileLocksContext *locks_ctx | ||
114 | ) { | ||
115 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 82 times.
|
82 | if (buffer->locked) { |
116 | ✗ | unlock_file(locks_ctx, ebuf, buffer->abs_filename); | |
117 | } | ||
118 | |||
119 | 82 | free_changes(&buffer->change_head); | |
120 | 82 | ptr_array_free_array(&buffer->line_start_states); | |
121 | 82 | ptr_array_free_array(&buffer->views); | |
122 | 82 | free(buffer->display_filename); | |
123 | 82 | free(buffer->abs_filename); | |
124 | |||
125 |
2/2✓ Branch 0 (7→8) taken 76 times.
✓ Branch 1 (7→10) taken 6 times.
|
82 | if (buffer->stdout_buffer) { |
126 | /* | ||
127 | * If this buffer is to be piped to stdout on exit, retain just | ||
128 | * the blocks and the buffer itself. After this point, the pointer | ||
129 | * in main() takes ownership and is responsible for freeing the | ||
130 | * remaining allocations. | ||
131 | * | ||
132 | * See also: | ||
133 | * • init_std_buffer() | ||
134 | * • buffer_write_blocks_and_free() | ||
135 | * • main() | ||
136 | * • cmd_save() | ||
137 | */ | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | 76 | free_blocks(buffer); | |
142 | 76 | free(buffer); | |
143 | } | ||
144 | |||
145 | 9 | void free_buffers ( | |
146 | PointerArray *buffers, | ||
147 | ErrorBuffer *ebuf, | ||
148 | const FileLocksContext *locks_ctx | ||
149 | ) { | ||
150 |
1/2✗ Branch 0 (5→3) not taken.
✓ Branch 1 (5→6) taken 9 times.
|
9 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
151 | ✗ | Buffer *buffer = buffers->ptrs[i]; | |
152 | ✗ | buffer_unlock_and_free(buffer, ebuf, locks_ctx); | |
153 | ✗ | buffers->ptrs[i] = NULL; | |
154 | } | ||
155 | 9 | ptr_array_free_array(buffers); | |
156 | 9 | } | |
157 | |||
158 | 82 | void buffer_remove_unlock_and_free ( | |
159 | PointerArray *buffers, | ||
160 | Buffer *buffer, | ||
161 | ErrorBuffer *ebuf, | ||
162 | const FileLocksContext *locks_ctx | ||
163 | ) { | ||
164 | 82 | ptr_array_remove(buffers, buffer); | |
165 | 82 | buffer_unlock_and_free(buffer, ebuf, locks_ctx); | |
166 | 82 | } | |
167 | |||
168 | 873 | static bool same_file(const Buffer *buffer, const struct stat *st) | |
169 | { | ||
170 |
3/4✓ Branch 0 (2→3) taken 349 times.
✓ Branch 1 (2→4) taken 524 times.
✓ Branch 2 (3→4) taken 349 times.
✗ Branch 3 (3→5) not taken.
|
873 | return (st->st_dev == buffer->file.dev) && (st->st_ino == buffer->file.ino); |
171 | } | ||
172 | |||
173 | 27 | Buffer *find_buffer(const PointerArray *buffers, const char *abs_filename) | |
174 | { | ||
175 | 27 | struct stat st; | |
176 | 27 | bool st_ok = stat(abs_filename, &st) == 0; | |
177 |
2/2✓ Branch 0 (9→4) taken 873 times.
✓ Branch 1 (9→10) taken 27 times.
|
900 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
178 | 873 | Buffer *buffer = buffers->ptrs[i]; | |
179 | 873 | const char *f = buffer->abs_filename; | |
180 |
5/8✓ Branch 0 (4→5) taken 349 times.
✓ Branch 1 (4→6) taken 524 times.
✓ Branch 2 (5→6) taken 349 times.
✗ Branch 3 (5→10) not taken.
✓ Branch 4 (6→7) taken 873 times.
✗ Branch 5 (6→8) not taken.
✓ Branch 6 (7→8) taken 873 times.
✗ Branch 7 (7→10) not taken.
|
873 | if ((f && streq(f, abs_filename)) || (st_ok && same_file(buffer, &st))) { |
181 | return buffer; | ||
182 | } | ||
183 | } | ||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | 11 | Buffer *find_buffer_by_id(const PointerArray *buffers, unsigned long id) | |
188 | { | ||
189 |
2/2✓ Branch 0 (5→3) taken 72 times.
✓ Branch 1 (5→6) taken 7 times.
|
79 | for (size_t i = 0, n = buffers->count; i < n; i++) { |
190 | 72 | Buffer *buffer = buffers->ptrs[i]; | |
191 |
2/2✓ Branch 0 (3→4) taken 68 times.
✓ Branch 1 (3→6) taken 4 times.
|
72 | if (buffer->id == id) { |
192 | return buffer; | ||
193 | } | ||
194 | } | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | 76 | bool buffer_detect_filetype(Buffer *buffer, const PointerArray *filetypes) | |
199 | { | ||
200 | 76 | StringView line = STRING_VIEW_INIT; | |
201 |
2/2✓ Branch 0 (2→3) taken 25 times.
✓ Branch 1 (2→5) taken 51 times.
|
76 | if (BLOCK(buffer->blocks.next)->size) { |
202 | 25 | BlockIter bi = block_iter(buffer); | |
203 | 25 | line = block_iter_get_line(&bi); | |
204 |
1/2✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→11) taken 51 times.
|
51 | } else if (!buffer->abs_filename) { |
205 | return false; | ||
206 | } | ||
207 | |||
208 | 25 | const char *ft = find_ft(filetypes, buffer->abs_filename, line); | |
209 |
3/4✓ Branch 0 (7→8) taken 4 times.
✓ Branch 1 (7→11) taken 21 times.
✓ Branch 2 (8→9) taken 4 times.
✗ Branch 3 (8→11) not taken.
|
25 | if (ft && !streq(ft, buffer->options.filetype)) { |
210 | 4 | buffer->options.filetype = str_intern(ft); | |
211 | 4 | return true; | |
212 | } | ||
213 | |||
214 | return false; | ||
215 | } | ||
216 | |||
217 | 136 | void buffer_update_short_filename_cwd(Buffer *buffer, const StringView *home, const char *cwd) | |
218 | { | ||
219 | 136 | const char *abs = buffer->abs_filename; | |
220 |
2/2✓ Branch 0 (2→3) taken 73 times.
✓ Branch 1 (2→7) taken 63 times.
|
136 | if (!abs) { |
221 | return; | ||
222 | } | ||
223 |
1/2✓ Branch 0 (3→4) taken 73 times.
✗ Branch 1 (3→5) not taken.
|
73 | char *name = cwd ? short_filename_cwd(abs, cwd, home) : xstrdup(abs); |
224 | 73 | buffer_set_display_filename(buffer, name); | |
225 | } | ||
226 | |||
227 | 47 | void buffer_update_short_filename(Buffer *buffer, const StringView *home) | |
228 | { | ||
229 | 47 | const char *abs = buffer->abs_filename; | |
230 | 47 | BUG_ON(!abs); | |
231 | 47 | buffer_set_display_filename(buffer, short_filename(abs, home)); | |
232 | 47 | } | |
233 | |||
234 | 59 | void buffer_update_syntax(EditorState *e, Buffer *buffer) | |
235 | { | ||
236 | 59 | Syntax *syn = NULL; | |
237 |
2/2✓ Branch 0 (2→3) taken 58 times.
✓ Branch 1 (2→6) taken 1 times.
|
59 | if (buffer->options.syntax) { |
238 | // Even "none" can have syntax | ||
239 | 58 | syn = find_syntax(&e->syntaxes, buffer->options.filetype); | |
240 |
2/2✓ Branch 0 (4→5) taken 53 times.
✓ Branch 1 (4→6) taken 5 times.
|
58 | if (!syn) { |
241 | 53 | syn = load_syntax_by_filetype(e, buffer->options.filetype); | |
242 | } | ||
243 | } | ||
244 |
2/2✓ Branch 0 (6→7) taken 6 times.
✓ Branch 1 (6→12) taken 53 times.
|
59 | if (syn == buffer->syntax) { |
245 | return; | ||
246 | } | ||
247 | |||
248 | 6 | buffer->syntax = syn; | |
249 |
2/2✓ Branch 0 (7→8) taken 5 times.
✓ Branch 1 (7→11) taken 1 times.
|
6 | if (syn) { |
250 | // Start state of first line is constant | ||
251 | 5 | PointerArray *s = &buffer->line_start_states; | |
252 |
1/2✓ Branch 0 (8→9) taken 5 times.
✗ Branch 1 (8→10) not taken.
|
5 | if (!s->alloc) { |
253 | 5 | ptr_array_init(s, 64); | |
254 | } | ||
255 | 5 | s->ptrs[0] = syn->start_state; | |
256 | 5 | s->count = 1; | |
257 | } | ||
258 | |||
259 | 6 | mark_all_lines_changed(buffer); | |
260 | } | ||
261 | |||
262 | 44 | static bool allow_odd_indent(uint8_t indents_bitmask) | |
263 | { | ||
264 | 44 | static_assert(INDENT_WIDTH_MAX == 8); | |
265 | 44 | return !!(indents_bitmask & 0x55); // 0x55 == 0b01010101 | |
266 | } | ||
267 | |||
268 | 195 | static int indent_len(StringView line, uint8_t indents_bitmask, bool *tab_indent) | |
269 | { | ||
270 | 195 | bool space_before_tab = false; | |
271 | 195 | size_t spaces = 0; | |
272 | 195 | size_t tabs = 0; | |
273 | 195 | size_t pos = 0; | |
274 | |||
275 |
2/2✓ Branch 0 (9→3) taken 787 times.
✓ Branch 1 (9→10) taken 24 times.
|
811 | for (size_t n = line.length; pos < n; pos++) { |
276 |
3/3✓ Branch 0 (3→4) taken 110 times.
✓ Branch 1 (3→7) taken 506 times.
✓ Branch 2 (3→10) taken 171 times.
|
787 | switch (line.data[pos]) { |
277 | 110 | case '\t': | |
278 | 110 | tabs++; | |
279 |
2/2✓ Branch 0 (4→5) taken 44 times.
✓ Branch 1 (4→6) taken 66 times.
|
110 | if (spaces) { |
280 | 44 | space_before_tab = true; | |
281 | } | ||
282 | 110 | continue; | |
283 | 506 | case ' ': | |
284 | 506 | spaces++; | |
285 | 506 | continue; | |
286 | } | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | 195 | *tab_indent = false; | |
291 |
2/2✓ Branch 0 (10→11) taken 171 times.
✓ Branch 1 (10→21) taken 24 times.
|
195 | if (pos == line.length) { |
292 | return -1; // Whitespace only | ||
293 | } | ||
294 |
2/2✓ Branch 0 (11→12) taken 139 times.
✓ Branch 1 (11→21) taken 32 times.
|
171 | if (pos == 0) { |
295 | return 0; // Not indented | ||
296 | } | ||
297 |
2/2✓ Branch 0 (12→13) taken 117 times.
✓ Branch 1 (12→21) taken 22 times.
|
139 | if (space_before_tab) { |
298 | return -2; // Mixed indent | ||
299 | } | ||
300 |
2/2✓ Branch 0 (13→14) taken 22 times.
✓ Branch 1 (13→15) taken 95 times.
|
117 | if (tabs) { |
301 | // Tabs and possible spaces after tab for alignment | ||
302 | 22 | *tab_indent = true; | |
303 | 22 | return tabs * 8; | |
304 | } | ||
305 |
3/4✓ Branch 0 (15→16) taken 95 times.
✗ Branch 1 (15→20) not taken.
✓ Branch 2 (16→17) taken 66 times.
✓ Branch 3 (16→20) taken 29 times.
|
95 | if (line.length > spaces && line.data[spaces] == '*') { |
306 | // '*' after indent, could be long C style comment | ||
307 |
4/4✓ Branch 0 (17→18) taken 44 times.
✓ Branch 1 (17→19) taken 22 times.
✓ Branch 2 (18→19) taken 22 times.
✓ Branch 3 (18→20) taken 22 times.
|
66 | if (spaces & 1 || allow_odd_indent(indents_bitmask)) { |
308 | 44 | return spaces - 1; | |
309 | } | ||
310 | } | ||
311 | 51 | return spaces; | |
312 | } | ||
313 | |||
314 | 22 | UNITTEST { | |
315 | 22 | bool tab; | |
316 | 22 | int len = indent_len(strview_from_cstring(" 4 space"), 0, &tab); | |
317 | 22 | BUG_ON(len != 4); | |
318 | 22 | BUG_ON(tab); | |
319 | |||
320 | 22 | len = indent_len(strview_from_cstring("\t\t2 tab"), 0, &tab); | |
321 | 22 | BUG_ON(len != 16); | |
322 | 22 | BUG_ON(!tab); | |
323 | |||
324 | 22 | len = indent_len(strview_from_cstring("no indent"), 0, &tab); | |
325 | 22 | BUG_ON(len != 0); | |
326 | |||
327 | 22 | len = indent_len(strview_from_cstring(" \t mixed"), 0, &tab); | |
328 | 22 | BUG_ON(len != -2); | |
329 | |||
330 | 22 | len = indent_len(strview_from_cstring("\t \t "), 0, &tab); | |
331 | 22 | BUG_ON(len != -1); // whitespace only | |
332 | |||
333 | 22 | len = indent_len(strview_from_cstring(" * 5 space"), 0, &tab); | |
334 | 22 | BUG_ON(len != 4); | |
335 | |||
336 | 22 | StringView line = strview_from_cstring(" * 4 space"); | |
337 | 22 | len = indent_len(line, 0, &tab); | |
338 | 22 | BUG_ON(len != 4); | |
339 | 22 | len = indent_len(line, 1 << 2, &tab); | |
340 | 22 | BUG_ON(len != 3); | |
341 | 22 | } | |
342 | |||
343 | 3 | static bool detect_indent(Buffer *buffer) | |
344 | { | ||
345 | 3 | LocalOptions *options = &buffer->options; | |
346 | 3 | unsigned int bitset = options->detect_indent; | |
347 | 3 | BlockIter bi = block_iter(buffer); | |
348 | 3 | unsigned int tab_count = 0; | |
349 | 3 | unsigned int space_count = 0; | |
350 | 3 | int current_indent = 0; | |
351 | 3 | int counts[INDENT_WIDTH_MAX + 1] = {0}; | |
352 | 3 | BUG_ON((bitset & ((1u << INDENT_WIDTH_MAX) - 1)) != bitset); | |
353 | |||
354 |
2/2✓ Branch 0 (19→4) taken 19 times.
✓ Branch 1 (19→20) taken 3 times.
|
22 | for (size_t i = 0, j = 1; i < 200 && j > 0; i++, j = block_iter_next_line(&bi)) { |
355 | 19 | StringView line = block_iter_get_line(&bi); | |
356 | 19 | bool tab; | |
357 | 19 | int indent = indent_len(line, bitset, &tab); | |
358 |
3/3✓ Branch 0 (6→7) taken 2 times.
✓ Branch 1 (6→8) taken 10 times.
✓ Branch 2 (6→9) taken 7 times.
|
19 | switch (indent) { |
359 | 2 | case -2: // Ignore mixed indent because tab width might not be 8 | |
360 | case -1: // Empty line; no change in indent | ||
361 | 12 | continue; | |
362 | 10 | case 0: | |
363 | 10 | current_indent = 0; | |
364 | 10 | continue; | |
365 | } | ||
366 | |||
367 | 7 | BUG_ON(indent <= 0); | |
368 | 7 | int change = indent - current_indent; | |
369 |
2/2✓ Branch 0 (11→12) taken 3 times.
✓ Branch 1 (11→13) taken 4 times.
|
7 | if (change >= 1 && change <= INDENT_WIDTH_MAX) { |
370 | 3 | counts[change]++; | |
371 | } | ||
372 | |||
373 |
1/2✗ Branch 0 (13→14) not taken.
✓ Branch 1 (13→15) taken 7 times.
|
7 | if (tab) { |
374 | ✗ | tab_count++; | |
375 | } else { | ||
376 | 7 | space_count++; | |
377 | } | ||
378 | 7 | current_indent = indent; | |
379 | } | ||
380 | |||
381 |
1/2✓ Branch 0 (20→21) taken 3 times.
✗ Branch 1 (20→30) not taken.
|
3 | if (tab_count == 0 && space_count == 0) { |
382 | return false; | ||
383 | } | ||
384 | |||
385 |
1/2✗ Branch 0 (21→22) not taken.
✓ Branch 1 (21→27) taken 3 times.
|
3 | if (tab_count > space_count) { |
386 | ✗ | options->emulate_tab = false; | |
387 | ✗ | options->expand_tab = false; | |
388 | ✗ | options->indent_width = options->tab_width; | |
389 | ✗ | return true; | |
390 | } | ||
391 | |||
392 | size_t m = 0; | ||
393 |
2/2✓ Branch 0 (27→23) taken 24 times.
✓ Branch 1 (27→28) taken 3 times.
|
27 | for (size_t i = 1; i < ARRAYLEN(counts); i++) { |
394 | 24 | unsigned int bit = 1u << (i - 1); | |
395 |
4/4✓ Branch 0 (23→24) taken 9 times.
✓ Branch 1 (23→26) taken 15 times.
✓ Branch 2 (24→25) taken 3 times.
✓ Branch 3 (24→26) taken 6 times.
|
24 | if ((bitset & bit) && counts[i] > counts[m]) { |
396 | 3 | m = i; | |
397 | } | ||
398 | } | ||
399 | |||
400 |
1/2✓ Branch 0 (28→29) taken 3 times.
✗ Branch 1 (28→30) not taken.
|
3 | if (m == 0) { |
401 | return false; | ||
402 | } | ||
403 | |||
404 | 3 | options->emulate_tab = true; | |
405 | 3 | options->expand_tab = true; | |
406 | 3 | options->indent_width = m; | |
407 | 3 | return true; | |
408 | } | ||
409 | |||
410 | 57 | void buffer_setup(EditorState *e, Buffer *buffer) | |
411 | { | ||
412 | 57 | const char *filename = buffer->abs_filename; | |
413 | 57 | buffer->setup = true; | |
414 | 57 | buffer_detect_filetype(buffer, &e->filetypes); | |
415 | 57 | set_file_options(e, buffer); | |
416 | 57 | set_editorconfig_options(buffer); | |
417 | 57 | buffer_update_syntax(e, buffer); | |
418 |
3/4✓ Branch 0 (6→7) taken 3 times.
✓ Branch 1 (6→9) taken 54 times.
✓ Branch 2 (7→8) taken 3 times.
✗ Branch 3 (7→9) not taken.
|
57 | if (buffer->options.detect_indent && filename) { |
419 | 3 | detect_indent(buffer); | |
420 | } | ||
421 | 57 | sanity_check_local_options(&e->err, &buffer->options); | |
422 | 57 | } | |
423 | |||
424 | 4 | void buffer_count_blocks_and_bytes(const Buffer *buffer, uintmax_t counts[2]) | |
425 | { | ||
426 | 4 | uintmax_t blocks = 0; | |
427 | 4 | uintmax_t bytes = 0; | |
428 | 4 | const Block *blk; | |
429 |
2/2✓ Branch 0 (4→3) taken 8 times.
✓ Branch 1 (4→5) taken 4 times.
|
12 | block_for_each(blk, &buffer->blocks) { |
430 | 8 | blocks += 1; | |
431 | 8 | bytes += blk->size; | |
432 | } | ||
433 | 4 | counts[0] = blocks; | |
434 | 4 | counts[1] = bytes; | |
435 | 4 | } | |
436 |