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); +}  | 
