diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2025-02-05 23:09:29 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2025-02-05 23:09:29 +0000 |
| commit | d5f194ce780c95821a855aca3c19426576d28ae0 (patch) | |
| tree | d45f461b19f9118ad2bb1f440a7a08973ad18832 /src/nvim/api | |
| parent | c5d770d311841ea5230426cc4c868e8db27300a8 (diff) | |
| parent | 44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff) | |
| download | rneovim-rahm.tar.gz rneovim-rahm.tar.bz2 rneovim-rahm.zip | |
Diffstat (limited to 'src/nvim/api')
| -rw-r--r-- | src/nvim/api/autocmd.c | 104 | ||||
| -rw-r--r-- | src/nvim/api/buffer.c | 351 | ||||
| -rw-r--r-- | src/nvim/api/command.c | 8 | ||||
| -rw-r--r-- | src/nvim/api/deprecated.c | 223 | ||||
| -rw-r--r-- | src/nvim/api/extmark.c | 157 | ||||
| -rw-r--r-- | src/nvim/api/extmark.h | 1 | ||||
| -rw-r--r-- | src/nvim/api/keysets_defs.h | 114 | ||||
| -rw-r--r-- | src/nvim/api/options.c | 60 | ||||
| -rw-r--r-- | src/nvim/api/private/converter.c | 3 | ||||
| -rw-r--r-- | src/nvim/api/private/defs.h | 2 | ||||
| -rw-r--r-- | src/nvim/api/private/helpers.c | 89 | ||||
| -rw-r--r-- | src/nvim/api/private/helpers.h | 16 | ||||
| -rw-r--r-- | src/nvim/api/tabpage.c | 13 | ||||
| -rw-r--r-- | src/nvim/api/ui.c | 4 | ||||
| -rw-r--r-- | src/nvim/api/ui.h | 1 | ||||
| -rw-r--r-- | src/nvim/api/ui_events.in.h | 6 | ||||
| -rw-r--r-- | src/nvim/api/vim.c | 416 | ||||
| -rw-r--r-- | src/nvim/api/vimscript.c | 70 | ||||
| -rw-r--r-- | src/nvim/api/win_config.c | 35 | ||||
| -rw-r--r-- | src/nvim/api/window.c | 77 |
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;< |