From 104800ce2eadd21475b5a4897265a8a177e58d77 Mon Sep 17 00:00:00 2001 From: Malte Dehling Date: Mon, 27 May 2024 04:14:57 -0700 Subject: build: "popcount" name conflict on NetBSD #28983 Problem: NetBSD's libc already has a function by the same name. Solution: Rename popcount to xpopcount and add #if defined(__NetBSD__) to prefer NetBSD's own implementation. This fixes #28983. --- src/nvim/api/vim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fc780e1248..52ab18cbff 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2354,8 +2354,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - int count = (win != NULL) + (buf != NULL); - VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + unsigned count = (win != NULL) + (buf != NULL); + VALIDATE(xpopcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { return; }); -- cgit From 6d6974eae685feeccac027287b4dee58730a7464 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 20:36:16 +0200 Subject: refactor(input): don't use a ring for input Since paste data is handled via a separate channel, the data processed via `input_buffer` is typically just explicit keys as typed in by the user. Therefore it should be fine to use `memmove()` to always put the remaining data in front when refilling the buffer. --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..ae8f73fa2c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -313,7 +313,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) keys_esc = keys.data; } if (lowlevel) { - input_enqueue_raw(cstr_as_string(keys_esc)); + input_enqueue_raw(keys_esc, strlen(keys_esc)); } else { ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), insert ? 0 : typebuf.tb_len, !typed, false); -- cgit From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..f5c89fb283 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -28,6 +28,7 @@ #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" -- cgit From 89f9f168a5c4317bcc71cb61e64a1dd63d17a377 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 20 May 2024 20:21:11 +0200 Subject: fix(api): alloc and draw cursor window in nvim__redraw Problem: Unable to move cursor to recently opened window. Solution: Make sure uninitialized window is drawn before trying to move the cursor to it. --- src/nvim/api/vim.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 26dc223948..7a4aefc620 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2393,10 +2393,6 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) redraw_buf_range_later(rbuf, first, last); } - if (opts->cursor) { - setcursor_mayforce(win ? win : curwin, true); - } - bool flush = opts->flush; if (opts->tabline) { // Flush later in case tabline was just hidden or shown for the first time. @@ -2423,11 +2419,22 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - // Flush pending screen updates if "flush" or "clear" is true, or when - // redrawing a status component may have changed the grid dimensions. + win_T *cwin = win ? win : curwin; + // Allow moving cursor to recently opened window and make sure it is drawn #28868. + if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) { + flush = true; + } + + // Redraw pending screen updates when explicitly requested or when determined + // that it is necessary to properly draw other requested components. if (flush && !cmdpreview) { update_screen(); } + + if (opts->cursor) { + setcursor_mayforce(cwin, true); + } + ui_flush(); RedrawingDisabled = save_rd; -- cgit From fa99afe35eb5d8cf01d875e12b53165bf1104a60 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 4 Sep 2024 12:09:42 +0200 Subject: fix(multibyte): handle backspace of wide clusters in replace mode Make utf_head_off more robust against invalid sequences and embedded NUL chars --- src/nvim/api/vim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7a4aefc620..630c534a7f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -28,6 +28,7 @@ #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/edit.h" #include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" -- cgit From 057d27a9d6ef0bb2ee5130704c45b9e9197e7c36 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Sep 2024 12:20:58 -0700 Subject: refactor: rename "process" => "proc" #30387 Problem: - "process" is often used as a verb (`multiqueue_process_events`), which is ambiguous for cases where it's used as a topic. - The documented naming convention for processes is "proc". - `:help dev-name-common` - Shorter is better, when it doesn't harm readability or discoverability. Solution: Rename "process" => "proc" in all C symbols and module names. --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 630c534a7f..fe263d051d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -70,7 +70,7 @@ #include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os_defs.h" -#include "nvim/os/process.h" +#include "nvim/os/proc.h" #include "nvim/popupmenu.h" #include "nvim/pos_defs.h" #include "nvim/runtime.h" -- cgit From ff85e54939b0aca34a779a2b6381d09db1858b29 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 18 Sep 2024 04:14:06 -0700 Subject: feat(tui): builtin UI (TUI) sets client info #30397 Problem: The default builtin UI client does not declare its client info. This reduces discoverability and makes it difficult for plugins to identify the UI. Solution: - Call nvim_set_client_info after attaching, as recommended by `:help dev-ui`. - Also set the "pid" field. - Also change `ui_active()` to return a count. Not directly relevant to this commit, but will be useful later. --- src/nvim/api/vim.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fe263d051d..d10ee91042 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1586,6 +1586,7 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// /// @param attributes Arbitrary string:string map of informal client properties. /// Suggested keys: +/// - "pid": Process id. /// - "website": Client homepage URL (e.g. GitHub repository) /// - "license": License description ("Apache 2", "GPLv3", "MIT", …) /// - "logo": URI or path to image, preferably small logo or icon. @@ -1627,7 +1628,7 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, /// Gets information about a channel. /// /// @param chan channel_id, or 0 for current channel -/// @returns Dictionary describing a channel, with these keys: +/// @returns Channel info dict with these keys: /// - "id" Channel id. /// - "argv" (optional) Job arguments list. /// - "stream" Stream underlying the channel. @@ -1639,14 +1640,12 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, /// - "bytes" Send and receive raw bytes. /// - "terminal" |terminal| instance interprets ASCII sequences. /// - "rpc" |RPC| communication on the channel is active. -/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this -/// is a device path like "/dev/pts/1". If the name is unknown, -/// the key will still be present if a pty is used (e.g. for -/// conpty on Windows). -/// - "buffer" (optional) Buffer with connected |terminal| instance. -/// - "client" (optional) Info about the peer (client on the other end of -/// the RPC channel), if provided by it via -/// |nvim_set_client_info()|. +/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this is a device path like +/// "/dev/pts/1". If unknown, the key will still be present if a pty is used (e.g. +/// for conpty on Windows). +/// - "buffer" (optional) Buffer connected to |terminal| instance. +/// - "client" (optional) Info about the peer (client on the other end of the RPC channel), +/// which it provided via |nvim_set_client_info()|. /// Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err) FUNC_API_SINCE(4) -- cgit From e697c1b43dfbeab132fee4149157f7abd08c51a0 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 22 Sep 2024 06:02:48 +0800 Subject: fix(paste): improve repeating of pasted text (#30438) - Fixes 'autoindent' being applied during redo. - Makes redoing a large paste significantly faster. - Stores pasted text in the register being recorded. Fix #28561 --- src/nvim/api/vim.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d10ee91042..4b80369654 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1259,30 +1259,19 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error draining = true; goto theend; } - if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 1)) { - ResetRedobuff(); - AppendCharToRedobuff('a'); // Dot-repeat. + if (phase == -1 || phase == 1) { + paste_store(kFalse, NULL_STRING, crlf); } // vim.paste() decides if client should cancel. Errors do NOT cancel: we // want to drain remaining chunks (rather than divert them to main input). cancel = (rv.type == kObjectTypeBoolean && !rv.data.boolean); - if (!cancel && !(State & MODE_CMDLINE)) { // Dot-repeat. - for (size_t i = 0; i < lines.size; i++) { - String s = lines.items[i].data.string; - assert(s.size <= INT_MAX); - AppendToRedobuffLit(s.data, (int)s.size); - // readfile()-style: "\n" is indicated by presence of N+1 item. - if (i + 1 < lines.size) { - AppendCharToRedobuff(NL); - } - } - } - if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 3)) { - AppendCharToRedobuff(ESC); // Dot-repeat. + if (!cancel) { + paste_store(kNone, data, crlf); } theend: if (cancel || phase == -1 || phase == 3) { // End of paste-stream. draining = false; + paste_store(kTrue, NULL_STRING, crlf); } return !cancel; -- cgit From 29bceb4f758097cc6b66726f1dcd3967ad170e35 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 22 Sep 2024 13:51:22 +0300 Subject: docs(api): nvim_get_runtime_file preserves 'runtimepath' order #30454 --- src/nvim/api/vim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 4b80369654..3d60dfa8ab 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -573,10 +573,10 @@ typedef struct { Arena *arena; } RuntimeCookie; -/// Find files in runtime directories +/// Finds files in runtime directories, in 'runtimepath' order. /// /// "name" can contain wildcards. For example -/// nvim_get_runtime_file("colors/*.vim", true) will return all color +/// `nvim_get_runtime_file("colors/*.{vim,lua}", true)` will return all color /// scheme files. Always use forward slashes (/) in the search pattern for /// subdirectories regardless of platform. /// -- cgit From 737f58e23230ea14f1648ac1fc7f442ea0f8563c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 20 Sep 2024 07:34:50 +0200 Subject: refactor(api)!: rename Dictionary => Dict In the api_info() output: :new|put =map(filter(api_info().functions, '!has_key(v:val,''deprecated_since'')'), 'v:val') ... {'return_type': 'ArrayOf(Integer, 2)', 'name': 'nvim_win_get_position', 'method': v:true, 'parameters': [['Window', 'window']], 'since': 1} The `ArrayOf(Integer, 2)` return type didn't break clients when we added it, which is evidence that clients don't use the `return_type` field, thus renaming Dictionary => Dict in api_info() is not (in practice) a breaking change. --- src/nvim/api/vim.c | 90 +++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3d60dfa8ab..c1add75af9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -117,7 +117,7 @@ Integer nvim_get_hl_id_by_name(String name) /// @param[out] err Error details, if any. /// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|, /// or only a single highlight definition map if requested by name or id. -Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) +Dict nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err) FUNC_API_SINCE(11) { return ns_get_hl_defs((NS)ns_id, opts, arena, err); @@ -526,13 +526,13 @@ Object nvim_exec_lua(String code, Array args, Arena *arena, Error *err) /// @param log_level The log level /// @param opts Reserved for future use. /// @param[out] err Error details, if any -Object nvim_notify(String msg, Integer log_level, Dictionary opts, Arena *arena, Error *err) +Object nvim_notify(String msg, Integer log_level, Dict opts, Arena *arena, Error *err) FUNC_API_SINCE(7) { MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, STRING_OBJ(msg)); ADD_C(args, INTEGER_OBJ(log_level)); - ADD_C(args, DICTIONARY_OBJ(opts)); + ADD_C(args, DICT_OBJ(opts)); return NLUA_EXEC_STATIC("return vim.notify(...)", args, kRetObject, arena, err); } @@ -1350,10 +1350,10 @@ Integer nvim_get_color_by_name(String name) /// (e.g. 65535). /// /// @return Map of color names and RGB values. -Dictionary nvim_get_color_map(Arena *arena) +Dict nvim_get_color_map(Arena *arena) FUNC_API_SINCE(1) { - Dictionary colors = arena_dict(arena, ARRAY_SIZE(color_name_table)); + Dict colors = arena_dict(arena, ARRAY_SIZE(color_name_table)); for (int i = 0; color_name_table[i].name != NULL; i++) { PUT_C(colors, color_name_table[i].name, INTEGER_OBJ(color_name_table[i].color)); @@ -1369,7 +1369,7 @@ Dictionary nvim_get_color_map(Arena *arena) /// @param[out] err Error details, if any /// /// @return map of global |context|. -Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) +Dict nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; @@ -1396,7 +1396,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) int_types |= kCtxFuncs; } else { VALIDATE_S(false, "type", s, { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; }); } } @@ -1405,7 +1405,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) Context ctx = CONTEXT_INIT; ctx_save(&ctx, int_types); - Dictionary dict = ctx_to_dict(&ctx, arena); + Dict dict = ctx_to_dict(&ctx, arena); ctx_free(&ctx); return dict; } @@ -1413,7 +1413,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err) /// Sets the current editor state from the given |context| map. /// /// @param dict |Context| map. -Object nvim_load_context(Dictionary dict, Error *err) +Object nvim_load_context(Dict dict, Error *err) FUNC_API_SINCE(6) { Context ctx = CONTEXT_INIT; @@ -1435,11 +1435,11 @@ Object nvim_load_context(Dictionary dict, Error *err) /// Gets the current mode. |mode()| /// "blocking" is true if Nvim is waiting for input. /// -/// @returns Dictionary { "mode": String, "blocking": Boolean } -Dictionary nvim_get_mode(Arena *arena) +/// @returns Dict { "mode": String, "blocking": Boolean } +Dict nvim_get_mode(Arena *arena) FUNC_API_SINCE(2) FUNC_API_FAST { - Dictionary rv = arena_dict(arena, 2); + Dict rv = arena_dict(arena, 2); char *modestr = arena_alloc(arena, MODE_MAX_LENGTH, false); get_mode(modestr); bool blocked = input_blocking(); @@ -1455,7 +1455,7 @@ Dictionary nvim_get_mode(Arena *arena) /// @param mode Mode short-name ("n", "i", "v", ...) /// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key is always zero. -ArrayOf(Dictionary) nvim_get_keymap(String mode, Arena *arena) +ArrayOf(Dict) nvim_get_keymap(String mode, Arena *arena) FUNC_API_SINCE(3) { return keymap_array(mode, NULL, arena); @@ -1514,7 +1514,7 @@ void nvim_del_keymap(uint64_t channel_id, String mode, String lhs, Error *err) } /// Returns a 2-tuple (Array), where item 0 is the current channel id and item -/// 1 is the |api-metadata| map (Dictionary). +/// 1 is the |api-metadata| map (Dict). /// /// @returns 2-tuple `[{channel-id}, {api-metadata}]` Array nvim_get_api_info(uint64_t channel_id, Arena *arena) @@ -1543,7 +1543,7 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// /// @param channel_id /// @param name Short name for the connected client -/// @param version Dictionary describing the version, with these +/// @param version Dict describing the version, with these /// (optional) keys: /// - "major" major version (defaults to 0 if not set, for no release yet) /// - "minor" minor version @@ -1582,8 +1582,8 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena) /// .png or .svg format is preferred. /// /// @param[out] err Error details, if any -void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, String type, - Dictionary methods, Dictionary attributes, Arena *arena, Error *err) +void nvim_set_client_info(uint64_t channel_id, String name, Dict version, String type, Dict methods, + Dict attributes, Arena *arena, Error *err) FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY { MAXSIZE_TEMP_DICT(info, 5); @@ -1597,7 +1597,7 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, } } if (!has_major) { - Dictionary v = arena_dict(arena, version.size + 1); + Dict v = arena_dict(arena, version.size + 1); if (version.size) { memcpy(v.items, version.items, version.size * sizeof(v.items[0])); v.size = version.size; @@ -1605,13 +1605,13 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, PUT_C(v, "major", INTEGER_OBJ(0)); version = v; } - PUT_C(info, "version", DICTIONARY_OBJ(version)); + PUT_C(info, "version", DICT_OBJ(version)); PUT_C(info, "type", STRING_OBJ(type)); - PUT_C(info, "methods", DICTIONARY_OBJ(methods)); - PUT_C(info, "attributes", DICTIONARY_OBJ(attributes)); + PUT_C(info, "methods", DICT_OBJ(methods)); + PUT_C(info, "attributes", DICT_OBJ(attributes)); - rpc_set_client_info(channel_id, copy_dictionary(info, NULL)); + rpc_set_client_info(channel_id, copy_dict(info, NULL)); } /// Gets information about a channel. @@ -1636,11 +1636,11 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, /// - "client" (optional) Info about the peer (client on the other end of the RPC channel), /// which it provided via |nvim_set_client_info()|. /// -Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err) +Dict nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err) FUNC_API_SINCE(4) { if (chan < 0) { - return (Dictionary)ARRAY_DICT_INIT; + return (Dict)ARRAY_DICT_INIT; } if (chan == 0 && !is_internal_call(channel_id)) { @@ -1737,17 +1737,17 @@ Array nvim__id_array(Array arr, Arena *arena) return copy_array(arr, arena); } -/// Returns dictionary given as argument. +/// Returns dict given as argument. /// /// This API function is used for testing. One should not rely on its presence /// in plugins. /// -/// @param[in] dct Dictionary to return. +/// @param[in] dct Dict to return. /// /// @return its argument. -Dictionary nvim__id_dictionary(Dictionary dct, Arena *arena) +Dict nvim__id_dict(Dict dct, Arena *arena) { - return copy_dictionary(dct, arena); + return copy_dict(dct, arena); } /// Returns floating-point value given as argument. @@ -1766,9 +1766,9 @@ Float nvim__id_float(Float flt) /// Gets internal stats. /// /// @return Map of various internal stats. -Dictionary nvim__stats(Arena *arena) +Dict nvim__stats(Arena *arena) { - Dictionary rv = arena_dict(arena, 6); + Dict rv = arena_dict(arena, 6); PUT_C(rv, "fsync", INTEGER_OBJ(g_stats.fsync)); PUT_C(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip)); PUT_C(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count())); @@ -1845,8 +1845,8 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err) }); #ifdef MSWIN - rvobj = DICTIONARY_OBJ(os_proc_info((int)pid, arena)); - if (rvobj.data.dictionary.size == 0) { // Process not found. + rvobj = DICT_OBJ(os_proc_info((int)pid, arena)); + if (rvobj.data.dict.size == 0) { // Process not found. return NIL; } #else @@ -1856,7 +1856,7 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err) Object o = NLUA_EXEC_STATIC("return vim._os_proc_info(...)", a, kRetObject, arena, err); if (o.type == kObjectTypeArray && o.data.array.size == 0) { return NIL; // Process not found. - } else if (o.type == kObjectTypeDictionary) { + } else if (o.type == kObjectTypeDict) { rvobj = o; } else if (!ERROR_SET(err)) { api_set_error(err, kErrorTypeException, @@ -1920,7 +1920,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E schar_get(sc_buf, g->chars[off]); ADD_C(ret, CSTR_AS_OBJ(sc_buf)); int attr = g->attrs[off]; - ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err))); + ADD_C(ret, DICT_OBJ(hl_get_attr_by_id(attr, true, arena, err))); // will not work first time if (!highlight_use_hlstate()) { ADD_C(ret, ARRAY_OBJ(hl_inspect(attr, arena))); @@ -2063,18 +2063,18 @@ Array nvim_get_mark(String name, Dict(empty) *opts, Arena *arena, Error *err) /// - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline. /// /// @param[out] err Error details, if any. -/// @return Dictionary containing statusline information, with these keys: +/// @return Dict containing statusline information, with these keys: /// - str: (string) Characters that will be displayed on the statusline. /// - width: (number) Display width of the statusline. /// - highlights: Array containing highlight information of the statusline. Only included when /// the "highlights" key in {opts} is true. Each element of the array is a -/// |Dictionary| with these keys: +/// |Dict| with these keys: /// - start: (number) Byte index (0-based) of first character that uses the highlight. /// - group: (string) Name of highlight group. -Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err) +Dict nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err) FUNC_API_SINCE(8) FUNC_API_FAST { - Dictionary result = ARRAY_DICT_INIT; + Dict result = ARRAY_DICT_INIT; int maxwidth; schar_T fillchar = 0; @@ -2200,18 +2200,18 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena * // If first character doesn't have a defined highlight, // add the default highlight at the beginning of the highlight list if (hltab->start == NULL || (hltab->start - buf) != 0) { - Dictionary hl_info = arena_dict(arena, 2); + Dict hl_info = arena_dict(arena, 2); const char *grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id); PUT_C(hl_info, "start", INTEGER_OBJ(0)); PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname)); - ADD_C(hl_values, DICTIONARY_OBJ(hl_info)); + ADD_C(hl_values, DICT_OBJ(hl_info)); } for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) { - Dictionary hl_info = arena_dict(arena, 2); + Dict hl_info = arena_dict(arena, 2); PUT_C(hl_info, "start", INTEGER_OBJ(sp->start - buf)); @@ -2225,7 +2225,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena * grpname = arena_memdupz(arena, user_group, strlen(user_group)); } PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname)); - ADD_C(hl_values, DICTIONARY_OBJ(hl_info)); + ADD_C(hl_values, DICT_OBJ(hl_info)); } PUT_C(result, "highlights", ARRAY_OBJ(hl_values)); } @@ -2251,12 +2251,12 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data) /// @param index Completion candidate index /// @param opts Optional parameters. /// - info: (string) info text. -/// @return Dictionary containing these keys: +/// @return Dict containing these keys: /// - winid: (number) floating window id /// - bufnr: (number) buffer id in floating window -Dictionary nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) +Dict nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) { - Dictionary rv = arena_dict(arena, 2); + Dict rv = arena_dict(arena, 2); if (HAS_KEY(opts, complete_set, info)) { win_T *wp = pum_set_info((int)index, opts->info.data); if (wp) { -- cgit From d831392b156087ddc38eb75b0260c03f955dd23c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 24 Sep 2024 07:14:14 +0800 Subject: feat(paste): unify cancel and error behavior (#30476) Before this PR, the behavior of nvim_paste is: - When vim.paste() returns false, return false to the client, but treat following chunks normally (i.e. rely on the client cancelling the paste as expected). - When vim.paste() throws an error, still return true to the client, but drain the following chunks in the stream without calling vim.paste(). There are two problems with such behavior: - When vim.paste() errors, the client is still supposed to send the remaining chunks of the stream, even though they do nothing. - Having different code paths for two uncommon but similar situations complicates maintenance. This PR makes both the cancel case and the error case return false to the client and drain the remaining chunks of the stream, which, apart from sharing the same code path, is beneficial whether the client checks the return value of nvim_paste or not: - If the client checks the return value, it can avoid sending the following chunks needlessly after an error. - If the client doesn't check the return value, chunks following a cancelled chunk won't be pasted on the server regardless, which leads to less confusing behavior. --- src/nvim/api/vim.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c1add75af9..b31accd3b0 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1219,8 +1219,8 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// /// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` /// but do not affect the return value (which is strictly decided by -/// `vim.paste()`). On error, subsequent calls are ignored ("drained") until -/// the next paste is initiated (phase 1 or -1). +/// `vim.paste()`). On error or cancel, subsequent calls are ignored +/// ("drained") until the next paste is initiated (phase 1 or -1). /// /// @param data Multiline input. May be binary (containing NUL bytes). /// @param crlf Also break lines at CR and CRLF. @@ -1233,20 +1233,19 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// @param[out] err Error details, if any /// @return /// - true: Client may continue pasting. -/// - false: Client must cancel the paste. +/// - false: Client should cancel the paste. Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error *err) FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { - static bool draining = false; - bool cancel = false; + static bool cancelled = false; VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, { return false; }); if (phase == -1 || phase == 1) { // Start of paste-stream. - draining = false; - } else if (draining) { + cancelled = false; + } else if (cancelled) { // Skip remaining chunks. Report error only once per "stream". goto theend; } @@ -1255,26 +1254,26 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error ADD_C(args, ARRAY_OBJ(lines)); ADD_C(args, INTEGER_OBJ(phase)); Object rv = NLUA_EXEC_STATIC("return vim.paste(...)", args, kRetNilBool, arena, err); - if (ERROR_SET(err)) { - draining = true; - goto theend; + // vim.paste() decides if client should cancel. + if (ERROR_SET(err) || (rv.type == kObjectTypeBoolean && !rv.data.boolean)) { + cancelled = true; } - if (phase == -1 || phase == 1) { + if (!cancelled && (phase == -1 || phase == 1)) { paste_store(kFalse, NULL_STRING, crlf); } - // vim.paste() decides if client should cancel. Errors do NOT cancel: we - // want to drain remaining chunks (rather than divert them to main input). - cancel = (rv.type == kObjectTypeBoolean && !rv.data.boolean); - if (!cancel) { + if (!cancelled) { paste_store(kNone, data, crlf); } -theend: - if (cancel || phase == -1 || phase == 3) { // End of paste-stream. - draining = false; + if (phase == 3 || phase == (cancelled ? 2 : -1)) { paste_store(kTrue, NULL_STRING, crlf); } - - return !cancel; +theend: + ; + bool retval = !cancelled; + if (phase == -1 || phase == 3) { // End of paste-stream. + cancelled = false; + } + return retval; } /// Puts text at cursor, in any mode. -- cgit From 3f6bc34e663c62bc8899dcdc65bf204b2ccfdaec Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 24 Sep 2024 04:46:50 -0700 Subject: docs: lua error patterns #30240 Co-authored-by: Mathias Fussenegger Co-authored-by: Ananth Bhaskararaman --- src/nvim/api/vim.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b31accd3b0..ae649e55d6 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -344,9 +344,10 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) } } -/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level -/// input buffer and the call is non-blocking (input is processed -/// asynchronously by the eventloop). +/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level input buffer and the call +/// is non-blocking (input is processed asynchronously by the eventloop). +/// +/// To input blocks of text, |nvim_paste()| is much faster and should be preferred. /// /// On execution error: does not fail, but updates v:errmsg. /// @@ -1212,17 +1213,30 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) } } -/// Pastes at cursor, in any mode. +/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call +/// this to implement "paste", but it's also intended for use by scripts to input large, +/// dot-repeatable blocks of text (as opposed to |nvim_input()| which is subject to mappings/events +/// and is thus much slower). +/// +/// Invokes the |vim.paste()| handler, which handles each mode appropriately. +/// +/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the +/// return value (which is strictly decided by `vim.paste()`). On error or cancel, subsequent calls +/// are ignored ("drained") until the next paste is initiated (phase 1 or -1). /// -/// Invokes the `vim.paste` handler, which handles each mode appropriately. -/// Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n"). +/// Useful in mappings and scripts to insert multiline text. Example: /// -/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` -/// but do not affect the return value (which is strictly decided by -/// `vim.paste()`). On error or cancel, subsequent calls are ignored -/// ("drained") until the next paste is initiated (phase 1 or -1). +/// ```vim +/// vim.keymap.set('n', 'x', function() +/// vim.api.nvim_paste([[ +/// line1 +/// line2 +/// line3 +/// ]], false, -1) +/// end, { buffer = true }) +/// ``` /// -/// @param data Multiline input. May be binary (containing NUL bytes). +/// @param data Multiline input. Lines break at LF ("\n"). May be binary (containing NUL bytes). /// @param crlf Also break lines at CR and CRLF. /// @param phase -1: paste in a single call (i.e. without streaming). /// To "stream" a paste, call `nvim_paste` sequentially with @@ -1276,7 +1290,7 @@ theend: return retval; } -/// Puts text at cursor, in any mode. +/// Puts text at cursor, in any mode. For dot-repeatable input, use |nvim_paste()|. /// /// Compare |:put| and |p| which are always linewise. /// -- cgit From 052875b9dc3de3283844a30dce9646f26982542d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 24 Sep 2024 19:48:40 +0800 Subject: fix(paste): only record a paste when it's from RPC (#30491) Problem: When using nvim_paste in a mapping during a macro recording, both the mapping and the paste are recorded, causing the paste to be performed twice when replaying the macro. Solution: Only record a paste when it is from RPC. Unfortunately this means there is no way for a script to make a recorded paste. A way to enable that can be discussed later if there is need. --- src/nvim/api/vim.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ae649e55d6..d18cfaccd0 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1248,7 +1248,8 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// @return /// - true: Client may continue pasting. /// - false: Client should cancel the paste. -Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error *err) +Boolean nvim_paste(uint64_t channel_id, String data, Boolean crlf, Integer phase, Arena *arena, + Error *err) FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { @@ -1273,13 +1274,13 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error cancelled = true; } if (!cancelled && (phase == -1 || phase == 1)) { - paste_store(kFalse, NULL_STRING, crlf); + paste_store(channel_id, kFalse, NULL_STRING, crlf); } if (!cancelled) { - paste_store(kNone, data, crlf); + paste_store(channel_id, kNone, data, crlf); } if (phase == 3 || phase == (cancelled ? 2 : -1)) { - paste_store(kTrue, NULL_STRING, crlf); + paste_store(channel_id, kTrue, NULL_STRING, crlf); } theend: ; -- cgit From ce7017b850e0f62b3ebe6ea0d7010ba0291624e5 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 25 Sep 2024 02:34:13 -0700 Subject: docs: render @see, @note items in _meta/api.lua #30494 --- src/nvim/api/vim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/vim.c') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d18cfaccd0..8c88a19147 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1226,7 +1226,7 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) /// /// Useful in mappings and scripts to insert multiline text. Example: /// -/// ```vim +/// ```lua /// vim.keymap.set('n', 'x', function() /// vim.api.nvim_paste([[ /// line1 -- cgit