| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <string.h> | ||
| 2 | #include "edit.h" | ||
| 3 | #include "block.h" | ||
| 4 | #include "buffer.h" | ||
| 5 | #include "syntax/highlight.h" | ||
| 6 | #include "util/debug.h" | ||
| 7 | #include "util/list.h" | ||
| 8 | #include "util/xmalloc.h" | ||
| 9 | |||
| 10 | enum { | ||
| 11 | BLOCK_EDIT_SIZE = 512 | ||
| 12 | }; | ||
| 13 | |||
| 14 | 459 | static void sanity_check_blocks(const View *view, bool check_newlines) | |
| 15 | { | ||
| 16 | 459 | if (!DEBUG_ASSERTIONS_ENABLED) { | |
| 17 | return; | ||
| 18 | } | ||
| 19 | |||
| 20 | 459 | const Buffer *buffer = view->buffer; | |
| 21 | 459 | BUG_ON(list_empty(&buffer->blocks)); | |
| 22 | 459 | BUG_ON(view->cursor.offset > view->cursor.blk->size); | |
| 23 | |||
| 24 | 459 | const Block *blk = BLOCK(buffer->blocks.next); | |
| 25 |
2/2✓ Branch 6 → 7 taken 19 times.
✓ Branch 6 → 24 taken 440 times.
|
459 | if (blk->size == 0) { |
| 26 | // The only time a zero-sized block is valid is when it's the | ||
| 27 | // first and only block | ||
| 28 | 19 | BUG_ON(buffer->blocks.next->next != &buffer->blocks); | |
| 29 | 19 | BUG_ON(view->cursor.blk != blk); | |
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | bool cursor_seen = false; | ||
| 34 |
2/2✓ Branch 24 → 11 taken 444 times.
✓ Branch 24 → 25 taken 440 times.
|
884 | block_for_each(blk, &buffer->blocks) { |
| 35 | 444 | const size_t size = blk->size; | |
| 36 | 444 | BUG_ON(size == 0); | |
| 37 | 444 | BUG_ON(size > blk->alloc); | |
| 38 |
2/2✓ Branch 15 → 16 taken 440 times.
✓ Branch 15 → 17 taken 4 times.
|
444 | if (blk == view->cursor.blk) { |
| 39 | 440 | cursor_seen = true; | |
| 40 | } | ||
| 41 |
2/2✓ Branch 17 → 18 taken 443 times.
✓ Branch 17 → 20 taken 1 time.
|
444 | if (check_newlines) { |
| 42 | // Non-empty blocks must ALWAYS end with a newline, since | ||
| 43 | // lines MAY NOT straddle multiple blocks | ||
| 44 | 443 | BUG_ON(blk->data[size - 1] != '\n'); | |
| 45 | } | ||
| 46 | 444 | if (DEBUG > 2) { | |
| 47 | 444 | BUG_ON(count_nl(blk->data, size) != blk->nl); | |
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | 440 | BUG_ON(!cursor_seen); | |
| 52 | } | ||
| 53 | |||
| 54 | 506 | static size_t copy_count_nl(char *dst, const char *src, size_t len) | |
| 55 | { | ||
| 56 | 506 | size_t nl = 0; | |
| 57 |
2/2✓ Branch 6 → 3 taken 28756 times.
✓ Branch 6 → 7 taken 506 times.
|
29262 | for (size_t i = 0; i < len; i++) { |
| 58 | 28756 | dst[i] = src[i]; | |
| 59 |
2/2✓ Branch 3 → 4 taken 232 times.
✓ Branch 3 → 5 taken 28524 times.
|
28756 | if (src[i] == '\n') { |
| 60 | 232 | nl++; | |
| 61 | } | ||
| 62 | } | ||
| 63 | 506 | return nl; | |
| 64 | } | ||
| 65 | |||
| 66 | 326 | static size_t insert_to_current(BlockIter *cursor, const char *buf, size_t len) | |
| 67 | { | ||
| 68 | 326 | Block *blk = cursor->blk; | |
| 69 | 326 | size_t offset = cursor->offset; | |
| 70 | 326 | size_t size = blk->size + len; | |
| 71 | 326 | block_grow(blk, size); | |
| 72 | 326 | memmove(blk->data + offset + len, blk->data + offset, blk->size - offset); | |
| 73 | 326 | size_t nl = copy_count_nl(blk->data + offset, buf, len); | |
| 74 | 326 | blk->nl += nl; | |
| 75 | 326 | blk->size = size; | |
| 76 | 326 | return nl; | |
| 77 | } | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Combine current block and new data into smaller blocks: | ||
| 81 | * | ||
| 82 | * • Block _must_ contain whole lines | ||
| 83 | * • Block _must_ contain at least one line | ||
| 84 | * • Preferred maximum size of block is BLOCK_EDIT_SIZE | ||
| 85 | * • Size of any block can be larger than BLOCK_EDIT_SIZE only if there's | ||
| 86 | * a very long line | ||
| 87 | */ | ||
| 88 | 2 | static size_t split_and_insert(BlockIter *cursor, const char *buf, size_t len) | |
| 89 | { | ||
| 90 | 2 | Block *blk = cursor->blk; | |
| 91 | 2 | ListHead *prev_node = blk->node.prev; | |
| 92 | 2 | const char *buf1 = blk->data; | |
| 93 | 2 | const char *buf2 = buf; | |
| 94 | 2 | const char *buf3 = blk->data + cursor->offset; | |
| 95 | 2 | size_t size1 = cursor->offset; | |
| 96 | 2 | size_t size2 = len; | |
| 97 | 2 | size_t size3 = blk->size - size1; | |
| 98 | 2 | size_t total = size1 + size2 + size3; | |
| 99 | 2 | size_t start = 0; // Beginning of new block | |
| 100 | 2 | size_t size = 0; // Size of new block | |
| 101 | 2 | size_t pos = 0; // Current position | |
| 102 | 2 | size_t nl_added = 0; | |
| 103 | |||
| 104 |
2/2✓ Branch 42 → 3 taken 28 times.
✓ Branch 42 → 43 taken 2 times.
|
30 | while (start < total) { |
| 105 | // Size of new block if next line would be added | ||
| 106 | 28 | size_t new_size = 0; | |
| 107 | 28 | size_t copied = 0; | |
| 108 | |||
| 109 |
2/2✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 6 taken 23 times.
|
28 | if (pos < size1) { |
| 110 | 5 | const char *nl = memchr(buf1 + pos, '\n', size1 - pos); | |
| 111 |
2/2✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 1 time.
|
5 | if (nl) { |
| 112 | 4 | new_size = nl - buf1 + 1 - start; | |
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 |
3/4✗ Branch 5 → 6 not taken.
✓ Branch 5 → 11 taken 4 times.
✓ Branch 6 → 7 taken 20 times.
✓ Branch 6 → 11 taken 4 times.
|
28 | if (!new_size && pos < size1 + size2) { |
| 117 | 20 | size_t offset = 0; | |
| 118 |
2/2✓ Branch 7 → 8 taken 18 times.
✓ Branch 7 → 9 taken 2 times.
|
20 | if (pos > size1) { |
| 119 | 18 | offset = pos - size1; | |
| 120 | } | ||
| 121 | |||
| 122 | 20 | const char *nl = memchr(buf2 + offset, '\n', size2 - offset); | |
| 123 |
1/2✓ Branch 9 → 10 taken 20 times.
✗ Branch 9 → 11 not taken.
|
20 | if (nl) { |
| 124 | 20 | new_size = size1 + nl - buf2 + 1 - start; | |
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 |
2/2✓ Branch 11 → 12 taken 4 times.
✓ Branch 11 → 17 taken 24 times.
|
28 | if (!new_size && pos < total) { |
| 129 | 4 | size_t offset = 0; | |
| 130 |
2/2✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 2 times.
|
4 | if (pos > size1 + size2) { |
| 131 | 2 | offset = pos - size1 - size2; | |
| 132 | } | ||
| 133 | |||
| 134 | 4 | const char *nl = memchr(buf3 + offset, '\n', size3 - offset); | |
| 135 |
1/2✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 16 not taken.
|
4 | if (nl) { |
| 136 | 4 | new_size = size1 + size2 + nl - buf3 + 1 - start; | |
| 137 | } else { | ||
| 138 | ✗ | new_size = total - start; | |
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 |
2/2✓ Branch 17 → 18 taken 25 times.
✓ Branch 17 → 20 taken 3 times.
|
28 | if (new_size <= BLOCK_EDIT_SIZE) { |
| 143 | // Fits | ||
| 144 | 25 | size = new_size; | |
| 145 | 25 | pos = start + new_size; | |
| 146 |
2/2✓ Branch 18 → 19 taken 23 times.
✓ Branch 18 → 22 taken 2 times.
|
25 | if (pos < total) { |
| 147 | 23 | continue; | |
| 148 | } | ||
| 149 | } else { | ||
| 150 | // Does not fit | ||
| 151 |
1/2✗ Branch 20 → 21 not taken.
✓ Branch 20 → 24 taken 3 times.
|
3 | if (!size) { |
| 152 | // One block containing one very long line | ||
| 153 | ✗ | size = new_size; | |
| 154 | ✗ | pos = start + new_size; | |
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | 2 | BUG_ON(!size); | |
| 159 | 5 | Block *new = block_new(size); | |
| 160 |
2/2✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 28 taken 4 times.
|
5 | if (start < size1) { |
| 161 | 1 | size_t avail = size1 - start; | |
| 162 | 1 | size_t count = MIN(size, avail); | |
| 163 | 1 | new->nl += copy_count_nl(new->data, buf1 + start, count); | |
| 164 | 1 | copied += count; | |
| 165 | 1 | start += count; | |
| 166 | } | ||
| 167 |
3/4✓ Branch 28 → 29 taken 5 times.
✗ Branch 28 → 32 not taken.
✓ Branch 29 → 30 taken 4 times.
✓ Branch 29 → 32 taken 1 time.
|
5 | if (start >= size1 && start < size1 + size2) { |
| 168 | 4 | size_t offset = start - size1; | |
| 169 | 4 | size_t avail = size2 - offset; | |
| 170 | 4 | size_t count = MIN(size - copied, avail); | |
| 171 | 4 | new->nl += copy_count_nl(new->data + copied, buf2 + offset, count); | |
| 172 | 4 | copied += count; | |
| 173 | 4 | start += count; | |
| 174 | } | ||
| 175 |
2/2✓ Branch 32 → 33 taken 3 times.
✓ Branch 32 → 37 taken 2 times.
|
5 | if (start >= size1 + size2) { |
| 176 | 3 | size_t offset = start - size1 - size2; | |
| 177 | 3 | size_t avail = size3 - offset; | |
| 178 | 3 | size_t count = size - copied; | |
| 179 | 3 | BUG_ON(count > avail); | |
| 180 | 3 | new->nl += copy_count_nl(new->data + copied, buf3 + offset, count); | |
| 181 | 3 | copied += count; | |
| 182 | 3 | start += count; | |
| 183 | } | ||
| 184 | |||
| 185 | 5 | new->size = size; | |
| 186 | 5 | BUG_ON(copied != size); | |
| 187 | 5 | list_insert_before(&new->node, &blk->node); | |
| 188 | |||
| 189 | 5 | nl_added += new->nl; | |
| 190 | 5 | size = 0; | |
| 191 | } | ||
| 192 | |||
| 193 | 2 | cursor->blk = BLOCK(prev_node->next); | |
| 194 |
1/2✗ Branch 45 → 44 not taken.
✓ Branch 45 → 46 taken 2 times.
|
2 | while (cursor->offset > cursor->blk->size) { |
| 195 | ✗ | cursor->offset -= cursor->blk->size; | |
| 196 | ✗ | cursor->blk = BLOCK(cursor->blk->node.next); | |
| 197 | } | ||
| 198 | |||
| 199 | 2 | nl_added -= blk->nl; | |
| 200 | 2 | block_free(blk); | |
| 201 | 2 | return nl_added; | |
| 202 | } | ||
| 203 | |||
| 204 | 328 | static size_t insert_bytes(BlockIter *cursor, const char *buf, size_t len) | |
| 205 | { | ||
| 206 | // Blocks must contain whole lines. | ||
| 207 | // Last char of buf might not be newline. | ||
| 208 | 328 | block_iter_normalize(cursor); | |
| 209 | |||
| 210 | 328 | Block *blk = cursor->blk; | |
| 211 | 328 | size_t new_size = blk->size + len; | |
| 212 |
4/4✓ Branch 3 → 4 taken 11 times.
✓ Branch 3 → 5 taken 317 times.
✓ Branch 4 → 5 taken 7 times.
✓ Branch 4 → 6 taken 4 times.
|
328 | if (new_size <= blk->alloc || new_size <= BLOCK_EDIT_SIZE) { |
| 213 | 324 | return insert_to_current(cursor, buf, len); | |
| 214 | } | ||
| 215 | |||
| 216 |
4/4✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 9 taken 1 time.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 1 time.
|
4 | if (blk->nl <= 1 && !memchr(buf, '\n', len)) { |
| 217 | // Can't split this possibly very long line. | ||
| 218 | // insert_to_current() is much faster than split_and_insert(). | ||
| 219 | 2 | return insert_to_current(cursor, buf, len); | |
| 220 | } | ||
| 221 | 2 | return split_and_insert(cursor, buf, len); | |
| 222 | } | ||
| 223 | |||
| 224 | 328 | void do_insert(View *view, const char *buf, size_t len) | |
| 225 | { | ||
| 226 | 328 | Buffer *buffer = view->buffer; | |
| 227 | 328 | size_t nl = insert_bytes(&view->cursor, buf, len); | |
| 228 | 328 | buffer->nl += nl; | |
| 229 | 328 | sanity_check_blocks(view, true); | |
| 230 | |||
| 231 | 328 | view_update_cursor_y(view); | |
| 232 |
2/2✓ Branch 5 → 6 taken 209 times.
✓ Branch 5 → 7 taken 119 times.
|
328 | buffer_mark_lines_changed(buffer, view->cy, nl ? LONG_MAX : view->cy); |
| 233 |
2/2✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 326 times.
|
328 | if (buffer->syntax) { |
| 234 | 2 | hl_insert(&buffer->line_start_states, view->cy, nl); | |
| 235 | } | ||
| 236 | 328 | } | |
| 237 | |||
| 238 | 19 | static bool only_block(const Buffer *buffer, const Block *blk) | |
| 239 | { | ||
| 240 |
2/4✓ Branch 2 → 3 taken 19 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 19 times.
|
19 | return blk->node.prev == &buffer->blocks && blk->node.next == &buffer->blocks; |
| 241 | } | ||
| 242 | |||
| 243 | 90 | char *do_delete(View *view, size_t len, bool sanity_check_newlines) | |
| 244 | { | ||
| 245 |
1/2✓ Branch 2 → 3 taken 90 times.
✗ Branch 2 → 34 not taken.
|
90 | if (len == 0) { |
| 246 | return NULL; | ||
| 247 | } | ||
| 248 | |||
| 249 | 90 | ListHead *saved_prev_node = NULL; | |
| 250 | 90 | Block *blk = view->cursor.blk; | |
| 251 | 90 | size_t offset = view->cursor.offset; | |
| 252 |
2/2✓ Branch 3 → 4 taken 39 times.
✓ Branch 3 → 5 taken 51 times.
|
90 | if (!offset) { |
| 253 | // The block where the cursor is can become empty and thus | ||
| 254 | // may be deleted | ||
| 255 | 39 | saved_prev_node = blk->node.prev; | |
| 256 | } | ||
| 257 | |||
| 258 | 90 | Buffer *buffer = view->buffer; | |
| 259 | 90 | char *deleted = xmalloc(len); | |
| 260 | 90 | size_t pos = 0; | |
| 261 | 90 | size_t deleted_nl = 0; | |
| 262 | |||
| 263 | 90 | while (pos < len) { | |
| 264 | 90 | ListHead *next = blk->node.next; | |
| 265 | 90 | size_t avail = blk->size - offset; | |
| 266 | 90 | size_t count = MIN(len - pos, avail); | |
| 267 | 90 | char *ptr = blk->data + offset; | |
| 268 | 90 | size_t nl = copy_count_nl(deleted + pos, ptr, count); | |
| 269 |
2/2✓ Branch 8 → 9 taken 63 times.
✓ Branch 8 → 10 taken 27 times.
|
90 | if (count < avail) { |
| 270 | 63 | memmove(ptr, ptr + count, avail - count); | |
| 271 | } | ||
| 272 | |||
| 273 | 90 | deleted_nl += nl; | |
| 274 | 90 | buffer->nl -= nl; | |
| 275 | 90 | blk->nl -= nl; | |
| 276 | 90 | blk->size -= count; | |
| 277 |
3/4✓ Branch 10 → 11 taken 19 times.
✓ Branch 10 → 13 taken 71 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 19 times.
|
90 | if (!blk->size && !only_block(buffer, blk)) { |
| 278 | ✗ | block_free(blk); | |
| 279 | } | ||
| 280 | |||
| 281 | 90 | offset = 0; | |
| 282 | 90 | pos += count; | |
| 283 | 90 | blk = BLOCK(next); | |
| 284 | 270 | BUG_ON(pos < len && next == &buffer->blocks); | |
| 285 | } | ||
| 286 | |||
| 287 |
2/2✓ Branch 18 → 19 taken 39 times.
✓ Branch 18 → 22 taken 51 times.
|
90 | if (saved_prev_node) { |
| 288 | // Cursor was at beginning of a block that was possibly deleted | ||
| 289 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 39 times.
|
39 | if (saved_prev_node->next == &buffer->blocks) { |
| 290 | ✗ | view->cursor.blk = BLOCK(saved_prev_node); | |
| 291 | ✗ | view->cursor.offset = view->cursor.blk->size; | |
| 292 | } else { | ||
| 293 | 39 | view->cursor.blk = BLOCK(saved_prev_node->next); | |
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | 90 | blk = view->cursor.blk; | |
| 298 | |||
| 299 | 90 | if ( | |
| 300 |
2/2✓ Branch 22 → 23 taken 71 times.
✓ Branch 22 → 27 taken 19 times.
|
90 | blk->size |
| 301 |
1/2✗ Branch 23 → 24 not taken.
✓ Branch 23 → 27 taken 71 times.
|
71 | && blk->data[blk->size - 1] != '\n' |
| 302 | ✗ | && blk->node.next != &buffer->blocks | |
| 303 | ) { | ||
| 304 | ✗ | Block *next = BLOCK(blk->node.next); | |
| 305 | ✗ | size_t size = blk->size + next->size; | |
| 306 | ✗ | block_grow(blk, size); | |
| 307 | ✗ | memcpy(blk->data + blk->size, next->data, next->size); | |
| 308 | ✗ | blk->size = size; | |
| 309 | ✗ | blk->nl += next->nl; | |
| 310 | ✗ | block_free(next); | |
| 311 | } | ||
| 312 | |||
| 313 | 90 | sanity_check_blocks(view, sanity_check_newlines); | |
| 314 | |||
| 315 | 90 | view_update_cursor_y(view); | |
| 316 |
2/2✓ Branch 29 → 30 taken 51 times.
✓ Branch 29 → 31 taken 39 times.
|
90 | buffer_mark_lines_changed(buffer, view->cy, deleted_nl ? LONG_MAX : view->cy); |
| 317 | |||
| 318 |
1/2✗ Branch 32 → 33 not taken.
✓ Branch 32 → 34 taken 90 times.
|
90 | if (buffer->syntax) { |
| 319 | ✗ | hl_delete(&buffer->line_start_states, view->cy, deleted_nl); | |
| 320 | } | ||
| 321 | |||
| 322 | return deleted; | ||
| 323 | } | ||
| 324 | |||
| 325 | 46 | char *do_replace(View *view, size_t del, const char *buf, size_t ins) | |
| 326 | { | ||
| 327 | 46 | BUG_ON(del == 0); | |
| 328 | 46 | BUG_ON(ins == 0); | |
| 329 | 46 | block_iter_normalize(&view->cursor); | |
| 330 | |||
| 331 | 46 | Block *blk = view->cursor.blk; | |
| 332 | 46 | size_t offset = view->cursor.offset; | |
| 333 | 46 | size_t avail = blk->size - offset; | |
| 334 |
2/2✓ Branch 7 → 8 taken 5 times.
✓ Branch 7 → 9 taken 41 times.
|
46 | if (del >= avail) { |
| 335 | 5 | goto slow; | |
| 336 | } | ||
| 337 | |||
| 338 | 41 | size_t new_size = blk->size + ins - del; | |
| 339 |
1/2✗ Branch 9 → 10 not taken.
✓ Branch 9 → 13 taken 41 times.
|
41 | if (new_size > BLOCK_EDIT_SIZE) { |
| 340 | // Should split | ||
| 341 | ✗ | if (blk->nl > 1 || memchr(buf, '\n', ins)) { | |
| 342 | // Most likely can be split | ||
| 343 | ✗ | goto slow; | |
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | 41 | block_grow(blk, new_size); | |
| 348 | |||
| 349 | // Modification is limited to one block | ||
| 350 | 41 | Buffer *buffer = view->buffer; | |
| 351 | 41 | char *ptr = blk->data + offset; | |
| 352 | 41 | char *deleted = xmalloc(del); | |
| 353 | 41 | size_t del_nl = copy_count_nl(deleted, ptr, del); | |
| 354 | 41 | blk->nl -= del_nl; | |
| 355 | 41 | buffer->nl -= del_nl; | |
| 356 | |||
| 357 |
2/2✓ Branch 16 → 17 taken 28 times.
✓ Branch 16 → 18 taken 13 times.
|
41 | if (del != ins) { |
| 358 | 28 | memmove(ptr + ins, ptr + del, avail - del); | |
| 359 | } | ||
| 360 | |||
| 361 | 41 | size_t ins_nl = copy_count_nl(ptr, buf, ins); | |
| 362 | 41 | blk->nl += ins_nl; | |
| 363 | 41 | buffer->nl += ins_nl; | |
| 364 | 41 | blk->size = new_size; | |
| 365 | 41 | sanity_check_blocks(view, true); | |
| 366 | 41 | view_update_cursor_y(view); | |
| 367 | |||
| 368 | // If the number of inserted and removed bytes are the same, some | ||
| 369 | // line(s) changed but the lines after them didn't move up or down | ||
| 370 |
2/2✓ Branch 21 → 22 taken 27 times.
✓ Branch 21 → 23 taken 14 times.
|
41 | long max = (del_nl == ins_nl) ? view->cy + del_nl : LONG_MAX; |
| 371 | 41 | buffer_mark_lines_changed(buffer, view->cy, max); | |
| 372 | |||
| 373 |
1/2✗ Branch 24 → 25 not taken.
✓ Branch 24 → 32 taken 41 times.
|
41 | if (buffer->syntax) { |
| 374 | ✗ | hl_delete(&buffer->line_start_states, view->cy, del_nl); | |
| 375 | ✗ | hl_insert(&buffer->line_start_states, view->cy, ins_nl); | |
| 376 | } | ||
| 377 | |||
| 378 | return deleted; | ||
| 379 | |||
| 380 | 5 | slow: | |
| 381 | // The "sanity_check_newlines" argument of do_delete() is false here | ||
| 382 | // because it may be removing a terminating newline that do_insert() | ||
| 383 | // is going to insert again at a different position: | ||
| 384 | 5 | deleted = do_delete(view, del, false); | |
| 385 | 5 | BUG_ON(!deleted); // do_delete() only returns NULL if len is 0 | |
| 386 | 5 | do_insert(view, buf, ins); | |
| 387 | 5 | return deleted; | |
| 388 | } | ||
| 389 |