aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/buffer.c76
-rw-r--r--src/nvim/api/private/dispatch.c2
-rw-r--r--src/nvim/api/private/helpers.c38
-rw-r--r--src/nvim/api/vim.c6
4 files changed, 104 insertions, 18 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index fa4ad27e60..e1fe7617ff 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -25,6 +25,7 @@
#include "nvim/window.h"
#include "nvim/undo.h"
#include "nvim/ex_docmd.h"
+#include "nvim/buffer_updates.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/buffer.c.generated.h"
@@ -75,6 +76,59 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
return rv;
}
+/// Activate updates from this buffer to the current channel.
+///
+/// @param buffer The buffer handle
+/// @param send_buffer Set to true if the initial notification should contain
+/// the whole buffer. If so, the first notification will be a
+/// `nvim_buf_lines_event`. Otherwise, the first notification will be
+/// a `nvim_buf_changedtick_event`
+/// @param opts Optional parameters. Currently not used.
+/// @param[out] err Details of an error that may have occurred
+/// @return False when updates couldn't be enabled because the buffer isn't
+/// loaded or `opts` contained an invalid key; otherwise True.
+Boolean nvim_buf_attach(uint64_t channel_id,
+ Buffer buffer,
+ Boolean send_buffer,
+ Dictionary opts,
+ Error *err)
+ FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
+{
+ if (opts.size > 0) {
+ api_set_error(err, kErrorTypeValidation, "dict isn't empty");
+ return false;
+ }
+
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (!buf) {
+ return false;
+ }
+
+ return buf_updates_register(buf, channel_id, send_buffer);
+}
+//
+/// Deactivate updates from this buffer to the current channel.
+///
+/// @param buffer The buffer handle
+/// @param[out] err Details of an error that may have occurred
+/// @return False when updates couldn't be disabled because the buffer
+/// isn't loaded; otherwise True.
+Boolean nvim_buf_detach(uint64_t channel_id,
+ Buffer buffer,
+ Error *err)
+ FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (!buf) {
+ return false;
+ }
+
+ buf_updates_unregister(buf, channel_id);
+ return true;
+}
+
/// Sets a buffer line
///
/// @deprecated use nvim_buf_set_lines instead.
@@ -184,23 +238,9 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
rv.size = (size_t)(end - start);
rv.items = xcalloc(sizeof(Object), rv.size);
- for (size_t i = 0; i < rv.size; i++) {
- int64_t lnum = start + (int64_t)i;
-
- if (lnum >= MAXLNUM) {
- api_set_error(err, kErrorTypeValidation, "Line index is too high");
- goto end;
- }
-
- const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false);
- Object str = STRING_OBJ(cstr_to_string(bufstr));
-
- // Vim represents NULs as NLs, but this may confuse clients.
- if (channel_id != VIML_INTERNAL_CALL) {
- strchrsub(str.data.string.data, '\n', '\0');
- }
-
- rv.items[i] = str;
+ if (!buf_collect_lines(buf, rv.size, start,
+ (channel_id != VIML_INTERNAL_CALL), &rv, err)) {
+ goto end;
}
end:
@@ -407,7 +447,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
false);
}
- changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra);
+ changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true);
if (save_curbuf.br_buf == NULL) {
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
index f8eebcdb10..5207a57b88 100644
--- a/src/nvim/api/private/dispatch.c
+++ b/src/nvim/api/private/dispatch.c
@@ -29,6 +29,8 @@ static void msgpack_rpc_add_method_handler(String method,
map_put(String, MsgpackRpcRequestHandler)(methods, method, handler);
}
+/// @param name API method name
+/// @param name_len name size (includes terminating NUL)
MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
size_t name_len)
{
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 692a0b51fd..f3e883de02 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -16,6 +16,7 @@
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/window.h"
+#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
@@ -742,6 +743,43 @@ String cstr_as_string(char *str) FUNC_ATTR_PURE
return (String){ .data = str, .size = strlen(str) };
}
+/// Collects `n` buffer lines into array `l`, optionally replacing newlines
+/// with NUL.
+///
+/// @param buf Buffer to get lines from
+/// @param n Number of lines to collect
+/// @param replace_nl Replace newlines ("\n") with NUL
+/// @param start Line number to start from
+/// @param[out] l Lines are copied here
+/// @param err[out] Error, if any
+/// @return true unless `err` was set
+bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl,
+ Array *l, Error *err)
+{
+ for (size_t i = 0; i < n; i++) {
+ int64_t lnum = start + (int64_t)i;
+
+ if (lnum >= MAXLNUM) {
+ if (err != NULL) {
+ api_set_error(err, kErrorTypeValidation, "Line index is too high");
+ }
+ return false;
+ }
+
+ const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false);
+ Object str = STRING_OBJ(cstr_to_string(bufstr));
+
+ if (replace_nl) {
+ // Vim represents NULs as NLs, but this may confuse clients.
+ strchrsub(str.data.string.data, '\n', '\0');
+ }
+
+ l->items[i] = str;
+ }
+
+ return true;
+}
+
/// Converts from type Object to a VimL value.
///
/// @param obj Object to convert from.
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b73ecc2d03..b3ae52602b 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -16,6 +16,7 @@
#include "nvim/api/private/dispatch.h"
#include "nvim/api/buffer.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/lua/executor.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
@@ -1163,6 +1164,11 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
MsgpackRpcRequestHandler handler = msgpack_rpc_get_handler_for(name.data,
name.size);
+ if (handler.fn == msgpack_rpc_handle_missing_method) {
+ api_set_error(&nested_error, kErrorTypeException, "Invalid method: %s",
+ name.size > 0 ? name.data : "<empty>");
+ break;
+ }
Object result = handler.fn(channel_id, args, &nested_error);
if (ERROR_SET(&nested_error)) {
// error handled after loop