aboutsummaryrefslogtreecommitdiff
path: root/src/api/buffer.c
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-05-10 18:32:33 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-05-13 14:11:22 -0300
commit4dc34bc0e052320feebdc3a9aed0df1d3e8af181 (patch)
tree4f20fe4293ea473d61b1a71c3845a9743e56b27c /src/api/buffer.c
parent417a61f54f6ca9b05454bae4c5dc6c2c8ff2d6af (diff)
downloadrneovim-4dc34bc0e052320feebdc3a9aed0df1d3e8af181.tar.gz
rneovim-4dc34bc0e052320feebdc3a9aed0df1d3e8af181.tar.bz2
rneovim-4dc34bc0e052320feebdc3a9aed0df1d3e8af181.zip
API: Implement buffer_{get,set}_slice
Diffstat (limited to 'src/api/buffer.c')
-rw-r--r--src/api/buffer.c151
1 files changed, 142 insertions, 9 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)