int delete_one_line(buffer * const b, line_desc * const ld, const int64_t line) { assert_line_desc(ld, b->encoding); assert_buffer(b); block_signals(); if (ld->line_len && (b->last_deleted = reset_stream(b->last_deleted))) add_to_stream(b->last_deleted, ld->line, ld->line_len); /* We delete a line by delete_stream()ing its length plus one. However, if we are on the last line of text, there is no terminating line feed. */ const int error = delete_stream(b, ld, line, 0, ld->line_len + (ld->ld_node.next->next ? 1 : 0)); release_signals(); return error; }
int auto_indent_line(buffer * const b, const int64_t line, line_desc * const ld, const int64_t up_to_col) { line_desc * const prev_ld = (line_desc *)ld->ld_node.prev; if (!prev_ld->ld_node.prev || prev_ld->line_len == 0) return 0; assert_line_desc(prev_ld, b->encoding); int c; int64_t pos = 0; for(int64_t col = 0; pos < prev_ld->line_len && ne_isspace(c = get_char(&prev_ld->line[pos], b->encoding), b->encoding); ) { col += (c == '\t' ? b->opt.tab_size - col % b->opt.tab_size : 1); if (col > up_to_col) break; pos = next_pos(prev_ld->line, pos, b->encoding); } if (pos) insert_stream(b, ld, line, 0, prev_ld->line, pos); return pos; }
int insert_stream(buffer * const b, line_desc * ld, int64_t line, int64_t pos, const char * const stream, const int64_t stream_len) { if (!b || !ld || !stream || stream_len < 1 || pos > ld->line_len) return ERROR; assert_line_desc(ld, b->encoding); assert_buffer(b); block_signals(); if (b->opt.do_undo && !(b->undoing || b->redoing)) { const int error = add_undo_step(b, line, pos, -stream_len); if (error) { release_signals(); return error; } } const char *s = stream; while(s - stream < stream_len) { int64_t const len = strnlen_ne(s, stream_len - (s - stream)); if (len) { /* First case; there is no character allocated on this line. We have to freshly allocate the line. */ if (!ld->line) { if (ld->line = alloc_chars(b, len)) { memcpy(ld->line, s, len); ld->line_len = len; } else { release_signals(); return OUT_OF_MEMORY; } } /* Second case. There are not enough characters around ld->line. Note that the value of the check_first_before parameter depends on the position at which the insertion will be done, and it is chosen in such a way to minimize the number of characters to move. */ else { const int64_t result = alloc_chars_around(b, ld, len, pos < ld->line_len / 2); if (result < 0) { char * const p = alloc_chars(b, ld->line_len + len); if (p) { memcpy(p, ld->line, pos); memcpy(&p[pos], s, len); memcpy(&p[pos + len], ld->line + pos, ld->line_len - pos); free_chars(b, ld->line, ld->line_len); ld->line = p; ld->line_len += len; } else { release_signals(); return OUT_OF_MEMORY; } } else { /* Third case. There are enough free characters around ld->line. */ if (len - result) memmove(ld->line - (len - result), ld->line, pos); if (result) memmove(ld->line + pos + result, ld->line + pos, ld->line_len - pos); memcpy(ld->line - (len - result) + pos, s, len); ld->line -= (len - result); ld->line_len += len; } } b->is_modified = 1; /* We just inserted len chars at (line,pos); adjust bookmarks and mark accordingly. */ if (b->marking && b->block_start_line == line && b->block_start_pos > pos) b->block_start_pos += len; for (int i = 0, mask = b->bookmark_mask; mask; i++, mask >>= 1) if ((mask & 1) && b->bookmark[i].line == line && b->bookmark[i].pos > pos) b->bookmark[i].pos += len; } /* If the string we have inserted has a NULL at the end, we create a new line under the current one and set ld to point to it. */ if (len + (s - stream) < stream_len) { line_desc *new_ld; if (new_ld = alloc_line_desc(b)) { add(&new_ld->ld_node, &ld->ld_node); b->num_lines++; if (pos + len < ld->line_len) { new_ld->line_len = ld->line_len - pos - len; new_ld->line = &ld->line[pos + len]; ld->line_len = pos + len; if (pos + len == 0) ld->line = NULL; } b->is_modified = 1; ld = new_ld; /* We just inserted a line break at (line,pos); adjust the buffer bookmarks and mark accordingly. */ if (b->marking) { if (b->block_start_line == line && b->block_start_pos > pos) { b->block_start_pos -= pos; b->block_start_line++; } else if (b->block_start_line > line) b->block_start_line++; } for (int i = 0, mask=b->bookmark_mask; mask; i++, mask >>= 1) { if (mask & 1) { if (b->bookmark[i].line == line && b->bookmark[i].pos > pos) { b->bookmark[i].pos -= pos; b->bookmark[i].line++; } else if (b->bookmark[i].line > line) b->bookmark[i].line++; } } pos = 0; line++; } else {