dte test coverage


Directory: ./
File: src/wrap.c
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 77 81 95.1%
Functions: 6 6 100.0%
Branches: 36 52 69.2%

Line Branch Exec Source
1 #include <stdbool.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "wrap.h"
5 #include "buffer.h"
6 #include "indent.h"
7 #include "selection.h"
8 #include "util/string-view.h"
9 #include "util/string.h"
10 #include "util/unicode.h"
11 #include "util/utf8.h"
12
13 typedef struct {
14 String buf;
15 char *indent;
16 size_t indent_len;
17 size_t indent_width;
18 size_t cur_width;
19 size_t text_width;
20 } ParagraphFormatter;
21
22 60 static void add_word(ParagraphFormatter *pf, const char *word, size_t len)
23 {
24 60 size_t i = 0;
25 60 size_t word_width = 0;
26
2/2
✓ Branch 0 (5→3) taken 180 times.
✓ Branch 1 (5→6) taken 60 times.
240 while (i < len) {
27 180 word_width += u_char_width(u_get_char(word, len, &i));
28 }
29
30
4/4
✓ Branch 0 (6→7) taken 58 times.
✓ Branch 1 (6→10) taken 2 times.
✓ Branch 2 (7→8) taken 6 times.
✓ Branch 3 (7→10) taken 52 times.
60 if (pf->cur_width && pf->cur_width + 1 + word_width > pf->text_width) {
31 6 string_append_byte(&pf->buf, '\n');
32 6 pf->cur_width = 0;
33 }
34
35
2/2
✓ Branch 0 (10→11) taken 8 times.
✓ Branch 1 (10→14) taken 52 times.
60 if (pf->cur_width == 0) {
36
1/2
✗ Branch 0 (11→12) not taken.
✓ Branch 1 (11→13) taken 8 times.
8 if (pf->indent_len) {
37 string_append_buf(&pf->buf, pf->indent, pf->indent_len);
38 }
39 8 pf->cur_width = pf->indent_width;
40 } else {
41 52 string_append_byte(&pf->buf, ' ');
42 52 pf->cur_width++;
43 }
44
45 60 string_append_buf(&pf->buf, word, len);
46 60 pf->cur_width += word_width;
47 60 }
48
49 2 static bool is_long_comment_delim(const StringView *sv)
50 {
51 // TODO: make this configurable
52
2/4
✓ Branch 0 (3→4) taken 2 times.
✗ Branch 1 (3→7) not taken.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→7) taken 2 times.
2 return strview_equal_cstring(sv, "/*") || strview_equal_cstring(sv, "*/");
53 }
54
55 5 static bool is_paragraph_separator(const StringView *line)
56 {
57 5 StringView trimmed = *line;
58 5 strview_trim(&trimmed);
59
3/4
✓ Branch 0 (3→4) taken 2 times.
✓ Branch 1 (3→7) taken 3 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→7) taken 2 times.
5 return (trimmed.length == 0) || is_long_comment_delim(&trimmed);
60 }
61
62 3 static bool in_paragraph (
63 const StringView *line,
64 size_t para_indent_width,
65 unsigned int tab_width
66 ) {
67 3 size_t w = get_indent_width(line, tab_width);
68
2/4
✓ Branch 0 (3→4) taken 3 times.
✗ Branch 1 (3→7) not taken.
✓ Branch 2 (5→6) taken 3 times.
✗ Branch 3 (5→7) not taken.
3 return (w == para_indent_width) && !is_paragraph_separator(line);
69 }
70
71 2 static size_t paragraph_size(View *view)
72 {
73 2 BlockIter bi = view->cursor;
74 2 block_iter_bol(&bi);
75 2 StringView line = block_iter_get_line(&bi);
76
1/2
✓ Branch 0 (5→6) taken 2 times.
✗ Branch 1 (5→21) not taken.
2 if (is_paragraph_separator(&line)) {
77 // Not in paragraph
78 return 0;
79 }
80
81 2 unsigned int tab_width = view->buffer->options.tab_width;
82 2 size_t para_indent_width = get_indent_width(&line, tab_width);
83
84 // Go to beginning of paragraph
85
2/2
✓ Branch 0 (14→7) taken 1 times.
✓ Branch 1 (14→15) taken 1 times.
2 while (block_iter_prev_line(&bi)) {
86 1 line = block_iter_get_line(&bi);
87
1/2
✓ Branch 0 (9→10) taken 1 times.
✗ Branch 1 (9→13) not taken.
1 if (!in_paragraph(&line, para_indent_width, tab_width)) {
88 1 block_iter_eat_line(&bi);
89 1 break;
90 }
91 }
92 2 view->cursor = bi;
93
94 // Get size of paragraph
95 2 size_t size = 0;
96 2 do {
97 2 size_t bytes = block_iter_eat_line(&bi);
98
1/2
✓ Branch 0 (17→18) taken 2 times.
✗ Branch 1 (17→21) not taken.
2 if (!bytes) {
99 break;
100 }
101 2 size += bytes;
102 2 line = block_iter_get_line(&bi);
103
1/2
✗ Branch 0 (20→16) not taken.
✓ Branch 1 (20→21) taken 2 times.
2 } while (in_paragraph(&line, para_indent_width, tab_width));
104 return size;
105 }
106
107 2 void wrap_paragraph(View *view, size_t text_width)
108 {
109 2 size_t len;
110
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 2 times.
2 if (view->selection) {
111 view->selection = SELECT_LINES;
112 len = prepare_selection(view);
113 } else {
114 2 len = paragraph_size(view);
115 }
116
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 2 times.
2 if (!len) {
117 return;
118 }
119
120 2 const LocalOptions *options = &view->buffer->options;
121 2 char *sel = block_iter_get_bytes(&view->cursor, len);
122 2 StringView sv = string_view(sel, len);
123 2 size_t indent_width = get_indent_width(&sv, options->tab_width);
124 2 char *indent = make_indent(options, indent_width);
125
126 4 ParagraphFormatter pf = {
127 .buf = STRING_INIT,
128 .indent = indent,
129
1/2
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 2 times.
2 .indent_len = indent ? strlen(indent) : 0,
130 .indent_width = indent_width,
131 .cur_width = 0,
132 .text_width = text_width
133 };
134
135 62 for (size_t i = 0; true; ) {
136
2/2
✓ Branch 0 (19→13) taken 122 times.
✓ Branch 1 (19→20) taken 2 times.
124 while (i < len) {
137 122 size_t tmp = i;
138
2/2
✓ Branch 0 (14→15) taken 62 times.
✓ Branch 1 (14→16) taken 60 times.
122 if (!u_is_breakable_whitespace(u_get_char(sel, len, &tmp))) {
139 break;
140 }
141 62 i = tmp;
142 }
143
2/2
✓ Branch 0 (20→25) taken 60 times.
✓ Branch 1 (20→27) taken 2 times.
62 if (i == len) {
144 break;
145 }
146
147 size_t start = i;
148
1/2
✓ Branch 0 (25→21) taken 240 times.
✗ Branch 1 (25→26) not taken.
240 while (i < len) {
149 240 size_t tmp = i;
150
2/2
✓ Branch 0 (22→23) taken 180 times.
✓ Branch 1 (22→24) taken 60 times.
240 if (u_is_breakable_whitespace(u_get_char(sel, len, &tmp))) {
151 break;
152 }
153 180 i = tmp;
154 }
155
156 60 add_word(&pf, sel + start, i - start);
157 }
158
159
1/2
✓ Branch 0 (27→28) taken 2 times.
✗ Branch 1 (27→29) not taken.
2 if (pf.buf.len) {
160 2 string_append_byte(&pf.buf, '\n');
161 }
162 2 buffer_replace_bytes(view, len, pf.buf.buffer, pf.buf.len);
163
1/2
✓ Branch 0 (30→31) taken 2 times.
✗ Branch 1 (30→32) not taken.
2 if (pf.buf.len) {
164 2 block_iter_skip_bytes(&view->cursor, pf.buf.len - 1);
165 }
166
167 2 string_free(&pf.buf);
168 2 free(pf.indent);
169 2 free(sel);
170 2 unselect(view);
171 }
172