diff options
Diffstat (limited to 'src/nvim/api')
| -rw-r--r-- | src/nvim/api/buffer.c | 116 | ||||
| -rw-r--r-- | src/nvim/api/private/defs.h | 11 | ||||
| -rw-r--r-- | src/nvim/api/private/helpers.c | 226 | ||||
| -rw-r--r-- | src/nvim/api/private/helpers.h | 1 | ||||
| -rw-r--r-- | src/nvim/api/ui.c | 79 | ||||
| -rw-r--r-- | src/nvim/api/ui_events.in.h | 6 | ||||
| -rw-r--r-- | src/nvim/api/vim.c | 358 | ||||
| -rw-r--r-- | src/nvim/api/window.c | 71 |
8 files changed, 658 insertions, 210 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 3613a8f8bc..9a5ffecad4 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -15,6 +15,7 @@ #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/getchar.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/misc1.h" @@ -49,7 +50,7 @@ /// Gets the buffer line count /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// @return Line count, or 0 for unloaded buffer. |api-buffer| Integer nvim_buf_line_count(Buffer buffer, Error *err) @@ -97,15 +98,16 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) return rv; } -/// Activate updates from this buffer to the current channel. +/// Activates buffer-update events on the channel. /// -/// @param buffer The buffer handle +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer /// @param send_buffer Set to true if the initial notification should contain /// the whole buffer. If so, the first notification will be a /// `nvim_buf_lines_event`. Otherwise, the first notification will be /// a `nvim_buf_changedtick_event` /// @param opts Optional parameters. Reserved for future use. -/// @param[out] err Details of an error that may have occurred +/// @param[out] err Error details, if any /// @return False when updates couldn't be enabled because the buffer isn't /// loaded or `opts` contained an invalid key; otherwise True. Boolean nvim_buf_attach(uint64_t channel_id, @@ -128,11 +130,12 @@ Boolean nvim_buf_attach(uint64_t channel_id, return buf_updates_register(buf, channel_id, send_buffer); } -// -/// Deactivate updates from this buffer to the current channel. + +/// Deactivates buffer-update events on the channel. /// -/// @param buffer The buffer handle -/// @param[out] err Details of an error that may have occurred +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer +/// @param[out] err Error details, if any /// @return False when updates couldn't be disabled because the buffer /// isn't loaded; otherwise True. Boolean nvim_buf_detach(uint64_t channel_id, @@ -221,7 +224,8 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer, /// Out-of-bounds indices are clamped to the nearest valid value, unless /// `strict_indexing` is set. /// -/// @param buffer Buffer handle +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index /// @param end Last line index (exclusive) /// @param strict_indexing Whether out-of-bounds should be an error. @@ -290,7 +294,7 @@ end: /// newend = end + int(include_end) + int(end < 0) /// int(bool) = 1 if bool is true else 0 /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index /// @param end Last line index /// @param include_start True if the slice includes the `start` parameter @@ -324,7 +328,8 @@ void buffer_set_line_slice(Buffer buffer, /// Out-of-bounds indices are clamped to the nearest valid value, unless /// `strict_indexing` is set. /// -/// @param buffer Buffer handle +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index /// @param end Last line index (exclusive) /// @param strict_indexing Whether out-of-bounds should be an error. @@ -470,6 +475,7 @@ void nvim_buf_set_lines(uint64_t channel_id, false); changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true); + fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra); end: for (size_t i = 0; i < new_len; i++) { @@ -491,7 +497,7 @@ end: /// Unlike |line2byte()|, throws error for out-of-bounds indexing. /// Returns -1 for unloaded buffer. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param index Line index /// @param[out] err Error details, if any /// @return Integer byte offset, or -1 for unloaded buffer. @@ -518,7 +524,7 @@ Integer nvim_buf_get_offset(Buffer buffer, Integer index, Error *err) /// Gets a buffer-scoped (b:) variable. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Variable name /// @param[out] err Error details, if any /// @return Variable value @@ -536,7 +542,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err) /// Gets a changed tick of a buffer /// -/// @param[in] buffer Buffer handle. +/// @param[in] buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// /// @return `b:changedtick` value. @@ -555,7 +561,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) /// Gets a list of buffer-local |mapping| definitions. /// /// @param mode Mode short-name ("n", "i", "v", ...) -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// @returns Array of maparg()-like dictionaries describing mappings. /// The "buffer" key holds the associated buffer handle. @@ -571,9 +577,34 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) return keymap_array(mode, buf); } +/// Sets a buffer-local |mapping| for the given mode. +/// +/// @see |nvim_set_keymap()| +/// +/// @param buffer Buffer handle, or 0 for current buffer +void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, + Dictionary opts, Error *err) + FUNC_API_SINCE(6) +{ + modify_keymap(buffer, false, mode, lhs, rhs, opts, err); +} + +/// Unmaps a buffer-local |mapping| for the given mode. +/// +/// @see |nvim_del_keymap()| +/// +/// @param buffer Buffer handle, or 0 for current buffer +void nvim_buf_del_keymap(Buffer buffer, String mode, String lhs, Error *err) + FUNC_API_SINCE(6) +{ + String rhs = { .data = "", .size = 0 }; + Dictionary opts = ARRAY_DICT_INIT; + modify_keymap(buffer, true, mode, lhs, rhs, opts, err); +} + /// Gets a map of buffer-local |user-commands|. /// -/// @param buffer Buffer handle. +/// @param buffer Buffer handle, or 0 for current buffer /// @param opts Optional parameters. Currently not used. /// @param[out] err Error details, if any. /// @@ -613,7 +644,7 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dictionary opts, Error *err) /// Sets a buffer-scoped (b:) variable /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Variable name /// @param value Variable value /// @param[out] err Error details, if any @@ -631,7 +662,7 @@ void nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err) /// Removes a buffer-scoped (b:) variable /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Variable name /// @param[out] err Error details, if any void nvim_buf_del_var(Buffer buffer, String name, Error *err) @@ -650,7 +681,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err) /// /// @deprecated /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Variable name /// @param value Variable value /// @param[out] err Error details, if any @@ -673,7 +704,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err) /// /// @deprecated /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Variable name /// @param[out] err Error details, if any /// @return Old value @@ -691,7 +722,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err) /// Gets a buffer option value /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Option name /// @param[out] err Error details, if any /// @return Option value @@ -710,7 +741,8 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err) /// Sets a buffer option value. Passing 'nil' as value deletes the option (only /// works if there's a global fallback) /// -/// @param buffer Buffer handle +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Option name /// @param value Option value /// @param[out] err Error details, if any @@ -732,7 +764,7 @@ void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, /// @deprecated The buffer number now is equal to the object id, /// so there is no need to use this function. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// @return Buffer number Integer nvim_buf_get_number(Buffer buffer, Error *err) @@ -751,7 +783,7 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err) /// Gets the full file name for the buffer /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param[out] err Error details, if any /// @return Buffer name String nvim_buf_get_name(Buffer buffer, Error *err) @@ -769,7 +801,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err) /// Sets the full file name for a buffer /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Buffer name /// @param[out] err Error details, if any void nvim_buf_set_name(Buffer buffer, String name, Error *err) @@ -801,7 +833,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err) /// Checks if a buffer is valid and loaded. See |api-buffer| for more info /// about unloaded buffers. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @return true if the buffer is valid and loaded, false otherwise. Boolean nvim_buf_is_loaded(Buffer buffer) FUNC_API_SINCE(5) @@ -817,7 +849,7 @@ Boolean nvim_buf_is_loaded(Buffer buffer) /// @note Even if a buffer is valid it may have been unloaded. See |api-buffer| /// for more info about unloaded buffers. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @return true if the buffer is valid, false otherwise. Boolean nvim_buf_is_valid(Buffer buffer) FUNC_API_SINCE(1) @@ -849,7 +881,7 @@ void buffer_insert(Buffer buffer, /// Return a tuple (row,col) representing the position of the named mark /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param name Mark name /// @param[out] err Error details, if any /// @return (row, col) tuple @@ -914,7 +946,7 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) /// supported for backwards compatibility, new code should use /// |nvim_create_namespace| to create a new empty namespace. /// -/// @param buffer Buffer handle +/// @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) @@ -964,7 +996,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, /// To clear the namespace in the entire buffer, pass in 0 and -1 to /// line_start and line_end respectively. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param ns_id Namespace to clear, or -1 to clear all namespaces. /// @param line_start Start of range of lines to clear /// @param line_end End of range of lines to clear (exclusive) or -1 to clear @@ -997,7 +1029,7 @@ void nvim_buf_clear_namespace(Buffer buffer, /// /// @deprecated use |nvim_buf_clear_namespace|. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param ns_id Namespace to clear, or -1 to clear all. /// @param line_start Start of range of lines to clear /// @param line_end End of range of lines to clear (exclusive) or -1 to clear @@ -1031,7 +1063,7 @@ void nvim_buf_clear_highlight(Buffer buffer, /// As a shorthand, `ns_id = 0` can be used to create a new namespace for the /// virtual text, the allocated id is then returned. /// -/// @param buffer Buffer handle +/// @param buffer Buffer handle, or 0 for current buffer /// @param ns_id Namespace to use or 0 to create a namespace, /// or -1 for a ungrouped annotation /// @param line Line to annotate with virtual text (zero-indexed) @@ -1101,6 +1133,26 @@ free_exit: return 0; } +// Check if deleting lines made the cursor position invalid. +// Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted). +static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) +{ + if (curwin->w_cursor.lnum >= lo) { + // Adjust cursor position if it's in/after the changed lines. + if (curwin->w_cursor.lnum >= hi) { + curwin->w_cursor.lnum += extra; + check_cursor_col(); + } else if (extra < 0) { + curwin->w_cursor.lnum = lo; + check_cursor(); + } else { + check_cursor_col(); + } + changed_cline_bef_curs(); + } + invalidate_botline(); +} + // Normalizes 0-based indexes to buffer line numbers static int64_t normalize_index(buf_T *buf, int64_t index, bool *oob) { diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index feca140547..978c55691b 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -29,14 +29,13 @@ typedef enum { } ErrorType; typedef enum { - kMessageTypeRequest, - kMessageTypeResponse, - kMessageTypeNotification + kMessageTypeUnknown = -1, + // Per msgpack-rpc spec. + kMessageTypeRequest = 0, + kMessageTypeResponse = 1, + kMessageTypeNotification = 2, } MessageType; -/// Used as the message ID of notifications. -#define NO_RESPONSE UINT64_MAX - /// Mask for all internal calls #define INTERNAL_CALL_MASK (((uint64_t)1) << (sizeof(uint64_t) * 8 - 1)) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index c2b382804d..521ec11906 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -744,6 +744,232 @@ String ga_take_string(garray_T *ga) return str; } +/// Set, tweak, or remove a mapping in a mode. Acts as the implementation for +/// functions like @ref nvim_buf_set_keymap. +/// +/// Arguments are handled like @ref nvim_set_keymap unless noted. +/// @param buffer Buffer handle for a specific buffer, or 0 for the current +/// buffer, or -1 to signify global behavior ("all buffers") +/// @param is_unmap When true, removes the mapping that matches {lhs}. +void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, + String rhs, Dictionary opts, Error *err) +{ + char *err_msg = NULL; // the error message to report, if any + char *err_arg = NULL; // argument for the error message format string + ErrorType err_type = kErrorTypeNone; + + char_u *lhs_buf = NULL; + char_u *rhs_buf = NULL; + + bool global = (buffer == -1); + if (global) { + buffer = 0; + } + buf_T *target_buf = find_buffer_by_handle(buffer, err); + + MapArguments parsed_args; + memset(&parsed_args, 0, sizeof(parsed_args)); + if (parse_keymap_opts(opts, &parsed_args, err)) { + goto fail_and_free; + } + parsed_args.buffer = !global; + + set_maparg_lhs_rhs((char_u *)lhs.data, lhs.size, + (char_u *)rhs.data, rhs.size, + CPO_TO_CPO_FLAGS, &parsed_args); + + if (parsed_args.lhs_len > MAXMAPLEN) { + err_msg = "LHS exceeds maximum map length: %s"; + err_arg = lhs.data; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + + if (mode.size > 1) { + err_msg = "Shortname is too long: %s"; + err_arg = mode.data; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + int mode_val; // integer value of the mapping mode, to be passed to do_map() + char_u *p = (char_u *)((mode.size) ? mode.data : "m"); + if (STRNCMP(p, "!", 2) == 0) { + mode_val = get_map_mode(&p, true); // mapmode-ic + } else { + mode_val = get_map_mode(&p, false); + if ((mode_val == VISUAL + SELECTMODE + NORMAL + OP_PENDING) + && mode.size > 0) { + // get_map_mode() treats unrecognized mode shortnames as ":map". + // This is an error unless the given shortname was empty string "". + err_msg = "Invalid mode shortname: \"%s\""; + err_arg = (char *)p; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + } + + if (parsed_args.lhs_len == 0) { + err_msg = "Invalid (empty) LHS"; + err_arg = ""; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + + bool is_noremap = parsed_args.noremap; + assert(!(is_unmap && is_noremap)); + + if (!is_unmap && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) { + if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop> + parsed_args.rhs_is_noop = true; + } else { + // the given RHS was nonempty and not a <Nop>, but was parsed as if it + // were empty? + assert(false && "Failed to parse nonempty RHS!"); + err_msg = "Parsing of nonempty RHS failed: %s"; + err_arg = rhs.data; + err_type = kErrorTypeException; + goto fail_with_message; + } + } else if (is_unmap && parsed_args.rhs_len) { + err_msg = "Gave nonempty RHS in unmap command: %s"; + err_arg = (char *)parsed_args.rhs; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + + // buf_do_map() reads noremap/unmap as its own argument. + int maptype_val = 0; + if (is_unmap) { + maptype_val = 1; + } else if (is_noremap) { + maptype_val = 2; + } + + switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) { + case 0: + break; + case 1: + api_set_error(err, kErrorTypeException, (char *)e_invarg, 0); + goto fail_and_free; + case 2: + api_set_error(err, kErrorTypeException, (char *)e_nomap, 0); + goto fail_and_free; + case 5: + api_set_error(err, kErrorTypeException, + "E227: mapping already exists for %s", parsed_args.lhs); + goto fail_and_free; + default: + assert(false && "Unrecognized return code!"); + goto fail_and_free; + } // switch + + xfree(lhs_buf); + xfree(rhs_buf); + xfree(parsed_args.rhs); + xfree(parsed_args.orig_rhs); + + return; + +fail_with_message: + api_set_error(err, err_type, err_msg, err_arg); + +fail_and_free: + xfree(lhs_buf); + xfree(rhs_buf); + xfree(parsed_args.rhs); + xfree(parsed_args.orig_rhs); + return; +} + +/// Read in the given opts, setting corresponding flags in `out`. +/// +/// @param opts A dictionary passed to @ref nvim_set_keymap or +/// @ref nvim_buf_set_keymap. +/// @param[out] out MapArguments object in which to set parsed +/// |:map-arguments| flags. +/// @param[out] err Error details, if any. +/// +/// @returns Zero on success, nonzero on failure. +Integer parse_keymap_opts(Dictionary opts, MapArguments *out, Error *err) +{ + char *err_msg = NULL; // the error message to report, if any + char *err_arg = NULL; // argument for the error message format string + ErrorType err_type = kErrorTypeNone; + + out->buffer = false; + out->nowait = false; + out->silent = false; + out->script = false; + out->expr = false; + out->unique = false; + + for (size_t i = 0; i < opts.size; i++) { + KeyValuePair *key_and_val = &opts.items[i]; + char *optname = key_and_val->key.data; + + if (key_and_val->value.type != kObjectTypeBoolean) { + err_msg = "Gave non-boolean value for an opt: %s"; + err_arg = optname; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + + bool was_valid_opt = false; + switch (optname[0]) { + // note: strncmp up to and including the null terminator, so that + // "nowaitFoobar" won't match against "nowait" + + // don't recognize 'buffer' as a key; user shouldn't provide <buffer> + // when calling nvim_set_keymap or nvim_buf_set_keymap, since it can be + // inferred from which function they called + case 'n': + if (STRNCMP(optname, "noremap", 8) == 0) { + was_valid_opt = true; + out->noremap = key_and_val->value.data.boolean; + } else if (STRNCMP(optname, "nowait", 7) == 0) { + was_valid_opt = true; + out->nowait = key_and_val->value.data.boolean; + } + break; + case 's': + if (STRNCMP(optname, "silent", 7) == 0) { + was_valid_opt = true; + out->silent = key_and_val->value.data.boolean; + } else if (STRNCMP(optname, "script", 7) == 0) { + was_valid_opt = true; + out->script = key_and_val->value.data.boolean; + } + break; + case 'e': + if (STRNCMP(optname, "expr", 5) == 0) { + was_valid_opt = true; + out->expr = key_and_val->value.data.boolean; + } + break; + case 'u': + if (STRNCMP(optname, "unique", 7) == 0) { + was_valid_opt = true; + out->unique = key_and_val->value.data.boolean; + } + break; + default: + break; + } // switch + if (!was_valid_opt) { + err_msg = "Invalid key: %s"; + err_arg = optname; + err_type = kErrorTypeValidation; + goto fail_with_message; + } + } // for + + return 0; + +fail_with_message: + api_set_error(err, err_type, err_msg, err_arg); + return 1; +} + /// Collects `n` buffer lines into array `l`, optionally replacing newlines /// with NUL. /// diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 0634764f13..cc74824402 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -5,6 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/vim.h" +#include "nvim/getchar.h" #include "nvim/memory.h" #include "nvim/ex_eval.h" #include "nvim/lib/kvec.h" diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index d3cbb46dad..4f28ea5af3 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -29,11 +29,12 @@ typedef struct { uint64_t channel_id; Array buffer; - int hl_id; // current higlight for legacy put event - Integer cursor_row, cursor_col; // Intended visibule cursor position + int hl_id; // Current highlight for legacy put event. + Integer cursor_row, cursor_col; // Intended visible cursor position. // Position of legacy cursor, used both for drawing and visible user cursor. Integer client_row, client_col; + bool wildmenu_active; } UIData; static PMap(uint64_t) *connected_uis = NULL; @@ -75,6 +76,21 @@ void remote_ui_wait_for_attach(void) pmap_has(uint64_t)(connected_uis, CHAN_STDIO)); } +/// Activates UI events on the channel. +/// +/// Entry point of all UI clients. Allows |\-\-embed| to continue startup. +/// Implies that the client is ready to show the UI. Adds the client to the +/// list of UIs. |nvim_list_uis()| +/// +/// @note If multiple UI clients are attached, the global screen dimensions +/// degrade to the smallest client. E.g. if client A requests 80x40 but +/// client B requests 200x100, the global screen has size 80x40. +/// +/// @param channel_id +/// @param width Requested screen columns +/// @param height Requested screen rows +/// @param options |ui-option| map +/// @param[out] err Error details, if any void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY @@ -94,6 +110,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, ui->width = (int)width; ui->height = (int)height; ui->rgb = true; + ui->override = false; ui->grid_resize = remote_ui_grid_resize; ui->grid_clear = remote_ui_grid_clear; ui->grid_cursor_goto = remote_ui_grid_cursor_goto; @@ -146,6 +163,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, data->buffer = (Array)ARRAY_DICT_INIT; data->hl_id = 0; data->client_col = -1; + data->wildmenu_active = false; ui->data = data; pmap_put(uint64_t)(connected_uis, channel_id, ui); @@ -162,6 +180,12 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height, api_free_dictionary(opts); } +/// Deactivates UI events on the channel. +/// +/// Removes the client from the list of UIs. |nvim_list_uis()| +/// +/// @param channel_id +/// @param[out] err Error details, if any void nvim_ui_detach(uint64_t channel_id, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { @@ -213,6 +237,15 @@ void nvim_ui_set_option(uint64_t channel_id, String name, static void ui_set_option(UI *ui, bool init, String name, Object value, Error *error) { + if (strequal(name.data, "override")) { + if (value.type != kObjectTypeBoolean) { + api_set_error(error, kErrorTypeValidation, "override must be a Boolean"); + return; + } + ui->override = value.data.boolean; + return; + } + if (strequal(name.data, "rgb")) { if (value.type != kObjectTypeBoolean) { api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean"); @@ -262,20 +295,22 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, /// /// On invalid grid handle, fails with error. /// +/// @param channel_id /// @param grid The handle of the grid to be changed. /// @param width The new requested width. /// @param height The new requested height. +/// @param[out] err Error details, if any void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, - Integer height, Error *error) + Integer height, Error *err) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY { if (!pmap_has(uint64_t)(connected_uis, channel_id)) { - api_set_error(error, kErrorTypeException, + api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; } - ui_grid_resize((handle_T)grid, (int)width, (int)height, error); + ui_grid_resize((handle_T)grid, (int)width, (int)height, err); } /// Pushes data into UI.UIData, to be consumed later by remote_ui_flush(). @@ -586,6 +621,7 @@ static Array translate_firstarg(UI *ui, Array args) static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) { + UIData *data = ui->data; if (!ui->ui_ext[kUILinegrid]) { // the representation of highlights in cmdline changed, translate back // never consumes args @@ -611,6 +647,39 @@ static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) } } + // Back-compat: translate popupmenu_xx to legacy wildmenu_xx. + if (ui->ui_ext[kUIWildmenu]) { + if (strequal(name, "popupmenu_show")) { + data->wildmenu_active = (args.items[4].data.integer == -1) + || !ui->ui_ext[kUIPopupmenu]; + if (data->wildmenu_active) { + Array new_args = ARRAY_DICT_INIT; + Array items = args.items[0].data.array; + Array new_items = ARRAY_DICT_INIT; + for (size_t i = 0; i < items.size; i++) { + ADD(new_items, copy_object(items.items[i].data.array.items[0])); + } + ADD(new_args, ARRAY_OBJ(new_items)); + push_call(ui, "wildmenu_show", new_args); + if (args.items[1].data.integer != -1) { + Array new_args2 = ARRAY_DICT_INIT; + ADD(new_args2, args.items[1]); + push_call(ui, "wildmenu_select", new_args); + } + return; + } + } else if (strequal(name, "popupmenu_select")) { + if (data->wildmenu_active) { + name = "wildmenu_select"; + } + } else if (strequal(name, "popupmenu_hide")) { + if (data->wildmenu_active) { + name = "wildmenu_hide"; + } + } + } + + Array my_args = ARRAY_DICT_INIT; // Objects are currently single-reference // make a copy, but only if necessary diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index b89c5b6014..a1d25766fe 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -143,11 +143,11 @@ void cmdline_block_hide(void) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; void wildmenu_show(Array items) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void wildmenu_select(Integer selected) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void wildmenu_hide(void) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL; void msg_show(String kind, Array content, Boolean replace_last) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index cb5ed5ecda..b8c863704a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -15,6 +15,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/buffer.h" +#include "nvim/api/window.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/lua/executor.h" @@ -213,8 +214,8 @@ Integer nvim_input(String keys) /// Send mouse event from GUI. /// -/// The call is non-blocking. It doesn't wait on any resulting action, but -/// queues the event to be processed soon by the event loop. +/// Non-blocking: does not wait on any result, but queues the event to be +/// processed soon by the event loop. /// /// @note Currently this doesn't support "scripting" multiple mouse events /// by calling it multiple times in a loop: the intermediate mouse @@ -232,6 +233,7 @@ Integer nvim_input(String keys) /// @param grid Grid number if the client uses |ui-multigrid|, else 0. /// @param row Mouse row-position (zero-based, like redraw events) /// @param col Mouse column-position (zero-based, like redraw events) +/// @param[out] err Error details, if any void nvim_input_mouse(String button, String action, String modifier, Integer grid, Integer row, Integer col, Error *err) FUNC_API_SINCE(6) FUNC_API_ASYNC @@ -681,14 +683,14 @@ void nvim_set_current_dir(String dir, Error *err) try_start(); - if (vim_chdir((char_u *)string, kCdScopeGlobal)) { + if (vim_chdir((char_u *)string)) { if (!try_end(err)) { api_set_error(err, kErrorTypeException, "Failed to change directory"); } return; } - post_chdir(kCdScopeGlobal); + post_chdir(kCdScopeGlobal, true); try_end(err); } @@ -755,9 +757,9 @@ void nvim_del_var(String name, Error *err) /// @deprecated /// @see nvim_set_var -/// @return Old value or nil if there was no previous value. /// @warning May return nil if there was no previous value /// OR if previous value was `v:null`. +/// @return Old value or nil if there was no previous value. Object vim_set_var(String name, Object value, Error *err) { return dict_set_var(&globvardict, name, value, false, true, err); @@ -805,6 +807,7 @@ Object nvim_get_option(String name, Error *err) /// Sets an option value. /// +/// @param channel_id /// @param name Option name /// @param value New option value /// @param[out] err Error details, if any @@ -937,6 +940,7 @@ Window nvim_get_current_win(void) /// Sets the current window. /// /// @param window Window handle +/// @param[out] err Error details, if any void nvim_set_current_win(Window window, Error *err) FUNC_API_SINCE(1) { @@ -958,7 +962,7 @@ void nvim_set_current_win(Window window, Error *err) /// Creates a new, empty, unnamed buffer. /// -/// @param listed Controls 'buflisted' +/// @param listed Sets 'buflisted' /// @param scratch Creates a "throwaway" |scratch-buffer| for temporary work /// (always 'nomodified') /// @param[out] err Error details, if any @@ -997,38 +1001,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) /// GUI with the |ui-multigrid| extension. External windows are only supported /// with multigrid GUIs, and are displayed as separate top-level windows. /// -/// Exactly one of `external` and `relative` must be specified. +/// For a general overview of floats, see |api-floatwin|. /// -/// @param buffer handle of buffer to be displayed in the window -/// @param enter whether the window should be entered (made the current window) -/// @param width width of window (in character cells) -/// @param height height of window (in character cells) -/// @param options dict of options for configuring window positioning -/// accepts the following keys: -/// `relative`: If set, the window becomes a floating window. The window -/// will be placed with row,col coordinates relative one of the -/// following: -/// "editor" the global editor grid -/// "win" a window. Use 'win' option below to specify window id, -/// or current window will be used by default. -/// "cursor" the cursor position in current window. -/// `anchor`: the corner of the float that the row,col position defines -/// "NW" north-west (default) -/// "NE" north-east -/// "SW" south-west -/// "SE" south-east -/// `focusable`: Whether window can be focused by wincmds and -/// mouse events. Defaults to true. Even if set to false, the window -/// can still be entered using |nvim_set_current_win()| API call. -/// `row`: row position. Screen cell height are used as unit. Can be -/// floating point. -/// `col`: column position. Screen cell width is used as unit. Can be -/// floating point. -/// `win`: when using relative='win', window id of the window where the -/// position is defined. -/// `external` GUI should display the window as an external -/// top-level window. Currently accepts no other positioning options -/// together with this. +/// Exactly one of `external` and `relative` must be specified. The `width` and +/// `height` of the new window must be specified. /// /// With editor positioning row=0, col=0 refers to the top-left corner of the /// screen-grid and row=Lines-1, Columns-1 refers to the bottom-right corner. @@ -1042,27 +1018,55 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) /// could let floats hover outside of the main window like a tooltip, but /// this should not be used to specify arbitrary WM screen positions. /// +/// @param buffer handle of buffer to be displayed in the window +/// @param enter whether the window should be entered (made the current window) +/// @param config Dictionary for the window configuration accepts these keys: +/// - `relative`: If set, the window becomes a floating window. The window +/// will be placed with row,col coordinates relative to one of the +/// following: +/// - "editor" the global editor grid +/// - "win" a window. Use `win` to specify a window id, +/// or the current window will be used by default. +/// "cursor" the cursor position in current window. +/// - `win`: When using relative='win', window id of the window where the +/// position is defined. +/// - `anchor`: The corner of the float that the row,col position defines: +/// - "NW" north-west (default) +/// - "NE" north-east +/// - "SW" south-west +/// - "SE" south-east +/// - `height`: window height (in character cells). Minimum of 1. +/// - `width`: window width (in character cells). Minimum of 1. +/// - `row`: row position. Screen cell height are used as unit. Can be +/// floating point. +/// - `col`: column position. Screen cell width is used as unit. Can be +/// floating point. +/// - `focusable`: Whether window can be focused by wincmds and +/// mouse events. Defaults to true. Even if set to false, the window +/// can still be entered using |nvim_set_current_win()| API call. +/// - `external`: GUI should display the window as an external +/// top-level window. Currently accepts no other positioning +/// configuration together with this. /// @param[out] err Error details, if any -/// @return the window handle or 0 when error -Window nvim_open_win(Buffer buffer, Boolean enter, - Integer width, Integer height, - Dictionary options, Error *err) +/// +/// @return Window handle, or 0 on error +Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, + Error *err) FUNC_API_SINCE(6) { - win_T *old = curwin; - FloatConfig config = FLOAT_CONFIG_INIT; - if (!parse_float_config(options, &config, false, err)) { + FloatConfig fconfig = FLOAT_CONFIG_INIT; + if (!parse_float_config(config, &fconfig, false, err)) { return 0; } - win_T *wp = win_new_float(NULL, (int)width, (int)height, config, err); + win_T *wp = win_new_float(NULL, fconfig, err); if (!wp) { return 0; } - if (buffer > 0) { - nvim_set_current_buf(buffer, err); + if (enter) { + win_enter(wp, false); } - if (!enter) { - win_enter(old, false); + if (buffer > 0) { + nvim_win_set_buf(wp->handle, buffer, err); } return wp->handle; } @@ -1194,12 +1198,29 @@ void nvim_unsubscribe(uint64_t channel_id, String event) rpc_unsubscribe(channel_id, e); } +/// Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or +/// "#rrggbb" hexadecimal string. +/// +/// Example: +/// <pre> +/// :echo nvim_get_color_by_name("Pink") +/// :echo nvim_get_color_by_name("#cbcbcb") +/// </pre> +/// +/// @param name Color name or "#rrggbb" string +/// @return 24-bit RGB value, or -1 for invalid argument. Integer nvim_get_color_by_name(String name) FUNC_API_SINCE(1) { return name_to_color((char_u *)name.data); } +/// Returns a map of color names and RGB values. +/// +/// Keys are color names (e.g. "Aqua") and values are 24-bit RGB color values +/// (e.g. 65535). +/// +/// @return Map of color names and RGB values. Dictionary nvim_get_color_map(void) FUNC_API_SINCE(1) { @@ -1241,6 +1262,49 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) return keymap_array(mode, NULL); } +/// Sets a global |mapping| for the given mode. +/// +/// To set a buffer-local mapping, use |nvim_buf_set_keymap()|. +/// +/// Unlike |:map|, leading/trailing whitespace is accepted as part of the {lhs} +/// or {rhs}. Empty {rhs} is |<Nop>|. |keycodes| are replaced as usual. +/// +/// Example: +/// <pre> +/// call nvim_set_keymap('n', ' <NL>', '', {'nowait': v:true}) +/// </pre> +/// +/// is equivalent to: +/// <pre> +/// nmap <nowait> <Space><NL> <Nop> +/// </pre> +/// +/// @param mode Mode short-name (map command prefix: "n", "i", "v", "x", …) +/// or "!" for |:map!|, or empty string for |:map|. +/// @param lhs Left-hand-side |{lhs}| of the mapping. +/// @param rhs Right-hand-side |{rhs}| of the mapping. +/// @param opts Optional parameters map. Accepts all |:map-arguments| +/// as keys excluding |<buffer>| but including |noremap|. +/// Values are Booleans. Unknown key is an error. +/// @param[out] err Error details, if any. +void nvim_set_keymap(String mode, String lhs, String rhs, + Dictionary opts, Error *err) + FUNC_API_SINCE(6) +{ + modify_keymap(-1, false, mode, lhs, rhs, opts, err); +} + +/// Unmaps a global |mapping| for the given mode. +/// +/// To unmap a buffer-local mapping, use |nvim_buf_del_keymap()|. +/// +/// @see |nvim_set_keymap()| +void nvim_del_keymap(String mode, String lhs, Error *err) + FUNC_API_SINCE(6) +{ + nvim_buf_del_keymap(-1, mode, lhs, err); +} + /// Gets a map of global (non-buffer-local) Ex commands. /// /// Currently only |user-commands| are supported, not builtin Ex commands. @@ -1272,47 +1336,48 @@ Array nvim_get_api_info(uint64_t channel_id) return rv; } -/// Identify the client for nvim. Can be called more than once, but subsequent -/// calls will remove earlier info, which should be resent if it is still -/// valid. (This could happen if a library first identifies the channel, and a +/// Identifies the client. Can be called more than once; subsequent calls +/// remove earlier info, which should be included by the caller if it is +/// still valid. (E.g. if a library first identifies the channel, then a /// plugin using that library later overrides that info) /// -/// @param name short name for the connected client -/// @param version Dictionary describing the version, with the following -/// possible keys (all optional) +/// @param channel_id +/// @param name Short name for the connected client +/// @param version Dictionary describing the version, with these +/// (optional) keys: /// - "major" major version (defaults to 0 if not set, for no release yet) /// - "minor" minor version /// - "patch" patch number /// - "prerelease" string describing a prerelease, like "dev" or "beta1" /// - "commit" hash or similar identifier of commit -/// @param type Must be one of the following values. A client library should -/// use "remote" if the library user hasn't specified other value. -/// - "remote" remote client that connected to nvim. +/// @param type Must be one of the following values. Client libraries should +/// default to "remote" unless overridden by the user. +/// - "remote" remote client connected to Nvim. /// - "ui" gui frontend -/// - "embedder" application using nvim as a component, for instance -/// IDE/editor implementing a vim mode. +/// - "embedder" application using Nvim as a component (for example, +/// IDE/editor implementing a vim mode). /// - "host" plugin host, typically started by nvim /// - "plugin" single plugin, started by nvim /// @param methods Builtin methods in the client. For a host, this does not /// include plugin methods which will be discovered later. /// The key should be the method name, the values are dicts with -/// the following (optional) keys: +/// these (optional) keys (more keys may be added in future +/// versions of Nvim, thus unknown keys are ignored. Clients +/// must only use keys defined in this or later versions of +/// Nvim): /// - "async" if true, send as a notification. If false or unspecified, /// use a blocking request /// - "nargs" Number of arguments. Could be a single integer or an array -/// two integers, minimum and maximum inclusive. -/// Further keys might be added in later versions of nvim and unknown keys -/// are thus ignored. Clients must only use keys defined in this or later -/// versions of nvim! -/// -/// @param attributes Informal attributes describing the client. Clients might -/// define their own keys, but the following are suggested: -/// - "website" Website of client (for instance github repository) -/// - "license" Informal description of the license, such as "Apache 2", -/// "GPLv3" or "MIT" -/// - "logo" URI or path to image, preferably small logo or icon. -/// .png or .svg format is preferred. +/// of two integers, minimum and maximum inclusive. +/// +/// @param attributes Arbitrary string:string map of informal client properties. +/// Suggested keys: +/// - "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. +/// .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, @@ -1344,15 +1409,14 @@ void nvim_set_client_info(uint64_t channel_id, String name, /// Get information about a channel. /// -/// @returns a Dictionary, describing a channel with the -/// following keys: -/// - "stream" the stream underlying the channel +/// @returns Dictionary describing a channel, with these keys: +/// - "stream" the stream underlying the channel /// - "stdio" stdin and stdout of this Nvim instance /// - "stderr" stderr of this Nvim instance /// - "socket" TCP/IP socket or named pipe /// - "job" job with communication over its stdio /// - "mode" how data received on the channel is interpreted -/// - "bytes" send and recieve raw bytes +/// - "bytes" send and receive raw bytes /// - "terminal" a |terminal| instance interprets ASCII sequences /// - "rpc" |RPC| communication on the channel is active /// - "pty" Name of pseudoterminal, if one is used (optional). @@ -1393,13 +1457,13 @@ Array nvim_list_chans(void) /// processing which have such side-effects, e.g. |:sleep| may wake timers). /// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests. /// +/// @param channel_id /// @param calls an array of calls, where each call is described by an array -/// with two elements: the request name, and an array of arguments. -/// @param[out] err Details of a validation error of the nvim_multi_request call -/// itself, i.e. malformed `calls` parameter. Errors from called methods will -/// be indicated in the return value, see below. +/// with two elements: the request name, and an array of arguments. +/// @param[out] err Validation error details (malformed `calls` parameter), +/// if any. Errors from batched calls are given in the return value. /// -/// @return an array with two elements. The first is an array of return +/// @return Array of two elements. The first is an array of return /// values. The second is NIL if all calls succeeded. If a call resulted in /// an error, it is a three-element array with the zero-based index of the call /// which resulted in an error, the error type and the error message. If an @@ -1490,9 +1554,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// Parse a VimL expression. /// -/// @param[in] expr Expression to parse. Is always treated as a single line. -/// @param[in] flags Flags: -/// +/// @param[in] expr Expression to parse. Always treated as a single line. +/// @param[in] flags Flags: /// - "m" if multiple expressions in a row are allowed (only /// the first one will be parsed), /// - "E" if EOC tokens are not allowed (determines whether @@ -1500,7 +1563,6 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// operator/space, though also yielding an error). /// - "l" when needing to start parsing with lvalues for /// ":let" or ":for". -/// /// Common flag sets: /// - "m" to parse like for ":echo". /// - "E" to parse like for "<C-r>=". @@ -1513,63 +1575,57 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// starting column and ending column (latter exclusive: /// one should highlight region [start_col, end_col)). /// -/// @return AST: top-level dictionary with these keys: -/// -/// "error": Dictionary with error, present only if parser saw some -/// error. Contains the following keys: -/// -/// "message": String, error message in printf format, translated. -/// Must contain exactly one "%.*s". -/// "arg": String, error message argument. -/// -/// "len": Amount of bytes successfully parsed. With flags equal to "" -/// that should be equal to the length of expr string. -/// -/// @note: “Sucessfully parsed” here means “participated in AST -/// creation”, not “till the first error”. -/// -/// "ast": AST, either nil or a dictionary with these keys: -/// -/// "type": node type, one of the value names from ExprASTNodeType -/// stringified without "kExprNode" prefix. -/// "start": a pair [line, column] describing where node is “started” -/// where "line" is always 0 (will not be 0 if you will be -/// using nvim_parse_viml() on e.g. ":let", but that is not -/// present yet). Both elements are Integers. -/// "len": “length” of the node. This and "start" are there for -/// debugging purposes primary (debugging parser and providing -/// debug information). -/// "children": a list of nodes described in top/"ast". There always -/// is zero, one or two children, key will not be present -/// if node has no children. Maximum number of children -/// may be found in node_maxchildren array. -/// -/// Local values (present only for certain nodes): -/// -/// "scope": a single Integer, specifies scope for "Option" and -/// "PlainIdentifier" nodes. For "Option" it is one of -/// ExprOptScope values, for "PlainIdentifier" it is one of -/// ExprVarScope values. -/// "ident": identifier (without scope, if any), present for "Option", -/// "PlainIdentifier", "PlainKey" and "Environment" nodes. -/// "name": Integer, register name (one character) or -1. Only present -/// for "Register" nodes. -/// "cmp_type": String, comparison type, one of the value names from -/// ExprComparisonType, stringified without "kExprCmp" -/// prefix. Only present for "Comparison" nodes. -/// "ccs_strategy": String, case comparison strategy, one of the -/// value names from ExprCaseCompareStrategy, -/// stringified without "kCCStrategy" prefix. Only -/// present for "Comparison" nodes. -/// "augmentation": String, augmentation type for "Assignment" nodes. -/// Is either an empty string, "Add", "Subtract" or -/// "Concat" for "=", "+=", "-=" or ".=" respectively. -/// "invert": Boolean, true if result of comparison needs to be -/// inverted. Only present for "Comparison" nodes. -/// "ivalue": Integer, integer value for "Integer" nodes. -/// "fvalue": Float, floating-point value for "Float" nodes. -/// "svalue": String, value for "SingleQuotedString" and -/// "DoubleQuotedString" nodes. +/// @return +/// - AST: top-level dictionary with these keys: +/// - "error": Dictionary with error, present only if parser saw some +/// error. Contains the following keys: +/// - "message": String, error message in printf format, translated. +/// Must contain exactly one "%.*s". +/// - "arg": String, error message argument. +/// - "len": Amount of bytes successfully parsed. With flags equal to "" +/// that should be equal to the length of expr string. +/// (“Sucessfully parsed” here means “participated in AST +/// creation”, not “till the first error”.) +/// - "ast": AST, either nil or a dictionary with these keys: +/// - "type": node type, one of the value names from ExprASTNodeType +/// stringified without "kExprNode" prefix. +/// - "start": a pair [line, column] describing where node is "started" +/// where "line" is always 0 (will not be 0 if you will be +/// using nvim_parse_viml() on e.g. ":let", but that is not +/// present yet). Both elements are Integers. +/// - "len": “length” of the node. This and "start" are there for +/// debugging purposes primary (debugging parser and providing +/// debug information). +/// - "children": a list of nodes described in top/"ast". There always +/// is zero, one or two children, key will not be present +/// if node has no children. Maximum number of children +/// may be found in node_maxchildren array. +/// - Local values (present only for certain nodes): +/// - "scope": a single Integer, specifies scope for "Option" and +/// "PlainIdentifier" nodes. For "Option" it is one of +/// ExprOptScope values, for "PlainIdentifier" it is one of +/// ExprVarScope values. +/// - "ident": identifier (without scope, if any), present for "Option", +/// "PlainIdentifier", "PlainKey" and "Environment" nodes. +/// - "name": Integer, register name (one character) or -1. Only present +/// for "Register" nodes. +/// - "cmp_type": String, comparison type, one of the value names from +/// ExprComparisonType, stringified without "kExprCmp" +/// prefix. Only present for "Comparison" nodes. +/// - "ccs_strategy": String, case comparison strategy, one of the +/// value names from ExprCaseCompareStrategy, +/// stringified without "kCCStrategy" prefix. Only +/// present for "Comparison" nodes. +/// - "augmentation": String, augmentation type for "Assignment" nodes. +/// Is either an empty string, "Add", "Subtract" or +/// "Concat" for "=", "+=", "-=" or ".=" respectively. +/// - "invert": Boolean, true if result of comparison needs to be +/// inverted. Only present for "Comparison" nodes. +/// - "ivalue": Integer, integer value for "Integer" nodes. +/// - "fvalue": Float, floating-point value for "Float" nodes. +/// - "svalue": String, value for "SingleQuotedString" and +/// "DoubleQuotedString" nodes. +/// @param[out] err Error details, if any Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Error *err) FUNC_API_SINCE(4) FUNC_API_ASYNC @@ -2034,15 +2090,12 @@ Dictionary nvim__stats(void) /// Gets a list of dictionaries representing attached UIs. /// -/// @return Array of UI dictionaries -/// -/// Each dictionary has the following keys: -/// - "height" requested height of the UI -/// - "width" requested width of the UI -/// - "rgb" whether the UI uses rgb colors (false implies cterm colors) -/// - "ext_..." Requested UI extensions, see |ui-options| -/// - "chan" Channel id of remote UI (not present for TUI) -/// +/// @return Array of UI dictionaries, each with these keys: +/// - "height" Requested height of the UI +/// - "width" Requested width of the UI +/// - "rgb" true if the UI uses RGB colors (false implies |cterm-colors|) +/// - "ext_..." Requested UI extensions, see |ui-option| +/// - "chan" Channel id of remote UI (not present for TUI) Array nvim_list_uis(void) FUNC_API_SINCE(4) { @@ -2145,6 +2198,7 @@ Object nvim_get_proc(Integer pid, Error *err) /// @param finish Finish the completion and dismiss the popupmenu. Implies /// `insert`. /// @param opts Optional parameters. Reserved for future use. +/// @param[out] err Error details, if any void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Dictionary opts, Error *err) FUNC_API_SINCE(6) diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 157f73c9fa..e1c50cb89d 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -67,6 +67,10 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) buffer); } + // If window is not current, state logic will not validate its cursor. + // So do it now. + validate_cursor(); + restore_win(save_curwin, save_curtab, false); } @@ -345,6 +349,7 @@ Object nvim_win_get_option(Window window, String name, Error *err) /// Sets a window option value. Passing 'nil' as value deletes the option(only /// works if there's a global fallback) /// +/// @param channel_id /// @param window Window handle /// @param name Option name /// @param value Option value @@ -438,14 +443,16 @@ Boolean nvim_win_is_valid(Window window) /// floating and external windows (including changing a split window to these /// types). /// -/// See documentation at |nvim_open_win()|, for the meaning of parameters. Pass -/// in -1 for 'witdh' and 'height' to keep exiting size. +/// See documentation at |nvim_open_win()|, for the meaning of parameters. /// /// When reconfiguring a floating window, absent option keys will not be /// changed. The following restriction apply: `row`, `col` and `relative` /// must be reconfigured together. Only changing a subset of these is an error. -void nvim_win_config(Window window, Integer width, Integer height, - Dictionary options, Error *err) +/// +/// @param window Window handle +/// @param config Dictionary of window configuration +/// @param[out] err Error details, if any +void nvim_win_set_config(Window window, Dictionary config, Error *err) FUNC_API_SINCE(6) { win_T *win = find_window_by_handle(window, err); @@ -453,25 +460,67 @@ void nvim_win_config(Window window, Integer width, Integer height, return; } bool new_float = !win->w_floating; - width = width > 0 ? width: win->w_width; - height = height > 0 ? height : win->w_height; // reuse old values, if not overriden - FloatConfig config = new_float ? FLOAT_CONFIG_INIT : win->w_float_config; + FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config; - if (!parse_float_config(options, &config, !new_float, err)) { + if (!parse_float_config(config, &fconfig, !new_float, err)) { return; } if (new_float) { - if (!win_new_float(win, (int)width, (int)height, config, err)) { + if (!win_new_float(win, fconfig, err)) { return; } redraw_later(NOT_VALID); } else { - win_config_float(win, (int)width, (int)height, config); + win_config_float(win, fconfig); win->w_pos_changed = true; } } +/// Return window configuration. +/// +/// Return a dictionary containing the same config that can be given to +/// |nvim_open_win()|. +/// +/// `relative` will be an empty string for normal windows. +/// +/// @param window Window handle +/// @param[out] err Error details, if any +/// @return Window configuration +Dictionary nvim_win_get_config(Window window, Error *err) + FUNC_API_SINCE(6) +{ + Dictionary rv = ARRAY_DICT_INIT; + + win_T *wp = find_window_by_handle(window, err); + if (!wp) { + return rv; + } + + PUT(rv, "focusable", BOOLEAN_OBJ(wp->w_float_config.focusable)); + PUT(rv, "external", BOOLEAN_OBJ(wp->w_float_config.external)); + + if (wp->w_floating) { + PUT(rv, "width", INTEGER_OBJ(wp->w_float_config.width)); + PUT(rv, "height", INTEGER_OBJ(wp->w_float_config.height)); + if (!wp->w_float_config.external) { + if (wp->w_float_config.relative == kFloatRelativeWindow) { + PUT(rv, "win", INTEGER_OBJ(wp->w_float_config.window)); + } + PUT(rv, "anchor", STRING_OBJ(cstr_to_string( + float_anchor_str[wp->w_float_config.anchor]))); + PUT(rv, "row", FLOAT_OBJ(wp->w_float_config.row)); + PUT(rv, "col", FLOAT_OBJ(wp->w_float_config.col)); + } + } + + const char *rel = (wp->w_floating && !wp->w_float_config.external + ? float_relative_str[wp->w_float_config.relative] : ""); + PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel))); + + return rv; +} + /// Close a window. /// /// This is equivalent to |:close| with count except that it takes a window id. @@ -480,9 +529,7 @@ void nvim_win_config(Window window, Integer width, Integer height, /// @param force Behave like `:close!` The last window of a buffer with /// unwritten changes can be closed. The buffer will become /// hidden, even if 'hidden' is not set. -/// /// @param[out] err Error details, if any -/// @return Window number void nvim_win_close(Window window, Boolean force, Error *err) FUNC_API_SINCE(6) { |