diff options
Diffstat (limited to 'src/nvim/api/vim.c')
-rw-r--r-- | src/nvim/api/vim.c | 270 |
1 files changed, 188 insertions, 82 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 602733fd31..d6f95c7a5f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -25,6 +25,7 @@ #include "nvim/highlight.h" #include "nvim/window.h" #include "nvim/types.h" +#include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" #include "nvim/screen.h" #include "nvim/memline.h" @@ -35,10 +36,12 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/userfunc.h" #include "nvim/fileio.h" #include "nvim/ops.h" #include "nvim/option.h" #include "nvim/state.h" +#include "nvim/extmark.h" #include "nvim/syntax.h" #include "nvim/getchar.h" #include "nvim/os/input.h" @@ -53,20 +56,6 @@ # include "api/vim.c.generated.h" #endif -// `msg_list` controls the collection of abort-causing non-exception errors, -// which would otherwise be ignored. This pattern is from do_cmdline(). -// -// TODO(bfredl): prepare error-handling at "top level" (nv_event). -#define TRY_WRAP(code) \ - do { \ - struct msglist **saved_msg_list = msg_list; \ - struct msglist *private_msg_list; \ - msg_list = &private_msg_list; \ - private_msg_list = NULL; \ - code \ - msg_list = saved_msg_list; /* Restore the exception context. */ \ - } while (0) - void api_vim_init(void) FUNC_API_NOEXPORT { @@ -85,10 +74,70 @@ void api_vim_free_all_mem(void) map_free(String, handle_T)(namespace_ids); } +/// Executes Vimscript (multiline block of Ex-commands), like anonymous +/// |:source|. +/// +/// Unlike |nvim_command()| this function supports heredocs, script-scope (s:), +/// etc. +/// +/// On execution error: fails with VimL error, does not update v:errmsg. +/// +/// @see |execute()| +/// @see |nvim_command()| +/// +/// @param src Vimscript code +/// @param output Capture and return all (non-error, non-shell |:!|) output +/// @param[out] err Error details (Vim error), if any +/// @return Output (non-error, non-shell |:!|) if `output` is true, +/// else empty string. +String nvim_exec(String src, Boolean output, Error *err) + FUNC_API_SINCE(7) +{ + const int save_msg_silent = msg_silent; + garray_T *const save_capture_ga = capture_ga; + garray_T capture_local; + if (output) { + ga_init(&capture_local, 1, 80); + capture_ga = &capture_local; + } + + try_start(); + msg_silent++; + do_source_str(src.data, "nvim_exec()"); + capture_ga = save_capture_ga; + msg_silent = save_msg_silent; + try_end(err); + + if (ERROR_SET(err)) { + goto theend; + } + + if (output && capture_local.ga_len > 1) { + String s = (String){ + .data = capture_local.ga_data, + .size = (size_t)capture_local.ga_len, + }; + // redir usually (except :echon) prepends a newline. + if (s.data[0] == '\n') { + memmove(s.data, s.data + 1, s.size - 1); + s.data[s.size - 1] = '\0'; + s.size = s.size - 1; + } + return s; // Caller will free the memory. + } +theend: + if (output) { + ga_clear(&capture_local); + } + return (String)STRING_INIT; +} + /// Executes an ex-command. /// /// On execution error: fails with VimL error, does not update v:errmsg. /// +/// @see |nvim_exec()| +/// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any void nvim_command(String command, Error *err) @@ -141,10 +190,29 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) return hl_get_attr_by_id(attrcode, rgb, err); } +/// Gets a highlight group by name +/// +/// similar to |hlID()|, but allocates a new ID if not present. +Integer nvim_get_hl_id_by_name(String name) + FUNC_API_SINCE(7) +{ + return syn_check_group((const char_u *)name.data, (int)name.size); +} + /// Sends input-keys to Nvim, subject to various quirks controlled by `mode` /// flags. This is a blocking call, unlike |nvim_input()|. /// /// On execution error: does not fail, but updates v:errmsg. +// +// If you need to input sequences like <C-o> use nvim_replace_termcodes +// to replace the termcodes and then pass the resulting string to +// nvim_feedkeys. You'll also want to enable escape_csi. +/// +/// Example: +/// <pre> +/// :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true) +/// :call nvim_feedkeys(key, 'n', v:true) +/// </pre> /// /// @param keys to be typed /// @param mode behavior flags, see |feedkeys()| @@ -184,19 +252,19 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) keys_esc = keys.data; } ins_typebuf((char_u *)keys_esc, (remap ? REMAP_YES : REMAP_NONE), - insert ? 0 : typebuf.tb_len, !typed, false); + insert ? 0 : typebuf.tb_len, !typed, false); + if (vgetc_busy) { + typebuf_was_filled = true; + } if (escape_csi) { xfree(keys_esc); } - if (vgetc_busy) { - typebuf_was_filled = true; - } if (execute) { int save_msg_scroll = msg_scroll; - /* Avoid a 1 second delay when the keys start Insert mode. */ + // Avoid a 1 second delay when the keys start Insert mode. msg_scroll = false; if (!dangerous) { ex_normal_busy++; @@ -278,7 +346,7 @@ void nvim_input_mouse(String button, String action, String modifier, if (strequal(action.data, "down")) { code = KE_MOUSEUP; } else if (strequal(action.data, "up")) { - code = KE_MOUSEDOWN; + // code = KE_MOUSEDOWN } else if (strequal(action.data, "left")) { code = KE_MOUSERIGHT; } else if (strequal(action.data, "right")) { @@ -345,53 +413,16 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, return cstr_as_string(ptr); } -/// Executes an ex-command and returns its (non-error) output. -/// Shell |:!| output is not captured. -/// -/// On execution error: fails with VimL error, does not update v:errmsg. -/// -/// @param command Ex-command string -/// @param[out] err Error details (Vim error), if any +/// @deprecated +/// @see nvim_exec String nvim_command_output(String command, Error *err) FUNC_API_SINCE(1) + FUNC_API_DEPRECATED_SINCE(7) { - const int save_msg_silent = msg_silent; - garray_T *const save_capture_ga = capture_ga; - garray_T capture_local; - ga_init(&capture_local, 1, 80); - - try_start(); - msg_silent++; - capture_ga = &capture_local; - do_cmdline_cmd(command.data); - capture_ga = save_capture_ga; - msg_silent = save_msg_silent; - try_end(err); - - if (ERROR_SET(err)) { - goto theend; - } - - if (capture_local.ga_len > 1) { - String s = (String){ - .data = capture_local.ga_data, - .size = (size_t)capture_local.ga_len, - }; - // redir usually (except :echon) prepends a newline. - if (s.data[0] == '\n') { - memmove(s.data, s.data + 1, s.size - 1); - s.data[s.size - 1] = '\0'; - s.size = s.size - 1; - } - return s; // Caller will free the memory. - } - -theend: - ga_clear(&capture_local); - return (String)STRING_INIT; + return nvim_exec(command, true, err); } -/// Evaluates a VimL expression (:help expression). +/// Evaluates a VimL |expression|. /// Dictionaries and Lists are recursively expanded. /// /// On execution error: fails with VimL error, does not update v:errmsg. @@ -423,7 +454,8 @@ Object nvim_eval(String expr, Error *err) if (!try_end(err)) { if (ok == FAIL) { // Should never happen, try_end() should get the error. #8371 - api_set_error(err, kErrorTypeException, "Failed to evaluate expression"); + api_set_error(err, kErrorTypeException, + "Failed to evaluate expression: '%.*s'", 256, expr.data); } else { rv = vim_to_object(&rettv); } @@ -436,6 +468,16 @@ Object nvim_eval(String expr, Error *err) return rv; } +/// @deprecated Use nvim_exec_lua() instead. +/// @see nvim_exec_lua +Object nvim_execute_lua(String code, Array args, Error *err) + FUNC_API_SINCE(3) + FUNC_API_DEPRECATED_SINCE(7) + FUNC_API_REMOTE_ONLY +{ + return executor_exec_lua_api(code, args, err); +} + /// Execute Lua code. Parameters (if any) are available as `...` inside the /// chunk. The chunk can return a value. /// @@ -448,8 +490,9 @@ Object nvim_eval(String expr, Error *err) /// or executing the Lua code. /// /// @return Return value of Lua code if present or NIL. -Object nvim_execute_lua(String code, Array args, Error *err) - FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY +Object nvim_exec_lua(String code, Array args, Error *err) + FUNC_API_SINCE(7) + FUNC_API_REMOTE_ONLY { return executor_exec_lua_api(code, args, err); } @@ -671,6 +714,40 @@ ArrayOf(String) nvim_list_runtime_paths(void) return rv; } +/// Find files in runtime directories +/// +/// 'name' can contain wildcards. For example +/// nvim_get_runtime_file("colors/*.vim", true) will return all color +/// scheme files. +/// +/// It is not an error to not find any files. An empty array is returned then. +/// +/// @param name pattern of files to search for +/// @param all whether to return all matches or only the first +/// @return list of absolute paths to the found files +ArrayOf(String) nvim_get_runtime_file(String name, Boolean all) + FUNC_API_SINCE(7) +{ + Array rv = ARRAY_DICT_INIT; + if (!name.data) { + return rv; + } + int flags = DIP_START | (all ? DIP_ALL : 0); + do_in_runtimepath((char_u *)name.data, flags, find_runtime_cb, &rv); + return rv; +} + +static void find_runtime_cb(char_u *fname, void *cookie) +{ + Array *rv = (Array *)cookie; + ADD(*rv, STRING_OBJ(cstr_to_string((char *)fname))); +} + +String nvim__get_lib_dir(void) +{ + return cstr_as_string(get_lib_dir()); +} + /// Changes the global working directory. /// /// @param dir Directory path @@ -970,7 +1047,7 @@ void nvim_set_current_win(Window window, Error *err) /// /// @param listed Sets 'buflisted' /// @param scratch Creates a "throwaway" |scratch-buffer| for temporary work -/// (always 'nomodified') +/// (always 'nomodified'). Also sets 'nomodeline' on the buffer. /// @param[out] err Error details, if any /// @return Buffer handle, or 0 on error /// @@ -1000,9 +1077,10 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) if (scratch) { aco_save_T aco; aucmd_prepbuf(&aco, buf); - set_option_value("bh", 0L, "hide", OPT_LOCAL); - set_option_value("bt", 0L, "nofile", OPT_LOCAL); - set_option_value("swf", 0L, NULL, OPT_LOCAL); + set_option_value("bufhidden", 0L, "hide", OPT_LOCAL); + set_option_value("buftype", 0L, "nofile", OPT_LOCAL); + set_option_value("swapfile", 0L, NULL, OPT_LOCAL); + set_option_value("modeline", 0L, NULL, OPT_LOCAL); // 'nomodeline' aucmd_restbuf(&aco); } return buf->b_fnum; @@ -1054,10 +1132,9 @@ fail: /// @param enter Enter the window (make it the current window) /// @param config Map defining the window configuration. Keys: /// - `relative`: Sets the window layout to "floating", placed at (row,col) -/// coordinates relative to one of: +/// coordinates relative to: /// - "editor" The global editor grid -/// - "win" Window given by the `win` field, or current window by -/// default. +/// - "win" Window given by the `win` field, or current window. /// - "cursor" Cursor position in current window. /// - `win`: |window-ID| for relative="win". /// - `anchor`: Decides which corner of the float to place at (row,col): @@ -1088,9 +1165,10 @@ fail: /// float where the text should not be edited. Disables /// 'number', 'relativenumber', 'cursorline', 'cursorcolumn', /// 'foldcolumn', 'spell' and 'list' options. 'signcolumn' -/// is changed to `auto`. The end-of-buffer region is hidden -/// by setting `eob` flag of 'fillchars' to a space char, -/// and clearing the |EndOfBuffer| region in 'winhighlight'. +/// is changed to `auto` and 'colorcolumn' is cleared. The +/// end-of-buffer region is hidden by setting `eob` flag of +/// 'fillchars' to a space char, and clearing the +/// |EndOfBuffer| region in 'winhighlight'. /// @param[out] err Error details, if any /// /// @return Window handle, or 0 on error @@ -1109,6 +1187,10 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, if (enter) { win_enter(wp, false); } + if (!win_valid(wp)) { + api_set_error(err, kErrorTypeException, "Window was closed immediately"); + return 0; + } if (buffer > 0) { nvim_win_set_buf(wp->handle, buffer, err); } @@ -1260,13 +1342,13 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err) Array lines = string_to_array(data, crlf); ADD(args, ARRAY_OBJ(lines)); ADD(args, INTEGER_OBJ(phase)); - rv = nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim.paste(...)"), args, - err); + rv = nvim_exec_lua(STATIC_CSTR_AS_STRING("return vim.paste(...)"), args, + err); if (ERROR_SET(err)) { draining = true; goto theend; } - if (!(State & CMDLINE) && !(State & INSERT) && (phase == -1 || phase == 1)) { + if (!(State & (CMDLINE | INSERT)) && (phase == -1 || phase == 1)) { ResetRedobuff(); AppendCharToRedobuff('a'); // Dot-repeat. } @@ -1284,7 +1366,7 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err) } } } - if (!(State & CMDLINE) && !(State & INSERT) && (phase == -1 || phase == 3)) { + if (!(State & (CMDLINE | INSERT)) && (phase == -1 || phase == 3)) { AppendCharToRedobuff(ESC); // Dot-repeat. } theend: @@ -1304,7 +1386,7 @@ theend: /// @param lines |readfile()|-style list of lines. |channel-lines| /// @param type Edit behavior: any |getregtype()| result, or: /// - "b" |blockwise-visual| mode (may include width, e.g. "b3") -/// - "c" |characterwise| mode +/// - "c" |charwise| mode /// - "l" |linewise| mode /// - "" guess by contents, see |setreg()| /// @param after Insert after cursor (like |p|), or before (like |P|). @@ -2395,7 +2477,7 @@ Array nvim_get_proc_children(Integer pid, Error *err) Array a = ARRAY_DICT_INIT; ADD(a, INTEGER_OBJ(pid)); String s = cstr_to_string("return vim._os_proc_children(select(1, ...))"); - Object o = nvim_execute_lua(s, a, err); + Object o = nvim_exec_lua(s, a, err); api_free_string(s); api_free_array(a); if (o.type == kObjectTypeArray) { @@ -2441,7 +2523,7 @@ Object nvim_get_proc(Integer pid, Error *err) Array a = ARRAY_DICT_INIT; ADD(a, INTEGER_OBJ(pid)); String s = cstr_to_string("return vim._os_proc_info(select(1, ...))"); - Object o = nvim_execute_lua(s, a, err); + Object o = nvim_exec_lua(s, a, err); api_free_string(s); api_free_array(a); if (o.type == kObjectTypeArray && o.data.array.size == 0) { @@ -2521,3 +2603,27 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err) } return ret; } + +/// Set attrs in nvim__buf_set_lua_hl callbacks +/// +/// TODO(bfredl): This is rather pedestrian. The final +/// interface should probably be derived from a reformed +/// bufhl/virttext interface with full support for multi-line +/// ranges etc +void nvim__put_attr(Integer id, Integer start_row, Integer start_col, + Integer end_row, Integer end_col) + FUNC_API_LUA_ONLY +{ + if (!lua_attr_active) { + return; + } + if (id == 0 || syn_get_final_id((int)id) == 0) { + return; + } + int attr = syn_id2attr((int)id); + if (attr == 0) { + return; + } + decorations_add_luahl_attr(attr, (int)start_row, (colnr_T)start_col, + (int)end_row, (colnr_T)end_col); +} |