diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/api/buffer.c | 151 | ||||
-rw-r--r-- | src/api/buffer.h | 17 |
2 files changed, 155 insertions, 13 deletions
diff --git a/src/api/buffer.c b/src/api/buffer.c index cb82714a34..14b7766c52 100644 --- a/src/api/buffer.c +++ b/src/api/buffer.c @@ -1,3 +1,5 @@ +// Much of this code was adapted from 'if_py_both.h' from the original +// vim source #include <stdint.h> #include <stdlib.h> @@ -10,6 +12,7 @@ #include "memory.h" #include "misc1.h" #include "misc2.h" +#include "mark.h" #include "move.h" #include "../window.h" #include "undo.h" @@ -136,20 +139,150 @@ void buffer_set_line(Buffer buffer, int64_t index, Object line, Error *err) } StringArray buffer_get_slice(Buffer buffer, - int64_t start, - int64_t end, - Error *err) + int64_t start, + int64_t end, + bool include_start, + bool include_end, + Error *err) { - abort(); + StringArray rv = {.size = 0}; + buf_T *buf = find_buffer(buffer, err); + + if (!buf) { + return rv; + } + + start = normalize_index(buf, start) + (include_start ? 0 : 1); + end = normalize_index(buf, end) + (include_end ? 1 : 0); + + if (start >= end) { + // Return 0-length array + return rv; + } + + rv.size = end - start; + rv.items = xmalloc(sizeof(String) * rv.size); + + for (uint32_t i = 0; i < rv.size; i++) { + rv.items[i].data = xstrdup((char *)ml_get_buf(buf, start + i, FALSE)); + rv.items[i].size = strlen(rv.items[i].data); + } + + return rv; } void buffer_set_slice(Buffer buffer, - int64_t start, - int64_t end, - StringArray lines, - Error *err) + int64_t start, + int64_t end, + bool include_start, + bool include_end, + StringArray replacement, + Error *err) { - abort(); + buf_T *buf = find_buffer(buffer, err); + + if (!buf) { + return; + } + + start = normalize_index(buf, start) + (include_start ? 0 : 1); + end = normalize_index(buf, end) + (include_end ? 1 : 0); + + if (start > end) { + set_api_error("start > end", err); + return; + } + + buf_T *save_curbuf = NULL; + win_T *save_curwin = NULL; + tabpage_T *save_curtab = NULL; + uint32_t new_len = replacement.size; + uint32_t old_len = end - start; + uint32_t i; + int32_t extra = 0; // lines added to text, can be negative + char **lines; + + if (new_len == 0) { + // avoid allocating zero bytes + lines = NULL; + } else { + lines = xcalloc(sizeof(char *), new_len); + } + + for (i = 0; i < new_len; i++) { + String l = replacement.items[i]; + lines[i] = xstrndup(l.data, l.size); + } + + try_start(); + switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + + if (u_save(start - 1, end) == FAIL) { + set_api_error("Cannot save undo information", err); + goto cleanup; + } + + // If the size of the range is reducing (ie, new_len < old_len) we + // need to delete some old_len. We do this at the start, by + // repeatedly deleting line "start". + for (i = 0; new_len < old_len && i < old_len - new_len; i++) { + if (ml_delete(start, false) == FAIL) { + set_api_error("Cannot delete line", err); + goto cleanup; + } + } + + extra -= i; + + // For as long as possible, replace the existing old_len with the + // new old_len. This is a more efficient operation, as it requires + // less memory allocation and freeing. + for (i = 0; i < old_len && i < new_len; i++) { + if (ml_replace(start + i, (char_u *)lines[i], false) == FAIL) { + set_api_error("Cannot replace line", err); + goto cleanup; + } + // Mark lines that haven't been passed to the buffer as they need + // to be freed later + lines[i] = NULL; + } + + // Now we may need to insert the remaining new old_len + while (i < new_len) { + if (ml_append(start + i - 1, (char_u *)lines[i], 0, false) == FAIL) { + set_api_error("Cannot insert line", err); + goto cleanup; + } + // Same as with replacing + lines[i] = NULL; + i++; + extra++; + } + + // Adjust marks. Invalidate any which lie in the + // changed range, and move any in the remainder of the buffer. + // Only adjust marks if we managed to switch to a window that holds + // the buffer, otherwise line numbers will be invalid. + if (save_curbuf == NULL) { + mark_adjust(start, end - 1, MAXLNUM, extra); + } + + changed_lines(start, 0, end, extra); + + if (buf == curbuf) { + fix_cursor(start, end, extra); + } + +cleanup: + for (uint32_t i = 0; i < new_len; i++) { + if (lines[i] != NULL) { + free(lines[i]); + } + } + + free(lines); + restore_win_for_buf(save_curwin, save_curtab, save_curbuf); + try_end(err); } Object buffer_get_var(Buffer buffer, String name, Error *err) diff --git a/src/api/buffer.h b/src/api/buffer.h index 3459ce8e45..49379e3bc9 100644 --- a/src/api/buffer.h +++ b/src/api/buffer.h @@ -34,25 +34,34 @@ void buffer_set_line(Buffer buffer, int64_t index, Object line, Error *err); /// /// @param buffer The buffer handle /// @param start The first line index -/// @param end The last line index(exclusive) +/// @param end The last line index +/// @param include_start True if the slice includes the `start` parameter +/// @param include_end True if the slice includes the `end` parameter /// @param[out] err Details of an error that may have occurred /// @return An array of lines StringArray buffer_get_slice(Buffer buffer, int64_t start, int64_t end, + bool include_start, + bool include_end, Error *err); /// Replaces a line range on the buffer /// /// @param buffer The buffer handle /// @param start The first line index -/// @param end The last line index(exclusive) -/// @param lines An array of lines to use as replacement +/// @param end The last line index +/// @param include_start True if the slice includes the `start` parameter +/// @param include_end True if the slice includes the `end` parameter +/// @param lines An array of lines to use as replacement(A 0-length array +/// will simply delete the line range) /// @param[out] err Details of an error that may have occurred void buffer_set_slice(Buffer buffer, int64_t start, int64_t end, - StringArray lines, + bool include_start, + bool include_end, + StringArray replacement, Error *err); /// Gets a buffer variable |