dte test coverage


Directory: ./
File: src/block-iter.h
Date: 2025-12-20 15:55:55
Coverage Exec Excl Total
Lines: 73.0% 27 0 37
Functions: 88.9% 8 0 9
Branches: 62.5% 10 0 16

Line Branch Exec Source
1 #ifndef BLOCK_ITER_H
2 #define BLOCK_ITER_H
3
4 #include <stdbool.h>
5 #include <stddef.h>
6 #include "block.h"
7 #include "util/list.h"
8 #include "util/macros.h"
9 #include "util/string-view.h"
10 #include "util/unicode.h"
11
12 // An iterator used to represent the cursor position for each View of a
13 // Buffer (see View::cursor) and also as a means for accessing/iterating
14 // the Blocks that make up the text contents of a Buffer (see Buffer::blocks).
15 typedef struct {
16 Block *blk; // The Block this iterator/cursor currently points to
17 const ListHead *head; // A pointer to the Buffer::blocks that owns `blk`
18 size_t offset; // The current position within `blk->data`
19 } BlockIter;
20
21 typedef struct {
22 StringView line;
23 size_t cursor_offset;
24 } CurrentLineRef;
25
26 11 static inline void block_iter_bof(BlockIter *bi)
27 {
28 11 bi->blk = BLOCK(bi->head->next);
29 11 bi->offset = 0;
30 11 }
31
32 8 static inline void block_iter_eof(BlockIter *bi)
33 {
34 8 bi->blk = BLOCK(bi->head->prev);
35 8 bi->offset = bi->blk->size;
36 8 }
37
38 325 static inline bool block_iter_is_eof(const BlockIter *bi)
39 {
40
3/4
✓ Branch 2 → 3 taken 59 times.
✓ Branch 2 → 4 taken 266 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 59 times.
325 return bi->offset == bi->blk->size && bi->blk->node.next == bi->head;
41 }
42
43 471 static inline bool block_iter_is_bol(const BlockIter *bi)
44 {
45 // See also: Block invariants mentioned in sanity_check_blocks()
46
4/4
✓ Branch 2 → 3 taken 372 times.
✓ Branch 2 → 5 taken 99 times.
✓ Branch 3 → 4 taken 210 times.
✓ Branch 3 → 5 taken 162 times.
471 return bi->offset == 0 || bi->blk->data[bi->offset - 1] == '\n';
47 }
48
49 static inline bool block_iter_is_eol(const BlockIter *bi)
50 {
51 const Block *blk = bi->blk;
52 size_t offset = bi->offset;
53 if (offset == blk->size) {
54 if (blk->node.next == bi->head) {
55 // EOF
56 return true;
57 }
58
59 // Normalize
60 blk = BLOCK(blk->node.next);
61 offset = 0;
62 }
63
64 return blk->data[offset] == '\n';
65 }
66
67 1518 static inline void block_iter_normalize(BlockIter *bi)
68 {
69 1518 const Block *blk = bi->blk;
70
3/4
✓ Branch 2 → 3 taken 103 times.
✓ Branch 2 → 5 taken 1415 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 103 times.
1518 if (bi->offset == blk->size && blk->node.next != bi->head) {
71 bi->blk = BLOCK(blk->node.next);
72 bi->offset = 0;
73 }
74 1518 }
75
76 size_t block_iter_eat_line(BlockIter *bi) NONNULL_ARGS;
77 size_t block_iter_next_line(BlockIter *bi) NONNULL_ARGS;
78 size_t block_iter_prev_line(BlockIter *bi) NONNULL_ARGS;
79 size_t block_iter_prev_line_eol(BlockIter *bi) NONNULL_ARGS;
80 size_t block_iter_next_char(BlockIter *bi, CodePoint *up) NONNULL_ARGS READWRITE(1) WRITEONLY(2);
81 size_t block_iter_prev_char(BlockIter *bi, CodePoint *up) NONNULL_ARGS READWRITE(1) WRITEONLY(2);
82 size_t block_iter_next_column(BlockIter *bi) NONNULL_ARGS;
83 size_t block_iter_prev_column(BlockIter *bi) NONNULL_ARGS;
84 size_t block_iter_bol(BlockIter *bi) NONNULL_ARGS;
85 size_t block_iter_eol(BlockIter *bi) NONNULL_ARGS;
86 size_t block_iter_skip_blanks_fwd(BlockIter *bi) NONNULL_ARGS;
87 size_t block_iter_skip_blanks_bwd(BlockIter *bi) NONNULL_ARGS;
88 bool block_iter_find_non_empty_line_bwd(BlockIter *bi) NONNULL_ARGS;
89 void block_iter_back_bytes(BlockIter *bi, size_t count) NONNULL_ARGS;
90 void block_iter_skip_bytes(BlockIter *bi, size_t count) NONNULL_ARGS;
91 void block_iter_goto_offset(BlockIter *bi, size_t offset) NONNULL_ARGS;
92 void block_iter_goto_line(BlockIter *bi, size_t line) NONNULL_ARGS;
93 size_t block_iter_get_offset(const BlockIter *bi) WARN_UNUSED_RESULT NONNULL_ARGS;
94 size_t block_iter_get_char(const BlockIter *bi, CodePoint *up) WARN_UNUSED_RESULT NONNULL_ARGS READONLY(1) WRITEONLY(2);
95 char *block_iter_get_bytes(const BlockIter *bi, size_t len) WARN_UNUSED_RESULT NONNULL_ARGS;
96 StringView block_iter_get_line_with_nl(BlockIter *bi) NONNULL_ARGS;
97
98 // Like block_iter_get_line_with_nl(), but excluding the newline
99 385 static inline StringView block_iter_get_line(BlockIter *bi)
100 {
101 385 StringView line = block_iter_get_line_with_nl(bi);
102 385 line.length -= (line.length > 0); // Trim the newline (if any)
103 385 return line;
104 }
105
106 // Like block_iter_get_line(), but always returning whole lines
107 18 static inline StringView get_current_line(BlockIter tmp)
108 {
109 18 block_iter_bol(&tmp);
110 18 return block_iter_get_line(&tmp);
111 }
112
113 // Like get_current_line(), but returning a struct that also includes the
114 // cursor offset (relative to BOL)
115 55 static inline CurrentLineRef get_current_line_and_offset(BlockIter tmp)
116 {
117 55 size_t offset = block_iter_bol(&tmp);
118 110 return (CurrentLineRef) {
119 55 .line = block_iter_get_line(&tmp),
120 .cursor_offset = offset,
121 };
122 }
123
124 #endif
125