dte test coverage


Directory: ./
File: src/shift.c
Date: 2025-11-12 12:04:10
Coverage Exec Excl Total
Lines: 77.3% 68 0 88
Functions: 100.0% 5 0 5
Branches: 57.9% 22 0 38

Line Branch Exec Source
1 #include <stddef.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "shift.h"
5 #include "block-iter.h"
6 #include "buffer.h"
7 #include "change.h"
8 #include "indent.h"
9 #include "move.h"
10 #include "options.h"
11 #include "selection.h"
12 #include "util/debug.h"
13 #include "util/macros.h"
14 #include "util/xmalloc.h"
15
16 10 static char *alloc_indent(const LocalOptions *options, size_t count, size_t *sizep)
17 {
18 10 bool use_spaces = use_spaces_for_indent(options);
19
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 9 times.
10 size_t size = use_spaces ? count * options->indent_width : count;
20 10 *sizep = size;
21 10 return memset(xmalloc(size), use_spaces ? ' ' : '\t', size);
22 }
23
24 10 static void shift_right(View *view, size_t nr_lines, size_t count)
25 {
26 10 BUG_ON(!block_iter_is_bol(&view->cursor))
27 10 const LocalOptions *options = &view->buffer->options;
28 10 size_t indent_size;
29 10 char *indent = alloc_indent(options, count, &indent_size);
30
31 30 for (size_t i = 0; true; ) {
32 30 StringView line = block_iter_get_line(&view->cursor);
33 30 IndentInfo info = get_indent_info(options, line);
34
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 30 times.
30 if (info.wsonly) {
35 if (info.bytes) {
36 // Remove indentation
37 buffer_delete_bytes(view, info.bytes);
38 }
39
1/2
✓ Branch 10 → 11 taken 30 times.
✗ Branch 10 → 12 not taken.
30 } else if (info.sane) {
40 // Insert whitespace
41 30 buffer_insert_bytes(view, indent, indent_size);
42 } else {
43 // Replace whole indentation with sane one
44 size_t size;
45 char *buf = alloc_indent(options, info.level + count, &size);
46 buffer_replace_bytes(view, info.bytes, buf, size);
47 free(buf);
48 }
49
2/2
✓ Branch 15 → 16 taken 20 times.
✓ Branch 15 → 18 taken 10 times.
30 if (++i == nr_lines) {
50 break;
51 }
52 20 block_iter_eat_line(&view->cursor);
53 }
54
55 10 free(indent);
56 10 }
57
58 9 static void shift_left(View *view, size_t nr_lines, size_t count)
59 {
60 9 BUG_ON(!block_iter_is_bol(&view->cursor))
61 9 const LocalOptions *options = &view->buffer->options;
62 9 const size_t indent_width = options->indent_width;
63 9 const bool space_indent = use_spaces_for_indent(options);
64
65 25 for (size_t i = 0; true; ) {
66 25 StringView line = block_iter_get_line(&view->cursor);
67 25 IndentInfo info = get_indent_info(options, line);
68
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 25 times.
25 if (info.wsonly) {
69 if (info.bytes) {
70 // Remove indentation
71 buffer_delete_bytes(view, info.bytes);
72 }
73
3/4
✓ Branch 10 → 11 taken 23 times.
✓ Branch 10 → 16 taken 2 times.
✓ Branch 11 → 12 taken 23 times.
✗ Branch 11 → 16 not taken.
48 } else if (info.level && info.sane) {
74 23 size_t n = MIN(count, info.level);
75
1/2
✓ Branch 12 → 13 taken 23 times.
✗ Branch 12 → 14 not taken.
23 if (space_indent) {
76 23 n *= indent_width;
77 }
78 23 buffer_delete_bytes(view, n);
79
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 22 taken 2 times.
2 } else if (info.bytes) {
80 // Replace whole indentation with sane one
81 if (info.level > count) {
82 size_t size;
83 char *buf = alloc_indent(options, info.level - count, &size);
84 buffer_replace_bytes(view, info.bytes, buf, size);
85 free(buf);
86 } else {
87 buffer_delete_bytes(view, info.bytes);
88 }
89 }
90
2/2
✓ Branch 22 → 23 taken 16 times.
✓ Branch 22 → 25 taken 9 times.
25 if (++i == nr_lines) {
91 break;
92 }
93 16 block_iter_eat_line(&view->cursor);
94 }
95 9 }
96
97 19 static void do_shift_lines(View *view, int count, size_t nr_lines)
98 {
99 19 begin_change_chain();
100 19 block_iter_bol(&view->cursor);
101
2/2
✓ Branch 4 → 5 taken 10 times.
✓ Branch 4 → 6 taken 9 times.
19 if (count > 0) {
102 10 shift_right(view, nr_lines, count);
103 } else {
104 9 shift_left(view, nr_lines, -count);
105 }
106 19 end_change_chain(view);
107 19 }
108
109 19 void shift_lines(View *view, int count)
110 {
111 19 int width = view->buffer->options.indent_width;
112 19 BUG_ON(width > INDENT_WIDTH_MAX || width < 1);
113 19 BUG_ON(count == 0);
114
115 19 long x = view_get_preferred_x(view) + (count * width);
116 19 x = MAX(x, 0);
117
118
2/2
✓ Branch 7 → 8 taken 10 times.
✓ Branch 7 → 10 taken 9 times.
19 if (view->selection == SELECT_NONE) {
119 10 do_shift_lines(view, count, 1);
120 10 goto out;
121 }
122
123 9 view->selection = SELECT_LINES;
124 9 SelectionInfo info = init_selection(view);
125 9 view->cursor = info.si;
126 9 size_t nr_lines = get_nr_selected_lines(&info);
127
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 9 times.
9 if (unlikely(nr_lines == 0)) {
128 return;
129 }
130
131 9 do_shift_lines(view, count, nr_lines);
132
1/2
✓ Branch 15 → 16 taken 9 times.
✗ Branch 15 → 21 not taken.
9 if (info.swapped) {
133 // Cursor should be at beginning of selection
134 9 block_iter_bol(&view->cursor);
135 9 view->sel_so = block_iter_get_offset(&view->cursor);
136
2/2
✓ Branch 20 → 19 taken 36 times.
✓ Branch 20 → 26 taken 9 times.
45 while (--nr_lines) {
137 36 block_iter_prev_line(&view->cursor);
138 }
139 } else {
140 BlockIter save = view->cursor;
141 while (--nr_lines) {
142 block_iter_prev_line(&view->cursor);
143 }
144 view->sel_so = block_iter_get_offset(&view->cursor);
145 view->cursor = save;
146 }
147
148 19 out:
149 19 move_to_preferred_x(view, x);
150 }
151