aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
committerJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
commitd5f194ce780c95821a855aca3c19426576d28ae0 (patch)
treed45f461b19f9118ad2bb1f440a7a08973ad18832 /src/nvim/api
parentc5d770d311841ea5230426cc4c868e8db27300a8 (diff)
parent44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff)
downloadrneovim-rahm.tar.gz
rneovim-rahm.tar.bz2
rneovim-rahm.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309HEADrahm
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/autocmd.c104
-rw-r--r--src/nvim/api/buffer.c351
-rw-r--r--src/nvim/api/command.c8
-rw-r--r--src/nvim/api/deprecated.c223
-rw-r--r--src/nvim/api/extmark.c157
-rw-r--r--src/nvim/api/extmark.h1
-rw-r--r--src/nvim/api/keysets_defs.h114
-rw-r--r--src/nvim/api/options.c60
-rw-r--r--src/nvim/api/private/converter.c3
-rw-r--r--src/nvim/api/private/defs.h2
-rw-r--r--src/nvim/api/private/helpers.c89
-rw-r--r--src/nvim/api/private/helpers.h16
-rw-r--r--src/nvim/api/tabpage.c13
-rw-r--r--src/nvim/api/ui.c4
-rw-r--r--src/nvim/api/ui.h1
-rw-r--r--src/nvim/api/ui_events.in.h6
-rw-r--r--src/nvim/api/vim.c416
-rw-r--r--src/nvim/api/vimscript.c70
-rw-r--r--src/nvim/api/win_config.c35
-rw-r--r--src/nvim/api/window.c77
20 files changed, 900 insertions, 850 deletions
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 22932fd1a2..d436dbb7f1 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -2,7 +2,6 @@
#include <lauxlib.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -23,6 +22,7 @@
#include "nvim/globals.h"
#include "nvim/lua/executor.h"
#include "nvim/memory.h"
+#include "nvim/memory_defs.h"
#include "nvim/strings.h"
#include "nvim/types_defs.h"
#include "nvim/vim_defs.h"
@@ -68,32 +68,31 @@ static int64_t next_autocmd_id = 1;
/// match any combination of them.
///
/// @param opts Dict with at least one of the following:
-/// - group (string|integer): the autocommand group name or id to match against.
-/// - event (string|array): event or events to match against |autocmd-events|.
-/// - pattern (string|array): pattern or patterns to match against |autocmd-pattern|.
-/// Cannot be used with {buffer}
-/// - buffer: Buffer number or list of buffer numbers for buffer local autocommands
+/// - buffer: (integer) Buffer number or list of buffer numbers for buffer local autocommands
/// |autocmd-buflocal|. Cannot be used with {pattern}
+/// - event: (string|table) event or events to match against |autocmd-events|.
+/// - id: (integer) Autocommand ID to match.
+/// - group: (string|table) the autocommand group name or id to match against.
+/// - pattern: (string|table) pattern or patterns to match against |autocmd-pattern|.
+/// Cannot be used with {buffer}
/// @return Array of autocommands matching the criteria, with each item
/// containing the following fields:
-/// - id (number): the autocommand id (only when defined with the API).
-/// - group (integer): the autocommand group id.
-/// - group_name (string): the autocommand group name.
-/// - desc (string): the autocommand description.
-/// - event (string): the autocommand event.
-/// - command (string): the autocommand command. Note: this will be empty if a callback is set.
-/// - callback (function|string|nil): Lua function or name of a Vim script function
+/// - buffer: (integer) the buffer number.
+/// - buflocal: (boolean) true if the autocommand is buffer local.
+/// - command: (string) the autocommand command. Note: this will be empty if a callback is set.
+/// - callback: (function|string|nil): Lua function or name of a Vim script function
/// which is executed when this autocommand is triggered.
-/// - once (boolean): whether the autocommand is only run once.
-/// - pattern (string): the autocommand pattern.
+/// - desc: (string) the autocommand description.
+/// - event: (string) the autocommand event.
+/// - id: (integer) the autocommand id (only when defined with the API).
+/// - group: (integer) the autocommand group id.
+/// - group_name: (string) the autocommand group name.
+/// - once: (boolean) whether the autocommand is only run once.
+/// - pattern: (string) the autocommand pattern.
/// If the autocommand is buffer local |autocmd-buffer-local|:
-/// - buflocal (boolean): true if the autocommand is buffer local.
-/// - buffer (number): the buffer number.
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(9)
{
- // TODO(tjdevries): Would be cool to add nvim_get_autocmds({ id = ... })
-
ArrayBuilder autocmd_list = KV_INITIAL_VALUE;
kvi_init(autocmd_list);
char *pattern_filters[AUCMD_MAX_PATTERNS];
@@ -127,6 +126,8 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
});
}
+ int id = (HAS_KEY(opts, get_autocmds, id)) ? (int)opts->id : -1;
+
if (HAS_KEY(opts, get_autocmds, event)) {
check_event = true;
@@ -237,6 +238,10 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
continue;
}
+ if (id != -1 && ac->id != id) {
+ continue;
+ }
+
// Skip autocmds from invalid groups if passed.
if (group != 0 && ap->group != group) {
continue;
@@ -285,10 +290,12 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
PUT_C(autocmd_info, "desc", CSTR_AS_OBJ(ac->desc));
}
- if (ac->exec.type == CALLABLE_CB) {
+ if (ac->handler_cmd) {
+ PUT_C(autocmd_info, "command", CSTR_AS_OBJ(ac->handler_cmd));
+ } else {
PUT_C(autocmd_info, "command", STRING_OBJ(STRING_INIT));
- Callback *cb = &ac->exec.callable.cb;
+ Callback *cb = &ac->handler_fn;
switch (cb->type) {
case kCallbackLua:
if (nlua_ref_is_function(cb->data.luaref)) {
@@ -302,8 +309,6 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
case kCallbackNone:
abort();
}
- } else {
- PUT_C(autocmd_info, "command", CSTR_AS_OBJ(ac->exec.callable.cmd));
}
PUT_C(autocmd_info, "pattern", CSTR_AS_OBJ(ap->pat));
@@ -317,23 +322,6 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
PUT_C(autocmd_info, "buflocal", BOOLEAN_OBJ(false));
}
- // TODO(sctx): It would be good to unify script_ctx to actually work with lua
- // right now it's just super weird, and never really gives you the info that
- // you would expect from this.
- //
- // I think we should be able to get the line number, filename, etc. from lua
- // when we're executing something, and it should be easy to then save that
- // info here.
- //
- // I think it's a big loss not getting line numbers of where options, autocmds,
- // etc. are set (just getting "Sourced (lua)" or something is not that helpful.
- //
- // Once we do that, we can put these into the autocmd_info, but I don't think it's
- // useful to do that at this time.
- //
- // PUT_C(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid));
- // PUT_C(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum));
-
kvi_push(autocmd_list, DICT_OBJ(autocmd_info));
}
}
@@ -386,9 +374,9 @@ cleanup:
/// - id: (number) autocommand id
/// - event: (string) name of the triggered event |autocmd-events|
/// - group: (number|nil) autocommand group id, if any
-/// - match: (string) expanded value of [<amatch>]
-/// - buf: (number) expanded value of [<abuf>]
-/// - file: (string) expanded value of [<afile>]
+/// - file: (string) [<afile>] (not expanded to a full path)
+/// - match: (string) [<amatch>] (expanded to a full path)
+/// - buf: (number) [<abuf>]
/// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]()
/// - command (string) optional: Vim command to execute on event. Cannot be used with
/// {callback}
@@ -406,8 +394,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
{
int64_t autocmd_id = -1;
char *desc = NULL;
- AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT;
- Callback cb = CALLBACK_NONE;
+ char *handler_cmd = NULL;
+ Callback handler_fn = CALLBACK_NONE;
Array event_array = unpack_string_or_array(event, "event", true, arena, err);
if (ERROR_SET(err)) {
@@ -432,13 +420,13 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
goto cleanup;
});
- cb.type = kCallbackLua;
- cb.data.luaref = callback->data.luaref;
+ handler_fn.type = kCallbackLua;
+ handler_fn.data.luaref = callback->data.luaref;
callback->data.luaref = LUA_NOREF;
break;
case kObjectTypeString:
- cb.type = kCallbackFuncref;
- cb.data.funcref = string_to_cstr(callback->data.string);
+ handler_fn.type = kCallbackFuncref;
+ handler_fn.data.funcref = string_to_cstr(callback->data.string);
break;
default:
VALIDATE_EXP(false, "callback", "Lua function or Vim function name",
@@ -446,12 +434,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
goto cleanup;
});
}
-
- aucmd.type = CALLABLE_CB;
- aucmd.callable.cb = cb;
} else if (HAS_KEY(opts, create_autocmd, command)) {
- aucmd.type = CALLABLE_EX;
- aucmd.callable.cmd = string_to_cstr(opts->command);
+ handler_cmd = string_to_cstr(opts->command);
} else {
VALIDATE(false, "%s", "Required: 'command' or 'callback'", {
goto cleanup;
@@ -491,7 +475,6 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
int retval;
FOREACH_ITEM(patterns, pat, {
- // See: TODO(sctx)
WITH_SCRIPT_CONTEXT(channel_id, {
retval = autocmd_register(autocmd_id,
event_nr,
@@ -501,7 +484,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
opts->once,
opts->nested,
desc,
- aucmd);
+ handler_cmd,
+ &handler_fn);
});
if (retval == FAIL) {
@@ -512,7 +496,11 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
});
cleanup:
- aucmd_exec_free(&aucmd);
+ if (handler_cmd) {
+ XFREE_CLEAR(handler_cmd);
+ } else {
+ callback_free(&handler_fn);
+ }
return autocmd_id;
}
@@ -631,7 +619,7 @@ Integer nvim_create_augroup(uint64_t channel_id, String name, Dict(create_augrou
FUNC_API_SINCE(9)
{
char *augroup_name = name.data;
- bool clear_autocmds = api_object_to_bool(opts->clear, "clear", true, err);
+ bool clear_autocmds = GET_BOOL_OR_TRUE(opts, create_augroup, clear);
int augroup = -1;
WITH_SCRIPT_CONTEXT(channel_id, {
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 9480292d9a..aa349790b3 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -23,7 +23,6 @@
#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/cursor.h"
-#include "nvim/drawscreen.h"
#include "nvim/ex_cmds.h"
#include "nvim/extmark.h"
#include "nvim/extmark_defs.h"
@@ -360,93 +359,91 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
memchrsub(lines[i], NUL, NL, l.size);
}
- try_start();
-
- if (!MODIFIABLE(buf)) {
- api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
- goto end;
- }
-
- if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to save undo information");
- goto end;
- }
-
- bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
-
- // 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".
- size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
- for (size_t i = 0; i < to_delete; i++) {
- if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to delete line");
+ TRY_WRAP(err, {
+ if (!MODIFIABLE(buf)) {
+ api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
- }
- if (to_delete > 0) {
- extra -= (ptrdiff_t)to_delete;
- }
+ if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to save undo information");
+ goto end;
+ }
- // 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.
- size_t to_replace = old_len < new_len ? old_len : new_len;
- bcount_t inserted_bytes = 0;
- for (size_t i = 0; i < to_replace; i++) {
- int64_t lnum = start + (int64_t)i;
+ bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
- VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
- goto end;
- });
+ // 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".
+ size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
+ for (size_t i = 0; i < to_delete; i++) {
+ if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to delete line");
+ goto end;
+ }
+ }
- if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to replace line");
- goto end;
+ if (to_delete > 0) {
+ extra -= (ptrdiff_t)to_delete;
}
- inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
- }
+ // 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.
+ size_t to_replace = old_len < new_len ? old_len : new_len;
+ bcount_t inserted_bytes = 0;
+ for (size_t i = 0; i < to_replace; i++) {
+ int64_t lnum = start + (int64_t)i;
+
+ VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
+ goto end;
+ });
+
+ if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to replace line");
+ goto end;
+ }
- // Now we may need to insert the remaining new old_len
- for (size_t i = to_replace; i < new_len; i++) {
- int64_t lnum = start + (int64_t)i - 1;
+ inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
+ }
- VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
- goto end;
- });
+ // Now we may need to insert the remaining new old_len
+ for (size_t i = to_replace; i < new_len; i++) {
+ int64_t lnum = start + (int64_t)i - 1;
- if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to insert line");
- goto end;
- }
+ VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", {
+ goto end;
+ });
- inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
+ if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to insert line");
+ goto end;
+ }
- extra++;
- }
+ inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
- // Adjust marks. Invalidate any which lie in the
- // changed range, and move any in the remainder of the buffer.
- linenr_T adjust = end > start ? MAXLNUM : 0;
- mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra,
- true, true, kExtmarkNOOP);
+ extra++;
+ }
- extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
- deleted_bytes, (int)new_len, 0, inserted_bytes,
- kExtmarkUndo);
+ // Adjust marks. Invalidate any which lie in the
+ // changed range, and move any in the remainder of the buffer.
+ linenr_T adjust = end > start ? MAXLNUM : 0;
+ mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra,
+ true, true, kExtmarkNOOP);
- changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
+ extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
+ deleted_bytes, (int)new_len, 0, inserted_bytes,
+ kExtmarkUndo);
- FOR_ALL_TAB_WINDOWS(tp, win) {
- if (win->w_buffer == buf) {
- fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
- }
- }
+ changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
-end:
- try_end(err);
+ FOR_ALL_TAB_WINDOWS(tp, win) {
+ if (win->w_buffer == buf) {
+ fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
+ }
+ }
+ end:;
+ });
}
/// Sets (replaces) a range in the buffer
@@ -593,101 +590,99 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
new_byte += (bcount_t)(last_item.size) + 1;
}
- try_start();
-
- if (!MODIFIABLE(buf)) {
- api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
- goto end;
- }
-
- // Small note about undo states: unlike set_lines, we want to save the
- // undo state of one past the end_row, since end_row is inclusive.
- if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to save undo information");
- goto end;
- }
-
- ptrdiff_t extra = 0; // lines added to text, can be negative
- size_t old_len = (size_t)(end_row - start_row + 1);
-
- // 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".
- size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
- for (size_t i = 0; i < to_delete; i++) {
- if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to delete line");
+ TRY_WRAP(err, {
+ if (!MODIFIABLE(buf)) {
+ api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
- }
- if (to_delete > 0) {
- extra -= (ptrdiff_t)to_delete;
- }
-
- // 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.
- size_t to_replace = old_len < new_len ? old_len : new_len;
- for (size_t i = 0; i < to_replace; i++) {
- int64_t lnum = start_row + (int64_t)i;
-
- VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
+ // Small note about undo states: unlike set_lines, we want to save the
+ // undo state of one past the end_row, since end_row is inclusive.
+ if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
- });
+ }
- if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to replace line");
- goto end;
+ ptrdiff_t extra = 0; // lines added to text, can be negative
+ size_t old_len = (size_t)(end_row - start_row + 1);
+
+ // 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".
+ size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
+ for (size_t i = 0; i < to_delete; i++) {
+ if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to delete line");
+ goto end;
+ }
}
- }
- // Now we may need to insert the remaining new old_len
- for (size_t i = to_replace; i < new_len; i++) {
- int64_t lnum = start_row + (int64_t)i - 1;
+ if (to_delete > 0) {
+ extra -= (ptrdiff_t)to_delete;
+ }
- VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
- goto end;
- });
+ // 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.
+ size_t to_replace = old_len < new_len ? old_len : new_len;
+ for (size_t i = 0; i < to_replace; i++) {
+ int64_t lnum = start_row + (int64_t)i;
- if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
- api_set_error(err, kErrorTypeException, "Failed to insert line");
- goto end;
+ VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
+ goto end;
+ });
+
+ if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to replace line");
+ goto end;
+ }
}
- extra++;
- }
+ // Now we may need to insert the remaining new old_len
+ for (size_t i = to_replace; i < new_len; i++) {
+ int64_t lnum = start_row + (int64_t)i - 1;
- colnr_T col_extent = (colnr_T)(end_col
- - ((end_row == start_row) ? start_col : 0));
-
- // Adjust marks. Invalidate any which lie in the
- // changed range, and move any in the remainder of the buffer.
- // Do not adjust any cursors. need to use column-aware logic (below)
- linenr_T adjust = end_row >= start_row ? MAXLNUM : 0;
- mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra,
- true, true, kExtmarkNOOP);
-
- extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
- (int)(end_row - start_row), col_extent, old_byte,
- (int)new_len - 1, (colnr_T)last_item.size, new_byte,
- kExtmarkUndo);
-
- changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
-
- FOR_ALL_TAB_WINDOWS(tp, win) {
- if (win->w_buffer == buf) {
- if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) {
- fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row,
- (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size);
- } else {
- fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
+ VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", {
+ goto end;
+ });
+
+ if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
+ api_set_error(err, kErrorTypeException, "Failed to insert line");
+ goto end;
}
+
+ extra++;
}
- }
-end:
- try_end(err);
+ colnr_T col_extent = (colnr_T)(end_col
+ - ((end_row == start_row) ? start_col : 0));
+
+ // Adjust marks. Invalidate any which lie in the
+ // changed range, and move any in the remainder of the buffer.
+ // Do not adjust any cursors. need to use column-aware logic (below)
+ linenr_T adjust = end_row >= start_row ? MAXLNUM : 0;
+ mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra,
+ true, true, kExtmarkNOOP);
+
+ extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
+ (int)(end_row - start_row), col_extent, old_byte,
+ (int)new_len - 1, (colnr_T)last_item.size, new_byte,
+ kExtmarkUndo);
+
+ changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
+
+ FOR_ALL_TAB_WINDOWS(tp, win) {
+ if (win->w_buffer == buf) {
+ if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) {
+ fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row,
+ (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size);
+ } else {
+ fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
+ }
+ }
+ }
+ end:;
+ });
}
/// Gets a range from the buffer.
@@ -965,26 +960,27 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
return;
}
- try_start();
-
- const bool is_curbuf = buf == curbuf;
- const int save_acd = p_acd;
- if (!is_curbuf) {
- // Temporarily disable 'autochdir' when setting file name for another buffer.
- p_acd = false;
- }
+ int ren_ret = OK;
+ TRY_WRAP(err, {
+ const bool is_curbuf = buf == curbuf;
+ const int save_acd = p_acd;
+ if (!is_curbuf) {
+ // Temporarily disable 'autochdir' when setting file name for another buffer.
+ p_acd = false;
+ }
- // Using aucmd_*: autocommands will be executed by rename_buffer
- aco_save_T aco;
- aucmd_prepbuf(&aco, buf);
- int ren_ret = rename_buffer(name.data);
- aucmd_restbuf(&aco);
+ // Using aucmd_*: autocommands will be executed by rename_buffer
+ aco_save_T aco;
+ aucmd_prepbuf(&aco, buf);
+ ren_ret = rename_buffer(name.data);
+ aucmd_restbuf(&aco);
- if (!is_curbuf) {
- p_acd = save_acd;
- }
+ if (!is_curbuf) {
+ p_acd = save_acd;
+ }
+ });
- if (try_end(err)) {
+ if (ERROR_SET(err)) {
return;
}
@@ -1184,12 +1180,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena,
/// This temporarily switches current buffer to "buffer".
/// If the current window already shows "buffer", the window is not switched.
/// If a window inside the current tabpage (including a float) already shows the
-/// buffer, then one of these windows will be set as current window temporarily.
+/// buffer, then one of those windows will be set as current window temporarily.
/// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used.
///
/// This is useful e.g. to call Vimscript functions that only work with the
-/// current buffer/window currently, like |termopen()|.
+/// current buffer/window currently, like `jobstart(…, {'term': v:true})`.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param fun Function to call inside the buffer (currently Lua callable
@@ -1204,15 +1200,18 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
if (!buf) {
return NIL;
}
- try_start();
- aco_save_T aco;
- aucmd_prepbuf(&aco, buf);
- Array args = ARRAY_DICT_INIT;
- Object res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
+ Object res = OBJECT_INIT;
+ TRY_WRAP(err, {
+ aco_save_T aco;
+ aucmd_prepbuf(&aco, buf);
+
+ Array args = ARRAY_DICT_INIT;
+ res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
+
+ aucmd_restbuf(&aco);
+ });
- aucmd_restbuf(&aco);
- try_end(err);
return res;
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index ab57d5c009..23e08bd3fe 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -26,6 +26,7 @@
#include "nvim/macros_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
+#include "nvim/memory_defs.h"
#include "nvim/ops.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
@@ -226,8 +227,8 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
addr = "?";
break;
}
- PUT_KEY(result, cmd, addr, CSTR_AS_OBJ(addr));
- PUT_KEY(result, cmd, nextcmd, CSTR_AS_OBJ(ea.nextcmd));
+ PUT_KEY(result, cmd, addr, cstr_as_string(addr));
+ PUT_KEY(result, cmd, nextcmd, cstr_as_string(ea.nextcmd));
// TODO(bfredl): nested keydict would be nice..
Dict mods = arena_dict(arena, 20);
@@ -930,6 +931,9 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err)
gap = &ucmds;
} else {
buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (ERROR_SET(err)) {
+ return;
+ }
gap = &buf->b_ucmds;
}
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index b38a7d4173..1d81b21be6 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -1,3 +1,5 @@
+// Island of misfit toys.
+
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
@@ -7,6 +9,7 @@
#include "nvim/api/extmark.h"
#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/vimscript.h"
@@ -18,14 +21,14 @@
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
+#include "nvim/marktree.h"
#include "nvim/memory.h"
#include "nvim/memory_defs.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/channel_defs.h"
-#include "nvim/msgpack_rpc/unpacker.h"
+#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/option_defs.h"
#include "nvim/pos_defs.h"
+#include "nvim/strings.h"
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -82,6 +85,17 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err)
return buf->b_fnum;
}
+static uint32_t src2ns(Integer *src_id)
+{
+ if (*src_id == 0) {
+ *src_id = nvim_create_namespace((String)STRING_INIT);
+ }
+ if (*src_id < 0) {
+ return (((uint32_t)1) << 31) - 1;
+ }
+ return (uint32_t)(*src_id);
+}
+
/// Clears highlights and virtual text from namespace and range of lines
///
/// @deprecated use |nvim_buf_clear_namespace()|.
@@ -100,6 +114,80 @@ void nvim_buf_clear_highlight(Buffer buffer, Integer ns_id, Integer line_start,
nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end, err);
}
+/// Adds a highlight to buffer.
+///
+/// @deprecated use |nvim_buf_set_extmark()| or |vim.hl.range()|
+///
+/// Namespaces are used for batch deletion/updating of a set of highlights. To
+/// create a namespace, use |nvim_create_namespace()| which returns a namespace
+/// id. Pass it in to this function as `ns_id` to add highlights to the
+/// namespace. All highlights in the same namespace can then be cleared with
+/// single call to |nvim_buf_clear_namespace()|. If the highlight never will be
+/// deleted by an API call, pass `ns_id = -1`.
+///
+/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
+/// highlight, the allocated id is then returned. If `hl_group` is the empty
+/// string no highlight is added, but a new `ns_id` is still returned. This is
+/// supported for backwards compatibility, new code should use
+/// |nvim_create_namespace()| to create a new empty namespace.
+///
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param ns_id namespace to use or -1 for ungrouped highlight
+/// @param hl_group Name of the highlight group to use
+/// @param line Line to highlight (zero-indexed)
+/// @param col_start Start of (byte-indexed) column range to highlight
+/// @param col_end End of (byte-indexed) column range to highlight,
+/// or -1 to highlight to end of line
+/// @param[out] err Error details, if any
+/// @return The ns_id that was used
+Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, Integer line,
+ Integer col_start, Integer col_end, Error *err)
+ FUNC_API_SINCE(1)
+ FUNC_API_DEPRECATED_SINCE(13)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (!buf) {
+ return 0;
+ }
+
+ VALIDATE_RANGE((line >= 0 && line < MAXLNUM), "line number", {
+ return 0;
+ });
+ VALIDATE_RANGE((col_start >= 0 && col_start <= MAXCOL), "column", {
+ return 0;
+ });
+
+ if (col_end < 0 || col_end > MAXCOL) {
+ col_end = MAXCOL;
+ }
+
+ uint32_t ns = src2ns(&ns_id);
+
+ if (!(line < buf->b_ml.ml_line_count)) {
+ // safety check, we can't add marks outside the range
+ return ns_id;
+ }
+
+ int hl_id = 0;
+ if (hl_group.size > 0) {
+ hl_id = syn_check_group(hl_group.data, hl_group.size);
+ } else {
+ return ns_id;
+ }
+
+ int end_line = (int)line;
+ if (col_end == MAXCOL) {
+ col_end = 0;
+ end_line++;
+ }
+
+ DecorInline decor = DECOR_INLINE_INIT;
+ decor.data.hl.hl_id = hl_id;<