diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/buffer.c | 49 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 14 | ||||
-rw-r--r-- | src/nvim/eval.c | 11 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 30 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 2 | ||||
-rw-r--r-- | src/nvim/normal.c | 2 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 14 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 1 | ||||
-rw-r--r-- | src/nvim/screen.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_ins_complete.vim | 24 | ||||
-rw-r--r-- | src/nvim/testdir/test_messages.vim | 1 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 17 |
14 files changed, 138 insertions, 33 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index c8dd85b39d..cad4c8314f 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -953,6 +953,53 @@ Boolean nvim_buf_is_loaded(Buffer buffer) return buf && buf->b_ml.ml_mfp != NULL; } +/// Deletes the buffer. See |:bwipeout| +/// +/// @param buffer Buffer handle, or 0 for current buffer +/// @param opts Optional parameters. Keys: +/// - force: Force deletion and ignore unsaved changes. +/// - unload: Unloaded only, do not delete. See |:bunload| +void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err) + FUNC_API_SINCE(7) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (ERROR_SET(err)) { + return; + } + + bool force = false; + bool unload = false; + for (size_t i = 0; i < opts.size; i++) { + String k = opts.items[i].key; + Object v = opts.items[i].value; + if (strequal("force", k.data)) { + force = api_coerce_to_bool(v, "force", false, err); + } else if (strequal("unload", k.data)) { + unload = api_coerce_to_bool(v, "unload", false, err); + } else { + api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + return; + } + } + + if (ERROR_SET(err)) { + return; + } + + int result = do_buffer( + unload ? DOBUF_UNLOAD : DOBUF_WIPE, + DOBUF_FIRST, + FORWARD, + buf->handle, + force); + + if (result == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to unload buffer."); + return; + } +} + /// Checks if a buffer is valid. /// /// @note Even if a buffer is valid it may have been unloaded. See |api-buffer| @@ -1394,7 +1441,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, goto error; } } else if (strequal("ephemeral", k.data)) { - ephemeral = api_is_truthy(*v, "ephemeral", false, err); + ephemeral = api_coerce_to_bool(*v, "ephemeral", false, err); if (ERROR_SET(err)) { goto error; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 84517c99fc..981d41ae6e 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1619,14 +1619,24 @@ free_exit: return virt_text; } -bool api_is_truthy(Object obj, const char *what, bool nil_truthy, Error *err) +/// Force obj to bool. +/// If it fails, returns false and sets err +/// @param obj The object to coerce to a boolean +/// @param what The name of the object, used for error message +/// @param nil_value What to return if the type is nil. +/// @param err Set if there was an error in converting to a bool +bool api_coerce_to_bool( + Object obj, + const char *what, + bool nil_value, + Error *err) { if (obj.type == kObjectTypeBoolean) { return obj.data.boolean; } else if (obj.type == kObjectTypeInteger) { return obj.data.integer; // C semantics: non-zero int is true } else if (obj.type == kObjectTypeNil) { - return nil_truthy; // caller decides what NIL (missing retval in lua) means + return nil_value; // caller decides what NIL (missing retval in lua) means } else { api_set_error(err, kErrorTypeValidation, "%s is not an boolean", what); return false; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a2490be355..cccf1e50ff 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -2994,7 +2994,6 @@ char_u *get_user_var_name(expand_T *xp, int idx) static size_t tdone; static size_t vidx; static hashitem_T *hi; - hashtab_T *ht; if (idx == 0) { gdone = bdone = wdone = vidx = 0; @@ -3015,7 +3014,10 @@ char_u *get_user_var_name(expand_T *xp, int idx) } // b: variables - ht = &curbuf->b_vars->dv_hashtab; + // In cmdwin, the alternative buffer should be used. + hashtab_T *ht = (cmdwin_type != 0 && get_cmdline_type() == NUL) + ? &prevwin->w_buffer->b_vars->dv_hashtab + : &curbuf->b_vars->dv_hashtab; if (bdone < ht->ht_used) { if (bdone++ == 0) hi = ht->ht_array; @@ -3027,7 +3029,10 @@ char_u *get_user_var_name(expand_T *xp, int idx) } // w: variables - ht = &curwin->w_vars->dv_hashtab; + // In cmdwin, the alternative window should be used. + ht = (cmdwin_type != 0 && get_cmdline_type() == NUL) + ? &prevwin->w_vars->dv_hashtab + : &curwin->w_vars->dv_hashtab; if (wdone < ht->ht_used) { if (wdone++ == 0) hi = ht->ht_array; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 15e9011d51..d2e9c68965 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8147,15 +8147,17 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// Create quickfix/location list from VimL values /// /// Used by `setqflist()` and `setloclist()` functions. Accepts invalid -/// list_arg, action_arg and what_arg arguments in which case errors out, -/// including VAR_UNKNOWN parameters. +/// args argument in which case errors out, including VAR_UNKNOWN parameters. /// /// @param[in,out] wp Window to create location list for. May be NULL in /// which case quickfix list will be created. -/// @param[in] list_arg Quickfix list contents. -/// @param[in] action_arg Action to perform: append to an existing list, -/// replace its content or create a new one. -/// @param[in] title_arg New list title. Defaults to caller function name. +/// @param[in] args [list, action, what] +/// @param[in] args[0] Quickfix list contents. +/// @param[in] args[1] Optional. Action to perform: +/// append to an existing list, replace its content, +/// or create a new one. +/// @param[in] args[2] Optional. Quickfix list properties or title. +/// Defaults to caller function name. /// @param[out] rettv Return value: 0 in case of success, -1 otherwise. static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) FUNC_ATTR_NONNULL_ARG(2, 3) @@ -8165,7 +8167,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) int action = ' '; static int recursive = 0; rettv->vval.v_number = -1; - dict_T *d = NULL; + dict_T *what = NULL; typval_T *list_arg = &args[0]; if (list_arg->v_type != VAR_LIST) { @@ -8193,18 +8195,18 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) return; } - typval_T *title_arg = &args[2]; - if (title_arg->v_type == VAR_UNKNOWN) { + typval_T *const what_arg = &args[2]; + if (what_arg->v_type == VAR_UNKNOWN) { // Option argument was not given. goto skip_args; - } else if (title_arg->v_type == VAR_STRING) { - title = tv_get_string_chk(title_arg); + } else if (what_arg->v_type == VAR_STRING) { + title = tv_get_string_chk(what_arg); if (!title) { // Type error. Error already printed by tv_get_string_chk(). return; } - } else if (title_arg->v_type == VAR_DICT) { - d = title_arg->vval.v_dict; + } else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) { + what = what_arg->vval.v_dict; } else { EMSG(_(e_dictreq)); return; @@ -8217,7 +8219,7 @@ skip_args: recursive++; list_T *const l = list_arg->vval.v_list; - if (set_errorlist(wp, l, action, (char_u *)title, d) == OK) { + if (set_errorlist(wp, l, action, (char_u *)title, what) == OK) { rettv->vval.v_number = 0; } recursive--; diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4bc5f4a9b8..dc94bc698d 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1052,7 +1052,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ex_nesting_level++; - eval1(&p, rettv, true); + (void)eval1(&p, rettv, true); ex_nesting_level--; } else { // call do_cmdline() to execute the lines diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 71ac542323..211791c19d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5400,7 +5400,7 @@ invalid_count: if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) == FAIL) { return FAIL; } - if (addr_type_arg != ADDR_LINES) { + if (*addr_type_arg != ADDR_LINES) { *argt |= (ZEROR | NOTADR); } } else { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f9ca7bfa42..940f446a7b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -5193,7 +5193,7 @@ ExpandFromContext ( * obtain strings, one by one. The strings are matched against a regexp * program. Matching strings are copied into an array, which is returned. */ -void ExpandGeneric( +static void ExpandGeneric( expand_T *xp, regmatch_T *regmatch, int *num_file, diff --git a/src/nvim/normal.c b/src/nvim/normal.c index a51aa0dc07..1cc400166c 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -6841,7 +6841,7 @@ static void nv_g_cmd(cmdarg_T *cap) } else { if (cap->count1 > 1) { // if it fails, let the cursor still move to the last char - cursor_down(cap->count1 - 1, false); + (void)cursor_down(cap->count1 - 1, false); } i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1; coladvance((colnr_T)i); diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 9cdb2d1404..d2d20852aa 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -919,11 +919,11 @@ void pum_set_event_info(dict_T *dict) r = (double)pum_row; c = (double)pum_col; } - tv_dict_add_float(dict, S_LEN("height"), h); - tv_dict_add_float(dict, S_LEN("width"), w); - tv_dict_add_float(dict, S_LEN("row"), r); - tv_dict_add_float(dict, S_LEN("col"), c); - tv_dict_add_nr(dict, S_LEN("size"), pum_size); - tv_dict_add_bool(dict, S_LEN("scrollbar"), - pum_scrollbar ? kBoolVarTrue : kBoolVarFalse); + (void)tv_dict_add_float(dict, S_LEN("height"), h); + (void)tv_dict_add_float(dict, S_LEN("width"), w); + (void)tv_dict_add_float(dict, S_LEN("row"), r); + (void)tv_dict_add_float(dict, S_LEN("col"), c); + (void)tv_dict_add_nr(dict, S_LEN("size"), pum_size); + (void)tv_dict_add_bool(dict, S_LEN("scrollbar"), + pum_scrollbar ? kBoolVarTrue : kBoolVarFalse); } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 96c903d206..1cd7879dc0 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6317,6 +6317,7 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi) // Populate the quickfix list with the items supplied in the list // of dictionaries. "title" will be copied to w:quickfix_title // "action" is 'a' for add, 'r' for replace. Otherwise create a new list. +// When "what" is not NULL then only set some properties. int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 9f450888a2..df0c5ce791 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -176,7 +176,7 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, textlock--; if (!ERROR_SET(&err) - && api_is_truthy(ret, "provider %s retval", default_true, &err)) { + && api_coerce_to_bool(ret, "provider %s retval", default_true, &err)) { return true; } diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 1339a9f25d..b8632b9595 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -327,7 +327,10 @@ func Test_compl_in_cmdwin() set wildmenu wildchar=<Tab> com! -nargs=1 -complete=command GetInput let input = <q-args> com! -buffer TestCommand echo 'TestCommand' + let w:test_winvar = 'winvar' + let b:test_bufvar = 'bufvar' + " User-defined commands let input = '' call feedkeys("q:iGetInput T\<C-x>\<C-v>\<CR>", 'tx!') call assert_equal('TestCommand', input) @@ -336,8 +339,29 @@ func Test_compl_in_cmdwin() call feedkeys("q::GetInput T\<Tab>\<CR>:q\<CR>", 'tx!') call assert_equal('T', input) + com! -nargs=1 -complete=var GetInput let input = <q-args> + " Window-local variables + let input = '' + call feedkeys("q:iGetInput w:test_\<C-x>\<C-v>\<CR>", 'tx!') + call assert_equal('w:test_winvar', input) + + let input = '' + call feedkeys("q::GetInput w:test_\<Tab>\<CR>:q\<CR>", 'tx!') + call assert_equal('w:test_', input) + + " Buffer-local variables + let input = '' + call feedkeys("q:iGetInput b:test_\<C-x>\<C-v>\<CR>", 'tx!') + call assert_equal('b:test_bufvar', input) + + let input = '' + call feedkeys("q::GetInput b:test_\<Tab>\<CR>:q\<CR>", 'tx!') + call assert_equal('b:test_', input) + delcom TestCommand delcom GetInput + unlet w:test_winvar + unlet b:test_bufvar set wildmenu& wildchar& endfunc diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 7fbf04311d..ca14494248 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -74,6 +74,7 @@ func Test_echomsg() call assert_equal("\n12345", execute(':echomsg 12345')) call assert_equal("\n[]", execute(':echomsg []')) call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]')) + call assert_equal("\n[1, 2, []]", execute(':echomsg [1, 2, v:_null_list]')) call assert_equal("\n{}", execute(':echomsg {}')) call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}')) if has('float') diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2ef9bf5a2e..62d7dc8b18 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -316,7 +316,13 @@ static void terminfo_start(UI *ui) #ifdef WIN32 uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW); #else - uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO); + int retry_count = 10; + // A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a + // few times. #12322 + while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR + && retry_count > 0) { + retry_count--; + } #endif } else { uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0); @@ -1102,6 +1108,15 @@ static void tui_set_mode(UI *ui, ModeShape mode) static void tui_mode_change(UI *ui, String mode, Integer mode_idx) { TUIData *data = ui->data; +#ifdef UNIX + // If stdin is not a TTY, the LHS of pipe may change the state of the TTY + // after calling uv_tty_set_mode. So, set the mode of the TTY again here. + // #13073 + if (data->is_starting && data->input.in_fd == STDERR_FILENO) { + uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL); + uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO); + } +#endif tui_set_mode(ui, (ModeShape)mode_idx); data->is_starting = false; // mode entered, no longer starting data->showing_mode = (ModeShape)mode_idx; |