aboutsummaryrefslogtreecommitdiff
path: root/src/api/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/api/buffer.c')
-rw-r--r--src/api/buffer.c210
1 files changed, 200 insertions, 10 deletions
diff --git a/src/api/buffer.c b/src/api/buffer.c
index 743d8c4729..554272955e 100644
--- a/src/api/buffer.c
+++ b/src/api/buffer.c
@@ -2,7 +2,40 @@
#include <stdlib.h>
#include "api/buffer.h"
+#include "api/helpers.h"
#include "api/defs.h"
+#include "../vim.h"
+#include "../buffer.h"
+#include "memline.h"
+#include "memory.h"
+#include "misc1.h"
+#include "misc2.h"
+#include "move.h"
+#include "../window.h"
+#include "undo.h"
+
+static buf_T *find_buffer(Buffer buffer, Error *err);
+
+// Find a window that contains "buf" and switch to it.
+// If there is no such window, use the current window and change "curbuf".
+// Caller must initialize save_curbuf to NULL.
+// restore_win_for_buf() MUST be called later!
+static void switch_to_win_for_buf(buf_T *buf,
+ win_T **save_curwinp,
+ tabpage_T **save_curtabp,
+ buf_T **save_curbufp);
+
+static void restore_win_for_buf(win_T *save_curwin,
+ tabpage_T *save_curtab,
+ buf_T *save_curbuf);
+
+// Check if deleting lines made the cursor position invalid.
+// Changed the lines from "lo" to "hi" and added "extra" lines (negative if
+// deleted).
+static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra);
+
+// Normalizes 0-based indexes to buffer line numbers
+static int64_t normalize_index(buf_T *buf, int64_t index);
int64_t buffer_get_length(Buffer buffer, Error *err)
{
@@ -11,27 +44,116 @@ int64_t buffer_get_length(Buffer buffer, Error *err)
String buffer_get_line(Buffer buffer, int64_t index, Error *err)
{
- abort();
+ String rv;
+ buf_T *buf = find_buffer(buffer, err);
+
+ if (!buf) {
+ return rv;
+ }
+
+ index = normalize_index(buf, index);
+ char *line = (char *)ml_get_buf(buf, index, false);
+ rv.size = strlen(line);
+ rv.data = xmalloc(rv.size);
+ memcpy(rv.data, line, rv.size);
+ return rv;
}
-void buffer_set_line(Buffer buffer, int64_t index, String line, Error *err)
+void buffer_set_line(Buffer buffer, int64_t index, Object line, Error *err)
{
- abort();
+ buf_T *buf = find_buffer(buffer, err);
+
+ if (!buf) {
+ return;
+ }
+
+ if (line.type != kObjectTypeNil && line.type != kObjectTypeString) {
+ char msg[] = "Invalid line";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ return;
+ }
+
+ index = normalize_index(buf, index);
+ buf_T *save_curbuf = NULL;
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+ try_start();
+ switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf);
+
+ if (line.type == kObjectTypeNil) {
+ // Delete the line
+
+ if (u_savedel(index, 1L) == FAIL) {
+ // Failed to save undo
+ char msg[] = "Cannot save undo information";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ } else if (ml_delete(index, FALSE) == FAIL) {
+ // Failed to delete
+ char msg[] = "Cannot delete the line";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ } else {
+ restore_win_for_buf(save_curwin, save_curtab, save_curbuf);
+ // Success
+ if (buf == curbuf) {
+ // fix the cursor if it's the current buffer
+ fix_cursor(index, index + 1, -1);
+ }
+
+ if (save_curbuf == NULL) {
+ // Only adjust marks if we managed to switch to a window that
+ // holds the buffer, otherwise line numbers will be invalid.
+ deleted_lines_mark(index, 1L);
+ }
+ }
+
+ } else if (line.type == kObjectTypeString) {
+ // Replace line
+ char *string = xmalloc(line.data.string.size + 1);
+ memcpy(string, line.data.string.data, line.data.string.size);
+ string[line.data.string.size] = NUL;
+
+ if (u_savesub(index) == FAIL) {
+ // Failed to save undo
+ char msg[] = "Cannot save undo information";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ } else if (ml_replace(index, (char_u *)string, FALSE) == FAIL) {
+ // Failed to replace
+ char msg[] = "Cannot replace line";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ free(string);
+ } else {
+ // Success
+ changed_bytes(index, 0);
+ restore_win_for_buf(save_curwin, save_curtab, save_curbuf);
+
+ // Check that the cursor is not beyond the end of the line now.
+ if (buf == curbuf) {
+ check_cursor_col();
+ }
+ }
+ }
+
+ try_end(err);
}
StringArray buffer_get_slice(Buffer buffer,
- int64_t start,
- int64_t end,
- Error *err)
+ int64_t start,
+ int64_t end,
+ Error *err)
{
abort();
}
void buffer_set_slice(Buffer buffer,
- int64_t start,
- int64_t end,
- StringArray lines,
- Error *err)
+ int64_t start,
+ int64_t end,
+ StringArray lines,
+ Error *err)
{
abort();
}
@@ -85,3 +207,71 @@ Position buffer_mark(Buffer buffer, String name, Error *err)
{
abort();
}
+
+static buf_T *find_buffer(Buffer buffer, Error *err)
+{
+ buf_T *buf = buflist_findnr(buffer);
+
+ if (buf == NULL) {
+ char msg[] = "Invalid buffer id";
+ strncpy(err->msg, msg, sizeof(err->msg));
+ err->set = true;
+ }
+
+ return buf;
+}
+
+static void switch_to_win_for_buf(buf_T *buf,
+ win_T **save_curwinp,
+ tabpage_T **save_curtabp,
+ buf_T **save_curbufp)
+{
+ win_T *wp;
+ tabpage_T *tp;
+
+ if (find_win_for_buf(buf, &wp, &tp) == FAIL
+ || switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL)
+ switch_buffer(save_curbufp, buf);
+}
+
+static void restore_win_for_buf(win_T *save_curwin,
+ tabpage_T *save_curtab,
+ buf_T *save_curbuf)
+{
+ if (save_curbuf == NULL) {
+ restore_win(save_curwin, save_curtab, TRUE);
+ } else {
+ restore_buffer(save_curbuf);
+ }
+}
+
+static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
+{
+ if (curwin->w_cursor.lnum >= lo) {
+ // Adjust the cursor position if it's in/after the changed
+ // lines.
+ if (curwin->w_cursor.lnum >= hi) {
+ curwin->w_cursor.lnum += extra;
+ check_cursor_col();
+ }
+ else if (extra < 0) {
+ curwin->w_cursor.lnum = lo;
+ check_cursor();
+ } else {
+ check_cursor_col();
+ }
+ changed_cline_bef_curs();
+ }
+ invalidate_botline();
+}
+
+static int64_t normalize_index(buf_T *buf, int64_t index)
+{
+ // Fix if < 0
+ index = index < 0 ? buf->b_ml.ml_line_count + index : index;
+ // Convert the index to a vim line number
+ index++;
+ // Fix if > line_count
+ index = index > buf->b_ml.ml_line_count ? buf->b_ml.ml_line_count : index;
+ return index;
+}