aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
commit9837de570c5972f98e74848edc97c297a13136ea (patch)
treecc948611912d116a3f98a744e690d3d7b6e2f59a /src/nvim/eval
parentc367400b73d207833d51e09d663f969ffab37531 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.gz
rneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.bz2
rneovim-9837de570c5972f98e74848edc97c297a13136ea.zip
Merge remote-tracking branch 'upstream/master' into colorcolchar
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/buffer.c734
-rw-r--r--src/nvim/eval/buffer.h10
-rw-r--r--src/nvim/eval/decode.c70
-rw-r--r--src/nvim/eval/encode.c53
-rw-r--r--src/nvim/eval/encode.h16
-rw-r--r--src/nvim/eval/executor.c18
-rw-r--r--src/nvim/eval/funcs.c1840
-rw-r--r--src/nvim/eval/funcs.h5
-rw-r--r--src/nvim/eval/gc.c5
-rw-r--r--src/nvim/eval/gc.h1
-rw-r--r--src/nvim/eval/typval.c200
-rw-r--r--src/nvim/eval/typval.h65
-rw-r--r--src/nvim/eval/typval_defs.h6
-rw-r--r--src/nvim/eval/typval_encode.c.h30
-rw-r--r--src/nvim/eval/typval_encode.h2
-rw-r--r--src/nvim/eval/userfunc.c573
-rw-r--r--src/nvim/eval/userfunc.h14
-rw-r--r--src/nvim/eval/vars.c295
-rw-r--r--src/nvim/eval/vars.h2
-rw-r--r--src/nvim/eval/window.c954
-rw-r--r--src/nvim/eval/window.h78
21 files changed, 3069 insertions, 1902 deletions
diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c
new file mode 100644
index 0000000000..2f37d1ba2e
--- /dev/null
+++ b/src/nvim/eval/buffer.c
@@ -0,0 +1,734 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// eval/buffer.c: Buffer related builtin functions
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/change.h"
+#include "nvim/cursor.h"
+#include "nvim/eval.h"
+#include "nvim/eval/buffer.h"
+#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/globals.h"
+#include "nvim/macros.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/move.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
+#include "nvim/sign.h"
+#include "nvim/types.h"
+#include "nvim/undo.h"
+#include "nvim/vim.h"
+
+typedef struct {
+ win_T *cob_curwin_save;
+ aco_save_T cob_aco;
+ int cob_using_aco;
+ int cob_save_VIsual_active;
+} cob_T;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/buffer.c.generated.h"
+#endif
+
+/// Find a buffer by number or exact name.
+buf_T *find_buffer(typval_T *avar)
+{
+ buf_T *buf = NULL;
+
+ if (avar->v_type == VAR_NUMBER) {
+ buf = buflist_findnr((int)avar->vval.v_number);
+ } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
+ buf = buflist_findname_exp(avar->vval.v_string);
+ if (buf == NULL) {
+ // No full path name match, try a match with a URL or a "nofile"
+ // buffer, these don't use the full path.
+ FOR_ALL_BUFFERS(bp) {
+ if (bp->b_fname != NULL
+ && (path_with_url(bp->b_fname) || bt_nofilename(bp))
+ && strcmp(bp->b_fname, avar->vval.v_string) == 0) {
+ buf = bp;
+ break;
+ }
+ }
+ }
+ }
+ return buf;
+}
+
+/// If there is a window for "curbuf", make it the current window.
+static void find_win_for_curbuf(void)
+{
+ wininfo_T *wip;
+
+ // The b_wininfo list should have the windows that recently contained the
+ // buffer, going over this is faster than going over all the windows.
+ // Do check the buffer is still there.
+ FOR_ALL_BUF_WININFO(curbuf, wip) {
+ if (wip->wi_win != NULL && wip->wi_win->w_buffer == curbuf) {
+ curwin = wip->wi_win;
+ break;
+ }
+ }
+}
+
+/// Used before making a change in "buf", which is not the current one: Make
+/// "buf" the current buffer and find a window for this buffer, so that side
+/// effects are done correctly (e.g., adjusting marks).
+///
+/// Information is saved in "cob" and MUST be restored by calling
+/// change_other_buffer_restore().
+static void change_other_buffer_prepare(cob_T *cob, buf_T *buf)
+{
+ CLEAR_POINTER(cob);
+
+ // Set "curbuf" to the buffer being changed. Then make sure there is a
+ // window for it to handle any side effects.
+ cob->cob_save_VIsual_active = VIsual_active;
+ VIsual_active = false;
+ cob->cob_curwin_save = curwin;
+ curbuf = buf;
+ find_win_for_curbuf(); // simplest: find existing window for "buf"
+
+ if (curwin->w_buffer != buf) {
+ // No existing window for this buffer. It is dangerous to have
+ // curwin->w_buffer differ from "curbuf", use the autocmd window.
+ curbuf = curwin->w_buffer;
+ aucmd_prepbuf(&cob->cob_aco, buf);
+ cob->cob_using_aco = true;
+ }
+}
+
+static void change_other_buffer_restore(cob_T *cob)
+{
+ if (cob->cob_using_aco) {
+ aucmd_restbuf(&cob->cob_aco);
+ } else {
+ curwin = cob->cob_curwin_save;
+ curbuf = curwin->w_buffer;
+ }
+ VIsual_active = cob->cob_save_VIsual_active;
+}
+
+/// Set line or list of lines in buffer "buf" to "lines".
+/// Any type is allowed and converted to a string.
+static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_T *lines,
+ typval_T *rettv)
+ FUNC_ATTR_NONNULL_ARG(4, 5)
+{
+ linenr_T lnum = lnum_arg + (append ? 1 : 0);
+ long added = 0;
+
+ // When using the current buffer ml_mfp will be set if needed. Useful when
+ // setline() is used on startup. For other buffers the buffer must be
+ // loaded.
+ const bool is_curbuf = buf == curbuf;
+ if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
+ rettv->vval.v_number = 1; // FAIL
+ return;
+ }
+
+ // After this don't use "return", goto "cleanup"!
+ cob_T cob;
+ if (!is_curbuf) {
+ // set "curbuf" to "buf" and find a window for this buffer
+ change_other_buffer_prepare(&cob, buf);
+ }
+
+ linenr_T append_lnum;
+ if (append) {
+ // appendbufline() uses the line number below which we insert
+ append_lnum = lnum - 1;
+ } else {
+ // setbufline() uses the line number above which we insert, we only
+ // append if it's below the last line
+ append_lnum = curbuf->b_ml.ml_line_count;
+ }
+
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ char *line = NULL;
+ if (lines->v_type == VAR_LIST) {
+ l = lines->vval.v_list;
+ if (l == NULL || tv_list_len(l) == 0) {
+ // set proper return code
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ rettv->vval.v_number = 1; // FAIL
+ }
+ goto cleanup;
+ }
+ li = tv_list_first(l);
+ } else {
+ line = typval_tostring(lines, false);
+ }
+
+ // Default result is zero == OK.
+ for (;;) {
+ if (lines->v_type == VAR_LIST) {
+ // List argument, get next string.
+ if (li == NULL) {
+ break;
+ }
+ xfree(line);
+ line = typval_tostring(TV_LIST_ITEM_TV(li), false);
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+
+ rettv->vval.v_number = 1; // FAIL
+ if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
+ break;
+ }
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (!append && lnum <= curbuf->b_ml.ml_line_count) {
+ // Existing line, replace it.
+ int old_len = (int)strlen(ml_get(lnum));
+ if (u_savesub(lnum) == OK
+ && ml_replace(lnum, line, true) == OK) {
+ inserted_bytes(lnum, 0, old_len, (int)strlen(line));
+ if (is_curbuf && lnum == curwin->w_cursor.lnum) {
+ check_cursor_col();
+ }
+ rettv->vval.v_number = 0; // OK
+ }
+ } else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
+ // append the line.
+ added++;
+ if (ml_append(lnum - 1, line, 0, false) == OK) {
+ rettv->vval.v_number = 0; // OK
+ }
+ }
+
+ if (l == NULL) { // only one string argument
+ break;
+ }
+ lnum++;
+ }
+ xfree(line);
+
+ if (added > 0) {
+ appended_lines_mark(append_lnum, added);
+
+ // Only adjust the cursor for buffers other than the current, unless it
+ // is the current window. For curbuf and other windows it has been done
+ // in mark_adjust_internal().
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf
+ && (wp->w_buffer != curbuf || wp == curwin)
+ && wp->w_cursor.lnum > append_lnum) {
+ wp->w_cursor.lnum += (linenr_T)added;
+ }
+ }
+ check_cursor_col();
+ update_topline(curwin);
+ }
+
+cleanup:
+ if (!is_curbuf) {
+ change_other_buffer_restore(&cob);
+ }
+}
+
+/// "append(lnum, string/list)" function
+void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ const linenr_T lnum = tv_get_lnum(&argvars[0]);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
+ }
+}
+
+/// Set or append lines to a buffer.
+static void buf_set_append_line(typval_T *argvars, typval_T *rettv, bool append)
+{
+ const int did_emsg_before = did_emsg;
+ buf_T *const buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ rettv->vval.v_number = 1; // FAIL
+ } else {
+ const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(buf, lnum, append, &argvars[2], rettv);
+ }
+ }
+}
+
+/// "appendbufline(buf, lnum, string/list)" function
+void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_set_append_line(argvars, rettv, true);
+}
+
+/// "bufadd(expr)" function
+void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ char *name = (char *)tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
+}
+
+/// "bufexists(expr)" function
+void f_bufexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
+}
+
+/// "buflisted(expr)" function
+void f_buflisted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
+}
+
+/// "bufload(expr)" function
+void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
+{
+ buf_T *buf = get_buf_arg(&argvars[0]);
+
+ if (buf != NULL) {
+ buffer_ensure_loaded(buf);
+ }
+}
+
+/// "bufloaded(expr)" function
+void f_bufloaded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *buf;
+
+ buf = find_buffer(&argvars[0]);
+ rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
+}
+
+/// "bufname(expr)" function
+void f_bufname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const buf_T *buf;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ buf = curbuf;
+ } else {
+ buf = tv_get_buf_from_arg(&argvars[0]);
+ }
+ if (buf != NULL && buf->b_fname != NULL) {
+ rettv->vval.v_string = xstrdup(buf->b_fname);
+ }
+}
+
+/// "bufnr(expr)" function
+void f_bufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const buf_T *buf;
+ bool error = false;
+
+ rettv->vval.v_number = -1;
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ buf = curbuf;
+ } else {
+ // Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
+ // and the second argument isn't zero, but we want to return early if the
+ // first argument isn't a string or number so only one error is shown.
+ if (!tv_check_str_or_nr(&argvars[0])) {
+ return;
+ }
+ emsg_off++;
+ buf = tv_get_buf(&argvars[0], false);
+ emsg_off--;
+ }
+
+ // If the buffer isn't found and the second argument is not zero create a
+ // new buffer.
+ const char *name;
+ if (buf == NULL
+ && argvars[1].v_type != VAR_UNKNOWN
+ && tv_get_number_chk(&argvars[1], &error) != 0
+ && !error
+ && (name = tv_get_string_chk(&argvars[0])) != NULL) {
+ buf = buflist_new((char *)name, NULL, 1, 0);
+ }
+
+ if (buf != NULL) {
+ rettv->vval.v_number = buf->b_fnum;
+ }
+}
+
+static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
+{
+ const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
+ if (buf == NULL) { // no need to search if invalid arg or buffer not found
+ rettv->vval.v_number = -1;
+ return;
+ }
+
+ int winnr = 0;
+ int winid;
+ bool found_buf = false;
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ winnr++;
+ if (wp->w_buffer == buf) {
+ found_buf = true;
+ winid = wp->handle;
+ break;
+ }
+ }
+ rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
+}
+
+/// "bufwinid(nr)" function
+void f_bufwinid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_win_common(argvars, rettv, false);
+}
+
+/// "bufwinnr(nr)" function
+void f_bufwinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_win_common(argvars, rettv, true);
+}
+
+/// "deletebufline()" function
+void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ rettv->vval.v_number = 1; // FAIL by default
+ buf_T *const buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
+
+ linenr_T last;
+ const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ last = tv_get_lnum_buf(&argvars[2], buf);
+ } else {
+ last = first;
+ }
+
+ if (buf->b_ml.ml_mfp == NULL || first < 1
+ || first > buf->b_ml.ml_line_count || last < first) {
+ return;
+ }
+
+ // After this don't use "return", goto "cleanup"!
+ const bool is_curbuf = buf == curbuf;
+ cob_T cob;
+ if (!is_curbuf) {
+ // set "curbuf" to "buf" and find a window for this buffer
+ change_other_buffer_prepare(&cob, buf);
+ }
+
+ if (last > curbuf->b_ml.ml_line_count) {
+ last = curbuf->b_ml.ml_line_count;
+ }
+ const long count = last - first + 1;
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (u_save(first - 1, last + 1) == FAIL) {
+ goto cleanup;
+ }
+
+ for (linenr_T lnum = first; lnum <= last; lnum++) {
+ ml_delete(first, true);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ if (wp->w_cursor.lnum > last) {
+ wp->w_cursor.lnum -= (linenr_T)count;
+ } else if (wp->w_cursor.lnum > first) {
+ wp->w_cursor.lnum = first;
+ }
+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
+ wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
+ }
+ }
+ }
+ check_cursor_col();
+ deleted_lines_mark(first, count);
+ rettv->vval.v_number = 0; // OK
+
+cleanup:
+ if (!is_curbuf) {
+ change_other_buffer_restore(&cob);
+ }
+}
+
+/// @return buffer options, variables and other attributes in a dictionary.
+static dict_T *get_buffer_info(buf_T *buf)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("bufnr"), buf->b_fnum);
+ tv_dict_add_str(dict, S_LEN("name"),
+ buf->b_ffname != NULL ? (const char *)buf->b_ffname : "");
+ tv_dict_add_nr(dict, S_LEN("lnum"),
+ buf == curbuf ? curwin->w_cursor.lnum : buflist_findlnum(buf));
+ tv_dict_add_nr(dict, S_LEN("linecount"), buf->b_ml.ml_line_count);
+ tv_dict_add_nr(dict, S_LEN("loaded"), buf->b_ml.ml_mfp != NULL);
+ tv_dict_add_nr(dict, S_LEN("listed"), buf->b_p_bl);
+ tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
+ tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
+ tv_dict_add_nr(dict, S_LEN("hidden"),
+ buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
+
+ // Get a reference to buffer variables
+ tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
+
+ // List of windows displaying this buffer
+ list_T *const windows = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == buf) {
+ tv_list_append_number(windows, (varnumber_T)wp->handle);
+ }
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), windows);
+
+ if (buf->b_signlist != NULL) {
+ // List of signs placed in this buffer
+ tv_dict_add_list(dict, S_LEN("signs"), get_buffer_signs(buf));
+ }
+
+ tv_dict_add_nr(dict, S_LEN("lastused"), buf->b_last_used);
+
+ return dict;
+}
+
+/// "getbufinfo()" function
+void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_T *argbuf = NULL;
+ bool filtered = false;
+ bool sel_buflisted = false;
+ bool sel_bufloaded = false;
+ bool sel_bufmodified = false;
+
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ // List of all the buffers or selected buffers
+ if (argvars[0].v_type == VAR_DICT) {
+ dict_T *sel_d = argvars[0].vval.v_dict;
+
+ if (sel_d != NULL) {
+ dictitem_T *di;
+
+ filtered = true;
+
+ di = tv_dict_find(sel_d, S_LEN("buflisted"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_buflisted = true;
+ }
+
+ di = tv_dict_find(sel_d, S_LEN("bufloaded"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_bufloaded = true;
+ }
+ di = tv_dict_find(sel_d, S_LEN("bufmodified"));
+ if (di != NULL && tv_get_number(&di->di_tv)) {
+ sel_bufmodified = true;
+ }
+ }
+ } else if (argvars[0].v_type != VAR_UNKNOWN) {
+ // Information about one buffer. Argument specifies the buffer
+ argbuf = tv_get_buf_from_arg(&argvars[0]);
+ if (argbuf == NULL) {
+ return;
+ }
+ }
+
+ // Return information about all the buffers or a specified buffer
+ FOR_ALL_BUFFERS(buf) {
+ if (argbuf != NULL && argbuf != buf) {
+ continue;
+ }
+ if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
+ || (sel_buflisted && !buf->b_p_bl)
+ || (sel_bufmodified && !buf->b_changed))) {
+ continue;
+ }
+
+ dict_T *const d = get_buffer_info(buf);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (argbuf != NULL) {
+ return;
+ }
+ }
+}
+
+/// Get line or list of lines from buffer "buf" into "rettv".
+///
+/// @param retlist if true, then the lines are returned as a Vim List.
+///
+/// @return range (from start to end) of lines in rettv from the specified
+/// buffer.
+static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
+{
+ rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
+ rettv->vval.v_string = NULL;
+
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
+ if (retlist) {
+ tv_list_alloc_ret(rettv, 0);
+ }
+ return;
+ }
+
+ if (retlist) {
+ if (start < 1) {
+ start = 1;
+ }
+ if (end > buf->b_ml.ml_line_count) {
+ end = buf->b_ml.ml_line_count;
+ }
+ tv_list_alloc_ret(rettv, end - start + 1);
+ while (start <= end) {
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)ml_get_buf(buf, start++, false), -1);
+ }
+ } else {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count)
+ ? xstrdup(ml_get_buf(buf, start, false)) : NULL);
+ }
+}
+
+/// @param retlist true: "getbufline()" function
+/// false: "getbufoneline()" function
+static void getbufline(typval_T *argvars, typval_T *rettv, bool retlist)
+{
+ const int did_emsg_before = did_emsg;
+ buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
+ const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
+ const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
+ ? lnum
+ : tv_get_lnum_buf(&argvars[2], buf));
+
+ get_buffer_lines(buf, lnum, end, retlist, rettv);
+}
+
+/// "getbufline()" function
+void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ getbufline(argvars, rettv, true);
+}
+
+/// "getbufoneline()" function
+void f_getbufoneline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ getbufline(argvars, rettv, false);
+}
+
+/// "getline(lnum, [end])" function
+void f_getline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ linenr_T end;
+ bool retlist;
+
+ const linenr_T lnum = tv_get_lnum(argvars);
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ end = lnum;
+ retlist = false;
+ } else {
+ end = tv_get_lnum(&argvars[1]);
+ retlist = true;
+ }
+
+ get_buffer_lines(curbuf, lnum, end, retlist, rettv);
+}
+
+/// "setbufline()" function
+void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_set_append_line(argvars, rettv, false);
+}
+
+/// "setline()" function
+void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ const int did_emsg_before = did_emsg;
+ linenr_T lnum = tv_get_lnum(&argvars[0]);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
+ }
+}
+
+/// Make "buf" the current buffer.
+///
+/// restore_buffer() MUST be called to undo.
+/// No autocommands will be executed. Use aucmd_prepbuf() if there are any.
+void switch_buffer(bufref_T *save_curbuf, buf_T *buf)
+{
+ block_autocmds();
+ set_bufref(save_curbuf, curbuf);
+ curbuf->b_nwindows--;
+ curbuf = buf;
+ curwin->w_buffer = buf;
+ curbuf->b_nwindows++;
+}
+
+/// Restore the current buffer after using switch_buffer().
+void restore_buffer(bufref_T *save_curbuf)
+{
+ unblock_autocmds();
+ // Check for valid buffer, just in case.
+ if (bufref_valid(save_curbuf)) {
+ curbuf->b_nwindows--;
+ curwin->w_buffer = save_curbuf->br_buf;
+ curbuf = save_curbuf->br_buf;
+ curbuf->b_nwindows++;
+ }
+}
+
+/// Find a window for buffer "buf".
+/// If found true is returned and "wp" and "tp" are set to
+/// the window and tabpage.
+/// If not found, false is returned.
+///
+/// @param buf buffer to find a window for
+/// @param[out] wp stores the found window
+/// @param[out] tp stores the found tabpage
+///
+/// @return true if a window was found for the buffer.
+bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
+{
+ *wp = NULL;
+ *tp = NULL;
+ FOR_ALL_TAB_WINDOWS(tp2, wp2) {
+ if (wp2->w_buffer == buf) {
+ *tp = tp2;
+ *wp = wp2;
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/nvim/eval/buffer.h b/src/nvim/eval/buffer.h
new file mode 100644
index 0000000000..4a2f8f9e94
--- /dev/null
+++ b/src/nvim/eval/buffer.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_EVAL_BUFFER_H
+#define NVIM_EVAL_BUFFER_H
+
+#include "nvim/buffer_defs.h"
+#include "nvim/eval/typval_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/buffer.h.generated.h"
+#endif
+#endif // NVIM_EVAL_BUFFER_H
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 94ef419bed..cd1479f150 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -1,20 +1,31 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include <msgpack.h>
+#include <assert.h>
+#include <msgpack/object.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
#include "klib/kvec.h"
#include "nvim/ascii.h"
-#include "nvim/charset.h" // vim_str2nr
+#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
-#include "nvim/globals.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/hashtab.h"
#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/vim.h" // OK, FAIL
+#include "nvim/types.h"
+#include "nvim/vim.h"
/// Helper structure for container_struct
typedef struct {
@@ -271,11 +282,9 @@ typval_T decode_string(const char *const s, const size_t len, const TriState has
list_T *const list = tv_list_alloc(kListLenMayKnow);
tv_list_ref(list);
create_special_dict(&tv, kMPString,
- ((typval_T){
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
+ (typval_T){ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list } });
const int elw_ret = encode_list_write((void *)list, s, len);
if (s_allocated) {
xfree((void *)s);
@@ -286,13 +295,12 @@ typval_T decode_string(const char *const s, const size_t len, const TriState has
}
}
return tv;
- } else {
- return (typval_T) {
- .v_type = VAR_STRING,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_string = ((s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
- };
}
+ return (typval_T) {
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_string = ((s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
+ };
}
/// Parse JSON double-quoted string
@@ -368,7 +376,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
goto parse_json_string_fail;
}
} else {
- uint8_t p_byte = (uint8_t)*p;
+ uint8_t p_byte = (uint8_t)(*p);
// unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
if (p_byte < 0x20) {
semsg(_("E474: ASCII control characters cannot be present "
@@ -469,7 +477,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
['r'] = CAR,
['f'] = FF,
};
- *str_end++ = escapes[(int)*t];
+ *str_end++ = escapes[(int)(*t)];
break;
}
default:
@@ -838,12 +846,10 @@ json_decode_string_cycle_start:
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
};
- kv_push(container_stack, ((ContainerStackItem) {
- .stack_index = kv_size(stack),
- .s = p,
- .container = tv,
- .special_val = NULL,
- }));
+ kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = NULL }));
kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
@@ -862,12 +868,10 @@ json_decode_string_cycle_start:
.vval = { .v_dict = dict },
};
}
- kv_push(container_stack, ((ContainerStackItem) {
- .stack_index = kv_size(stack),
- .s = p,
- .container = tv,
- .special_val = val_list,
- }));
+ kv_push(container_stack, ((ContainerStackItem) { .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = val_list }));
kv_push(stack, OBJ(tv, false, didcomma, didcolon));
break;
}
@@ -1089,11 +1093,9 @@ msgpack_to_vim_generic_map: {}
tv_list_append_number(list, mobj.via.ext.type);
list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
tv_list_append_list(list, ext_val_list);
- create_special_dict(rettv, kMPExt, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
+ create_special_dict(rettv, kMPExt, ((typval_T) { .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list } }));
if (encode_list_write((void *)ext_val_list, mobj.via.ext.ptr,
mobj.via.ext.size) == -1) {
return FAIL;
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 27d35ea24f..c2f1eae8af 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -10,23 +10,28 @@
#include <assert.h>
#include <inttypes.h>
#include <math.h>
-#include <msgpack.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
#include "klib/kvec.h"
+#include "msgpack/pack.h"
#include "nvim/ascii.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/charset.h" // vim_isprintc()
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/hashtab.h"
#include "nvim/macros.h"
#include "nvim/math.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/vim.h" // For _()
const char *const encode_bool_var_names[] = {
@@ -131,35 +136,35 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
typval_T key_tv = {
.v_type = VAR_STRING,
.vval = { .v_string =
- (char *)(v.data.d.hi ==
- NULL ? v.data.d.dict->dv_hashtab.ht_array : (v.data.d.hi -
- 1))->hi_key },
+ (v.data.d.hi ==
+ NULL ? v.data.d.dict->dv_hashtab.ht_array : (v.data.d.hi -
+ 1))->hi_key },
};
char *const key = encode_tv2string(&key_tv, NULL);
- vim_snprintf((char *)IObuff, IOSIZE, key_msg, key);
+ vim_snprintf(IObuff, IOSIZE, key_msg, key);
xfree(key);
- ga_concat(&msg_ga, (char *)IObuff);
+ ga_concat(&msg_ga, IObuff);
break;
}
case kMPConvPairs:
case kMPConvList: {
const int idx = (v.data.l.li == tv_list_first(v.data.l.list)
- ? 0
- : (v.data.l.li == NULL
- ? tv_list_len(v.data.l.list) - 1
- : (int)tv_list_idx_of_item(v.data.l.list,
- TV_LIST_ITEM_PREV(v.data.l.list,
- v.data.l.li))));
+ ? 0
+ : (v.data.l.li == NULL
+ ? tv_list_len(v.data.l.list) - 1
+ : (int)tv_list_idx_of_item(v.data.l.list,
+ TV_LIST_ITEM_PREV(v.data.l.list,
+ v.data.l.li))));
const listitem_T *const li = (v.data.l.li == NULL
- ? tv_list_last(v.data.l.list)
- : TV_LIST_ITEM_PREV(v.data.l.list,
- v.data.l.li));
+ ? tv_list_last(v.data.l.list)
+ : TV_LIST_ITEM_PREV(v.data.l.list,
+ v.data.l.li));
if (v.type == kMPConvList
|| li == NULL
|| (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
&& tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
- vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
- ga_concat(&msg_ga, (char *)IObuff);
+ vim_snprintf(IObuff, IOSIZE, idx_msg, idx);
+ ga_concat(&msg_ga, IObuff);
} else {
assert(li != NULL);
listitem_T *const first_item =
@@ -167,9 +172,9 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
assert(first_item != NULL);
typval_T key_tv = *TV_LIST_ITEM_TV(first_item);
char *const key = encode_tv2echo(&key_tv, NULL);
- vim_snprintf((char *)IObuff, IOSIZE, key_pair_msg, key, idx);
+ vim_snprintf(IObuff, IOSIZE, key_pair_msg, key, idx);
xfree(key);
- ga_concat(&msg_ga, (char *)IObuff);
+ ga_concat(&msg_ga, IObuff);
}
break;
}
@@ -188,8 +193,8 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
break;
case kMPConvPartialList: {
const int idx = (int)(v.data.a.arg - v.data.a.argv) - 1;
- vim_snprintf((char *)IObuff, IOSIZE, partial_arg_i_msg, idx);
- ga_concat(&msg_ga, (char *)IObuff);
+ vim_snprintf(IObuff, IOSIZE, partial_arg_i_msg, idx);
+ ga_concat(&msg_ga, IObuff);
break;
}
}
@@ -304,7 +309,7 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
if (buf_[i_] == '\'') { \
ga_append(gap, '\''); \
} \
- ga_append(gap, buf_[i_]); \
+ ga_append(gap, (uint8_t)buf_[i_]); \
} \
ga_append(gap, '\''); \
} \
diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h
index 8755ff48ac..41e7614fc0 100644
--- a/src/nvim/eval/encode.h
+++ b/src/nvim/eval/encode.h
@@ -2,11 +2,15 @@
#define NVIM_EVAL_ENCODE_H
#include <msgpack.h>
+#include <msgpack/pack.h>
#include <stddef.h>
+#include <string.h>
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/garray.h"
-#include "nvim/vim.h" // For STRLEN
+#include "nvim/vim.h"
/// Convert VimL value to msgpack string
///
@@ -15,9 +19,7 @@
/// @param[in] objname Object name, used for error message.
///
/// @return OK in case of success, FAIL otherwise.
-int encode_vim_to_msgpack(msgpack_packer *const packer,
- typval_T *const tv,
- const char *const objname);
+int encode_vim_to_msgpack(msgpack_packer *packer, typval_T *tv, const char *objname);
/// Convert VimL value to :echo output
///
@@ -26,9 +28,7 @@ int encode_vim_to_msgpack(msgpack_packer *const packer,
/// @param[in] objname Object name, used for error message.
///
/// @return OK in case of success, FAIL otherwise.
-int encode_vim_to_echo(garray_T *const packer,
- typval_T *const tv,
- const char *const objname);
+int encode_vim_to_echo(garray_T *packer, typval_T *tv, const char *objname);
/// Structure defining state for read_from_list()
typedef struct {
@@ -48,7 +48,7 @@ static inline ListReaderState encode_init_lrstate(const list_T *const list)
.offset = 0,
.li_length = (TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string == NULL
? 0
- : STRLEN(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
+ : strlen(TV_LIST_ITEM_TV(tv_list_first(list))->vval.v_string)),
};
}
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index 0e0d0fe696..9caea2fef1 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -1,15 +1,23 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <inttypes.h>
+#include <stdlib.h>
+
#include "nvim/eval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/message.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/executor.c.generated.h"
+# include "eval/executor.c.generated.h" // IWYU pragma: export
#endif
char *e_listidx = N_("E684: list index out of range: %" PRId64);
@@ -43,7 +51,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
blob_T *const b1 = tv1->vval.v_blob;
blob_T *const b2 = tv2->vval.v_blob;
for (int i = 0; i < tv_blob_len(b2); i++) {
- ga_append(&b1->bv_ga, (char)tv_blob_get(b2, i));
+ ga_append(&b1->bv_ga, tv_blob_get(b2, i));
}
}
return OK;
@@ -61,7 +69,7 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
if (tv2->v_type == VAR_LIST) {
break;
}
- if (vim_strchr("+-*/%", *op) != NULL) {
+ if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
// nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
@@ -122,8 +130,8 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *cons
break;
}
const float_T f = (tv2->v_type == VAR_FLOAT
- ? tv2->vval.v_float
- : (float_T)tv_get_number(tv2));
+ ? tv2->vval.v_float
+ : (float_T)tv_get_number(tv2));
switch (*op) {
case '+':
tv1->vval.v_float += f; break;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index a326c44371..5a31288ecd 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1,27 +1,44 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <assert.h>
+#include <fcntl.h>
#include <float.h>
+#include <inttypes.h>
+#include <limits.h>
#include <math.h>
-
+#include <msgpack/object.h>
+#include <msgpack/pack.h>
+#include <msgpack/unpack.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <uv.h>
+
+#include "auto/config.h"
#include "nvim/api/private/converter.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
-#include "nvim/arglist.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
-#include "nvim/change.h"
+#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
-#include "nvim/cmdhist.h"
#include "nvim/context.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
-#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/buffer.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
@@ -29,55 +46,72 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
+#include "nvim/event/process.h"
+#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/file_search.h"
#include "nvim/fileio.h"
-#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
+#include "nvim/hashtab.h"
+#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
-#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/input.h"
-#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
-#include "nvim/mapping.h"
+#include "nvim/main.h"
#include "nvim/mark.h"
-#include "nvim/match.h"
#include "nvim/math.h"
+#include "nvim/mbyte.h"
+#include "nvim/memfile_defs.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/menu.h"
+#include "nvim/message.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/msgpack_rpc/server.h"
+#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/optionstr.h"
#include "nvim/os/dl.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/fs_defs.h"
+#include "nvim/os/os.h"
+#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
+#include "nvim/os/stdpaths_defs.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/plines.h"
#include "nvim/popupmenu.h"
+#include "nvim/pos.h"
#include "nvim/profile.h"
-#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sha256.h"
-#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/spellsuggest.h"
#include "nvim/state.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/testing.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/version.h"
@@ -106,6 +140,7 @@ typedef enum {
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
# include "funcs.generated.h"
+
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
#endif
@@ -113,6 +148,8 @@ PRAGMA_DIAG_POP
static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number");
static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
+static char e_using_number_as_bool_nr[]
+ = N_("E1023: Using a Number as a Bool: %d");
/// Dummy va_list for passing to vim_snprintf
///
@@ -132,13 +169,13 @@ char *get_function_name(expand_T *xp, int idx)
intidx = -1;
}
if (intidx < 0) {
- char_u *name = (char_u *)get_user_func_name(xp, idx);
+ char *name = get_user_func_name(xp, idx);
if (name != NULL) {
if (*name != NUL && *name != '<'
- && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
- return cat_prefix_varname('g', (char *)name);
+ && strncmp("g:", xp->xp_pattern, 2) == 0) {
+ return cat_prefix_varname('g', name);
}
- return (char *)name;
+ return name;
}
}
@@ -155,7 +192,7 @@ char *get_function_name(expand_T *xp, int idx)
} else {
IObuff[key_len + 1] = NUL;
}
- return (char *)IObuff;
+ return IObuff;
}
/// Function given to ExpandGeneric() to obtain the list of internal or
@@ -168,9 +205,9 @@ char *get_expr_name(expand_T *xp, int idx)
intidx = -1;
}
if (intidx < 0) {
- char_u *name = (char_u *)get_function_name(xp, idx);
+ char *name = get_function_name(xp, idx);
if (name != NULL) {
- return (char *)name;
+ return name;
}
}
return get_user_var_name(xp, ++intidx);
@@ -189,11 +226,11 @@ const EvalFuncDef *find_internal_func(const char *const name)
return index >= 0 ? &functions[index] : NULL;
}
-int call_internal_func(const char_u *const fname, const int argcount, typval_T *const argvars,
+int call_internal_func(const char *const fname, const int argcount, typval_T *const argvars,
typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL
{
- const EvalFuncDef *const fdef = find_internal_func((const char *)fname);
+ const EvalFuncDef *const fdef = find_internal_func(fname);
if (fdef == NULL) {
return FCERR_UNKNOWN;
} else if (argcount < fdef->min_argc) {
@@ -207,11 +244,11 @@ int call_internal_func(const char_u *const fname, const int argcount, typval_T *
}
/// Invoke a method for base->method().
-int call_internal_method(const char_u *const fname, const int argcount, typval_T *const argvars,
+int call_internal_method(const char *const fname, const int argcount, typval_T *const argvars,
typval_T *const rettv, typval_T *const basetv)
FUNC_ATTR_NONNULL_ALL
{
- const EvalFuncDef *const fdef = find_internal_func((const char *)fname);
+ const EvalFuncDef *const fdef = find_internal_func(fname);
if (fdef == NULL) {
return FCERR_UNKNOWN;
} else if (fdef->base_arg == BASE_NONE) {
@@ -325,20 +362,20 @@ static void f_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = 1; // Default: failed.
if (argvars[0].v_type == VAR_LIST) {
list_T *const l = argvars[0].vval.v_list;
- if (!var_check_lock(tv_list_locked(l), N_("add() argument"),
- TV_TRANSLATE)) {
+ if (!value_check_lock(tv_list_locked(l), N_("add() argument"),
+ TV_TRANSLATE)) {
tv_list_append_tv(l, &argvars[1]);
tv_copy(&argvars[0], rettv);
}
} else if (argvars[0].v_type == VAR_BLOB) {
blob_T *const b = argvars[0].vval.v_blob;
if (b != NULL
- && !var_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
+ && !value_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
bool error = false;
const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
if (!error) {
- ga_append(&b->bv_ga, (char)n);
+ ga_append(&b->bv_ga, (uint8_t)n);
tv_copy(&argvars[0], rettv);
}
}
@@ -361,26 +398,6 @@ static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
(void)object_to_vim(DICTIONARY_OBJ(metadata), rettv, NULL);
}
-/// "append(lnum, string/list)" function
-static void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- const linenr_T lnum = tv_get_lnum(&argvars[0]);
-
- set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
-}
-
-/// "appendbufline(buf, lnum, string/list)" function
-static void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *const buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, true, &argvars[2], rettv);
- }
-}
-
/// "atan2()" function
static void f_atan2(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -408,166 +425,6 @@ static void f_browsedir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
f_browse(argvars, rettv, fptr);
}
-/// Find a buffer by number or exact name.
-static buf_T *find_buffer(typval_T *avar)
-{
- buf_T *buf = NULL;
-
- if (avar->v_type == VAR_NUMBER) {
- buf = buflist_findnr((int)avar->vval.v_number);
- } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
- buf = buflist_findname_exp(avar->vval.v_string);
- if (buf == NULL) {
- // No full path name match, try a match with a URL or a "nofile"
- // buffer, these don't use the full path.
- FOR_ALL_BUFFERS(bp) {
- if (bp->b_fname != NULL
- && (path_with_url(bp->b_fname) || bt_nofilename(bp))
- && strcmp(bp->b_fname, avar->vval.v_string) == 0) {
- buf = bp;
- break;
- }
- }
- }
- }
- return buf;
-}
-
-/// "bufadd(expr)" function
-static void f_bufadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- char_u *name = (char_u *)tv_get_string(&argvars[0]);
-
- rettv->vval.v_number = buflist_add(*name == NUL ? NULL : (char *)name, 0);
-}
-
-/// "bufexists(expr)" function
-static void f_bufexists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
-}
-
-/// "buflisted(expr)" function
-static void f_buflisted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *buf;
-
- buf = find_buffer(&argvars[0]);
- rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
-}
-
-/// "bufload(expr)" function
-static void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
-{
- buf_T *buf = get_buf_arg(&argvars[0]);
-
- if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
- aco_save_T aco;
-
- aucmd_prepbuf(&aco, buf);
- swap_exists_action = SEA_NONE;
- open_buffer(false, NULL, 0);
- aucmd_restbuf(&aco);
- }
-}
-
-/// "bufloaded(expr)" function
-static void f_bufloaded(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *buf;
-
- buf = find_buffer(&argvars[0]);
- rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
-}
-
-/// "bufname(expr)" function
-static void f_bufname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- const buf_T *buf;
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- if (argvars[0].v_type == VAR_UNKNOWN) {
- buf = curbuf;
- } else {
- buf = tv_get_buf_from_arg(&argvars[0]);
- }
- if (buf != NULL && buf->b_fname != NULL) {
- rettv->vval.v_string = xstrdup(buf->b_fname);
- }
-}
-
-/// "bufnr(expr)" function
-static void f_bufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- const buf_T *buf;
- bool error = false;
-
- rettv->vval.v_number = -1;
-
- if (argvars[0].v_type == VAR_UNKNOWN) {
- buf = curbuf;
- } else {
- // Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found
- // and the second argument isn't zero, but we want to return early if the
- // first argument isn't a string or number so only one error is shown.
- if (!tv_check_str_or_nr(&argvars[0])) {
- return;
- }
- emsg_off++;
- buf = tv_get_buf(&argvars[0], false);
- emsg_off--;
- }
-
- // If the buffer isn't found and the second argument is not zero create a
- // new buffer.
- const char *name;
- if (buf == NULL
- && argvars[1].v_type != VAR_UNKNOWN
- && tv_get_number_chk(&argvars[1], &error) != 0
- && !error
- && (name = tv_get_string_chk(&argvars[0])) != NULL) {
- buf = buflist_new((char *)name, NULL, 1, 0);
- }
-
- if (buf != NULL) {
- rettv->vval.v_number = buf->b_fnum;
- }
-}
-
-static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)
-{
- const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
- if (buf == NULL) { // no need to search if invalid arg or buffer not found
- rettv->vval.v_number = -1;
- return;
- }
-
- int winnr = 0;
- int winid;
- bool found_buf = false;
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- winnr++;
- if (wp->w_buffer == buf) {
- found_buf = true;
- winid = wp->handle;
- break;
- }
- }
- rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1);
-}
-
-/// "bufwinid(nr)" function
-static void f_bufwinid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_win_common(argvars, rettv, false);
-}
-
-/// "bufwinnr(nr)" function
-static void f_bufwinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_win_common(argvars, rettv, true);
-}
-
/// Get buffer by number or pattern.
buf_T *tv_get_buf(typval_T *tv, int curtab_only)
{
@@ -578,7 +435,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
return NULL;
}
- char_u *name = (char_u *)tv->vval.v_string;
+ char *name = tv->vval.v_string;
if (name == NULL || *name == NUL) {
return curbuf;
@@ -593,7 +450,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)
char *save_cpo = p_cpo;
p_cpo = empty_option;
- buf_T *buf = buflist_findnr(buflist_findpat((char *)name, (char *)name + STRLEN(name),
+ buf_T *buf = buflist_findnr(buflist_findpat(name, name + strlen(name),
true, false, curtab_only));
p_magic = save_magic;
@@ -691,19 +548,19 @@ static void f_call(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
bool owned = false;
- char_u *func;
+ char *func;
partial_T *partial = NULL;
if (argvars[0].v_type == VAR_FUNC) {
- func = (char_u *)argvars[0].vval.v_string;
+ func = argvars[0].vval.v_string;
} else if (argvars[0].v_type == VAR_PARTIAL) {
partial = argvars[0].vval.v_partial;
- func = (char_u *)partial_name(partial);
+ func = partial_name(partial);
} else if (nlua_is_table_from_lua(&argvars[0])) {
// TODO(tjdevries): UnifiedCallback
func = nlua_register_table_as_callable(&argvars[0]);
owned = true;
} else {
- func = (char_u *)tv_get_string(&argvars[0]);
+ func = (char *)tv_get_string(&argvars[0]);
}
if (*func == NUL) {
@@ -791,6 +648,14 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ptrdiff_t input_len = 0;
char *input = NULL;
+ uint64_t id = (uint64_t)argvars[0].vval.v_number;
+#ifdef UNIX
+ bool crlf = false;
+#else
+ Channel *chan = find_channel(id);
+ bool crlf = (chan != NULL && chan->term) ? true: false;
+#endif
+
if (argvars[1].v_type == VAR_BLOB) {
const blob_T *const b = argvars[1].vval.v_blob;
input_len = tv_blob_len(b);
@@ -798,7 +663,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
input = xmemdup(b->bv_ga.ga_data, (size_t)input_len);
}
} else {
- input = save_tv_as_string(&argvars[1], &input_len, false);
+ input = save_tv_as_string(&argvars[1], &input_len, false, crlf);
}
if (!input) {
@@ -806,7 +671,6 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// or there is no input to send.
return;
}
- uint64_t id = (uint64_t)argvars[0].vval.v_number;
const char *error = NULL;
rettv->vval.v_number = (varnumber_T)channel_send(id, input, (size_t)input_len, true, &error);
if (error) {
@@ -832,9 +696,32 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// otherwise the byte index of the column.
static void get_col(typval_T *argvars, typval_T *rettv, bool charcol)
{
+ if (tv_check_for_string_or_list_arg(argvars, 0) == FAIL
+ || tv_check_for_opt_number_arg(argvars, 1) == FAIL) {
+ return;
+ }
+
+ switchwin_T switchwin;
+ bool winchanged = false;
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ // use the window specified in the second argument
+ tabpage_T *tp;
+ win_T *wp = win_id2wp_tp((int)tv_get_number(&argvars[1]), &tp);
+ if (wp == NULL || tp == NULL) {
+ return;
+ }
+
+ if (switch_win_noblock(&switchwin, wp, tp, true) != OK) {
+ return;
+ }
+
+ check_cursor();
+ winchanged = true;
+ }
+
colnr_T col = 0;
int fnum = curbuf->b_fnum;
-
pos_T *fp = var2fpos(&argvars[0], false, &fnum, charcol);
if (fp != NULL && fnum == curbuf->b_fnum) {
if (fp->col == MAXCOL) {
@@ -862,6 +749,10 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol)
}
}
rettv->vval.v_number = col;
+
+ if (winchanged) {
+ restore_win_noblock(&switchwin, true);
+ }
}
/// "charcol()" function
@@ -894,7 +785,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
countcc = (int)tv_get_number(&argvars[2]);
}
if (countcc < 0 || countcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), countcc);
return;
}
@@ -931,7 +822,7 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// Return the current directory
char *cwd = xmalloc(MAXPATHL);
- if (os_dirname((char_u *)cwd, MAXPATHL) != FAIL) {
+ if (os_dirname(cwd, MAXPATHL) != FAIL) {
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(cwd);
#endif
@@ -968,14 +859,14 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
win_T *get_optional_window(typval_T *argvars, int idx)
{
- win_T *win = curwin;
+ if (argvars[idx].v_type == VAR_UNKNOWN) {
+ return curwin;
+ }
- if (argvars[idx].v_type != VAR_UNKNOWN) {
- win = find_win_by_nr_or_id(&argvars[idx]);
- if (win == NULL) {
- emsg(_(e_invalwindow));
- return NULL;
- }
+ win_T *win = find_win_by_nr_or_id(&argvars[idx]);
+ if (win == NULL) {
+ emsg(_(e_invalwindow));
+ return NULL;
}
return win;
}
@@ -1057,12 +948,12 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
if (argvars[0].v_type == VAR_STRING) {
- const char_u *expr = (char_u *)tv_get_string_chk(&argvars[1]);
- const char_u *p = (char_u *)argvars[0].vval.v_string;
+ const char *expr = tv_get_string_chk(&argvars[1]);
+ const char *p = argvars[0].vval.v_string;
if (!error && expr != NULL && *expr != NUL && p != NULL) {
if (ic) {
- const size_t len = STRLEN(expr);
+ const size_t len = strlen(expr);
while (*p != NUL) {
if (mb_strnicmp((char *)p, (char *)expr, len) == 0) {
@@ -1073,10 +964,10 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
} else {
- char_u *next;
- while ((next = (char_u *)strstr((char *)p, (char *)expr)) != NULL) {
+ char *next;
+ while ((next = strstr((char *)p, (char *)expr)) != NULL) {
n++;
- p = next + STRLEN(expr);
+ p = next + strlen(expr);
}
}
}
@@ -1132,29 +1023,6 @@ static void f_count(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = n;
}
-/// "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
-///
-/// Checks the existence of a cscope connection.
-static void f_cscope_connection(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- int num = 0;
- const char *dbpath = NULL;
- const char *prepend = NULL;
- char buf[NUMBUFLEN];
-
- if (argvars[0].v_type != VAR_UNKNOWN
- && argvars[1].v_type != VAR_UNKNOWN) {
- num = (int)tv_get_number(&argvars[0]);
- dbpath = tv_get_string(&argvars[1]);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- prepend = tv_get_string_buf(&argvars[2], buf);
- }
- }
-
- rettv->vval.v_number = cs_connection(num, (char_u *)dbpath,
- (char_u *)prepend);
-}
-
/// "ctxget([{index}])" function
static void f_ctxget(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -1348,19 +1216,21 @@ static void f_debugbreak(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int pid = (int)tv_get_number(&argvars[0]);
if (pid == 0) {
emsg(_(e_invarg));
- } else {
+ return;
+ }
+
#ifdef MSWIN
- HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ if (hProcess == NULL) {
+ return;
+ }
- if (hProcess != NULL) {
- DebugBreakProcess(hProcess);
- CloseHandle(hProcess);
- rettv->vval.v_number = OK;
- }
+ DebugBreakProcess(hProcess);
+ CloseHandle(hProcess);
+ rettv->vval.v_number = OK;
#else
- uv_kill(pid, SIGINT);
+ uv_kill(pid, SIGINT);
#endif
- }
}
/// "deepcopy()" function
@@ -1369,10 +1239,10 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int noref = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- noref = (int)tv_get_number_chk(&argvars[1], NULL);
+ noref = (int)tv_get_bool_chk(&argvars[1], NULL);
}
if (noref < 0 || noref > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), noref);
} else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID()
@@ -1489,82 +1359,6 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fp
callback_free(&callback);
}
-/// "deletebufline()" function
-static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *const buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- return;
- }
- const bool is_curbuf = buf == curbuf;
- const bool save_VIsual_active = VIsual_active;
-
- linenr_T last;
- const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- last = tv_get_lnum_buf(&argvars[2], buf);
- } else {
- last = first;
- }
-
- if (buf->b_ml.ml_mfp == NULL || first < 1
- || first > buf->b_ml.ml_line_count || last < first) {
- rettv->vval.v_number = 1; // FAIL
- return;
- }
-
- buf_T *curbuf_save = NULL;
- win_T *curwin_save = NULL;
- if (!is_curbuf) {
- VIsual_active = false;
- curbuf_save = curbuf;
- curwin_save = curwin;
- curbuf = buf;
- find_win_for_curbuf();
- }
- if (last > curbuf->b_ml.ml_line_count) {
- last = curbuf->b_ml.ml_line_count;
- }
- const long count = last - first + 1;
-
- // When coming here from Insert mode, sync undo, so that this can be
- // undone separately from what was previously inserted.
- if (u_sync_once == 2) {
- u_sync_once = 1; // notify that u_sync() was called
- u_sync(true);
- }
-
- if (u_save(first - 1, last + 1) == FAIL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- for (linenr_T lnum = first; lnum <= last; lnum++) {
- ml_delete(first, true);
- }
-
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp->w_buffer == buf) {
- if (wp->w_cursor.lnum > last) {
- wp->w_cursor.lnum -= (linenr_T)count;
- } else if (wp->w_cursor.lnum > first) {
- wp->w_cursor.lnum = first;
- }
- if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
- wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
- }
- }
- }
- check_cursor_col();
- deleted_lines_mark(first, count);
- }
-
- if (!is_curbuf) {
- curbuf = curbuf_save;
- curwin = curwin_save;
- VIsual_active = save_VIsual_active;
- }
-}
-
/// "did_filetype()" function
static void f_did_filetype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -1595,9 +1389,10 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|| changedtick != buf_get_changedtick(curbuf)
|| fnum != curbuf->b_fnum) {
// New line, buffer, change: need to get the values.
- int filler_lines = diff_check(curwin, lnum);
- if (filler_lines < 0) {
- if (filler_lines == -1) {
+ int linestatus = 0;
+ int filler_lines = diff_check_with_linestatus(curwin, lnum, &linestatus);
+ if (filler_lines < 0 || linestatus < 0) {
+ if (filler_lines == -1 || linestatus == -1) {
change_start = MAXCOL;
change_end = -1;
if (diff_find_change(curwin, lnum, &change_start, &change_end)) {
@@ -1624,7 +1419,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
hlID = HLF_CHD; // Changed line.
}
}
- rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)(hlID + 1);
+ rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (hlID + 1);
}
/// "empty({expr})" function
@@ -1727,23 +1522,22 @@ static void f_escape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char buf[NUMBUFLEN];
- rettv->vval.v_string = (char *)vim_strsave_escaped((const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1],
- buf));
+ rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
+ tv_get_string_buf(&argvars[1], buf));
rettv->v_type = VAR_STRING;
}
/// "getenv()" function
static void f_getenv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u *p = (char_u *)vim_getenv(tv_get_string(&argvars[0]));
+ char *p = vim_getenv(tv_get_string(&argvars[0]));
if (p == NULL) {
rettv->v_type = VAR_SPECIAL;
rettv->vval.v_special = kSpecialVarNull;
return;
}
- rettv->vval.v_string = (char *)p;
+ rettv->vval.v_string = p;
rettv->v_type = VAR_STRING;
}
@@ -1804,7 +1598,7 @@ static char *get_list_line(int c, void *cookie, int indent, bool do_concat)
return s == NULL ? NULL : xstrdup(s);
}
-static void execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
+void execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
{
const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_silent;
@@ -1888,21 +1682,6 @@ static void f_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
execute_common(argvars, rettv, 0);
}
-/// "win_execute(win_id, command)" function
-static void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- // Return an empty string if something fails.
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
-
- int id = (int)tv_get_number(argvars);
- tabpage_T *tp;
- win_T *wp = win_id2wp_tp(id, &tp);
- if (wp != NULL && tp != NULL) {
- WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1));
- }
-}
-
/// "exepath()" function
static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -1916,7 +1695,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
#ifdef BACKSLASH_IN_FILENAME
if (path != NULL) {
- slash_adjust((char_u *)path);
+ slash_adjust(path);
}
#endif
@@ -1943,14 +1722,9 @@ static void f_exists(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
xfree(exp);
}
} else if (*p == '&' || *p == '+') { // Option.
- bool working = (*p == '+'); // whether option needs to be working
- int opt_flags;
-
- if (find_option_end(&p, &opt_flags) != NULL) {
- int opt_idx = findoption(p);
- n = (opt_idx >= 0 && (!working || get_varp_scope(get_option(opt_idx), opt_flags) != NULL));
- } else {
- n = false;
+ n = (get_option_tv(&p, NULL, true) == OK);
+ if (*skipwhite(p) != NUL) {
+ n = false; // Trailing garbage.
}
} else if (*p == '*') { // Internal or user defined function.
n = function_exists(p + 1, false);
@@ -1975,7 +1749,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
bool error = false;
#ifdef BACKSLASH_IN_FILENAME
- char_u *p_csl_save = p_csl;
+ char *p_csl_save = p_csl;
// avoid using 'completeslash' here
p_csl = empty_option;
@@ -1996,7 +1770,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
size_t len;
char *errormsg = NULL;
- char_u *result = eval_vars((char_u *)s, (char_u *)s, &len, NULL, &errormsg, NULL, false);
+ char *result = eval_vars((char *)s, s, &len, NULL, &errormsg, NULL, false);
if (p_verbose == 0) {
emsg_off--;
} else if (errormsg != NULL) {
@@ -2009,7 +1783,7 @@ static void f_expand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
XFREE_CLEAR(result);
} else {
- rettv->vval.v_string = (char *)result;
+ rettv->vval.v_string = result;
}
} else {
// When the optional second argument is non-zero, don't remove matches
@@ -2062,6 +1836,12 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *errormsg = NULL;
+ bool emsgoff = true;
+
+ if (argvars[1].v_type == VAR_DICT
+ && tv_dict_get_bool(argvars[1].vval.v_dict, "errmsg", kBoolVarFalse)) {
+ emsgoff = false;
+ }
rettv->v_type = VAR_STRING;
char *cmdstr = xstrdup(tv_get_string(&argvars[0]));
@@ -2075,9 +1855,17 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
};
eap.argt |= EX_NOSPC;
- emsg_off++;
- expand_filename(&eap, &cmdstr, &errormsg);
- emsg_off--;
+ if (emsgoff) {
+ emsg_off++;
+ }
+ if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL) {
+ if (!emsgoff && errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
+ }
+ if (emsgoff) {
+ emsg_off--;
+ }
rettv->vval.v_string = cmdstr;
}
@@ -2108,9 +1896,9 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
list_T *list = argvars[0].vval.v_list;
if (list != NULL
- && !var_check_lock(tv_list_locked(list),
- N_("flatten() argument"),
- TV_TRANSLATE)
+ && !value_check_lock(tv_list_locked(list),
+ N_("flatten() argument"),
+ TV_TRANSLATE)
&& tv_list_flatten(list, maxdepth) == OK) {
tv_copy(&argvars[0], rettv);
}
@@ -2127,7 +1915,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
list_T *const l1 = argvars[0].vval.v_list;
list_T *const l2 = argvars[1].vval.v_list;
- if (!var_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
+ if (!value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
listitem_T *item;
if (argvars[2].v_type != VAR_UNKNOWN) {
long before = (long)tv_get_number_chk(&argvars[2], &error);
@@ -2156,13 +1944,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
dict_T *const d1 = argvars[0].vval.v_dict;
dict_T *const d2 = argvars[1].vval.v_dict;
if (d1 == NULL) {
- const bool locked = var_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
+ const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
(void)locked;
assert(locked == true);
} else if (d2 == NULL) {
// Do nothing
tv_copy(&argvars[0], rettv);
- } else if (!var_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ } else if (!value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *action = "force";
// Check the third argument.
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -2233,8 +2021,8 @@ static void f_filewritable(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
{
- char_u *fresult = NULL;
- char_u *path = *curbuf->b_p_path == NUL ? p_path : (char_u *)curbuf->b_p_path;
+ char *fresult = NULL;
+ char *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
int count = 1;
bool first = true;
bool error = false;
@@ -2251,7 +2039,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
error = true;
} else {
if (*p != NUL) {
- path = (char_u *)p;
+ path = (char *)p;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -2269,13 +2057,13 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) {
xfree(fresult);
}
- fresult = find_file_in_path_option(first ? (char_u *)fname : NULL,
+ fresult = find_file_in_path_option(first ? (char *)fname : NULL,
first ? strlen(fname) : 0,
0, first, path,
- find_what, (char_u *)curbuf->b_ffname,
+ find_what, curbuf->b_ffname,
(find_what == FINDFILE_DIR
- ? (char_u *)""
- : (char_u *)curbuf->b_p_sua));
+ ? ""
+ : curbuf->b_p_sua));
first = false;
if (fresult != NULL && rettv->v_type == VAR_LIST) {
@@ -2285,7 +2073,7 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
}
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = (char *)fresult;
+ rettv->vval.v_string = fresult;
}
}
@@ -2312,14 +2100,16 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
float_T f;
- if (tv_get_float_chk(argvars, &f)) {
- if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
- rettv->vval.v_number = -VARNUMBER_MAX;
- } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
- rettv->vval.v_number = VARNUMBER_MAX;
- } else {
- rettv->vval.v_number = (varnumber_T)f;
- }
+ if (!tv_get_float_chk(argvars, &f)) {
+ return;
+ }
+
+ if (f <= (float_T) - VARNUMBER_MAX + DBL_EPSILON) {
+ rettv->vval.v_number = -VARNUMBER_MAX;
+ } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
+ rettv->vval.v_number = VARNUMBER_MAX;
+ } else {
+ rettv->vval.v_number = (varnumber_T)f;
}
}
@@ -2347,7 +2137,7 @@ static void f_fnameescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "fnamemodify({fname}, {mods})" function
static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- char_u *fbuf = NULL;
+ char *fbuf = NULL;
size_t len = 0;
char buf[NUMBUFLEN];
const char *fname = tv_get_string_chk(&argvars[0]);
@@ -2359,7 +2149,7 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (*mods != NUL) {
size_t usedlen = 0;
(void)modify_fname((char *)mods, false, &usedlen,
- (char **)&fname, (char **)&fbuf, &len);
+ (char **)&fname, &fbuf, &len);
}
}
@@ -2454,13 +2244,17 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *const what = tv_get_string(&argvars[1]);
if (strcmp(what, "func") == 0 || strcmp(what, "name") == 0) {
+ const char *name = partial_name(pt);
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
- const char *const n = (const char *)partial_name(pt);
- assert(n != NULL);
- rettv->vval.v_string = xstrdup(n);
+ assert(name != NULL);
if (rettv->v_type == VAR_FUNC) {
- func_ref((char_u *)rettv->vval.v_string);
+ func_ref((char *)name);
}
+ if (*what == 'n' && pt->pt_name == NULL && pt->pt_func != NULL) {
+ // use <SNR> instead of the byte code
+ name = printable_func_name(pt->pt_func);
+ }
+ rettv->vval.v_string = xstrdup(name);
} else if (strcmp(what, "dict") == 0) {
what_is_dict = true;
if (pt->pt_dict != NULL) {
@@ -2495,117 +2289,6 @@ static void f_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
-/// "getbufinfo()" function
-static void f_getbufinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *argbuf = NULL;
- bool filtered = false;
- bool sel_buflisted = false;
- bool sel_bufloaded = false;
- bool sel_bufmodified = false;
-
- tv_list_alloc_ret(rettv, kListLenMayKnow);
-
- // List of all the buffers or selected buffers
- if (argvars[0].v_type == VAR_DICT) {
- dict_T *sel_d = argvars[0].vval.v_dict;
-
- if (sel_d != NULL) {
- dictitem_T *di;
-
- filtered = true;
-
- di = tv_dict_find(sel_d, S_LEN("buflisted"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_buflisted = true;
- }
-
- di = tv_dict_find(sel_d, S_LEN("bufloaded"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_bufloaded = true;
- }
- di = tv_dict_find(sel_d, S_LEN("bufmodified"));
- if (di != NULL && tv_get_number(&di->di_tv)) {
- sel_bufmodified = true;
- }
- }
- } else if (argvars[0].v_type != VAR_UNKNOWN) {
- // Information about one buffer. Argument specifies the buffer
- argbuf = tv_get_buf_from_arg(&argvars[0]);
- if (argbuf == NULL) {
- return;
- }
- }
-
- // Return information about all the buffers or a specified buffer
- FOR_ALL_BUFFERS(buf) {
- if (argbuf != NULL && argbuf != buf) {
- continue;
- }
- if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
- || (sel_buflisted && !buf->b_p_bl)
- || (sel_bufmodified && !buf->b_changed))) {
- continue;
- }
-
- dict_T *const d = get_buffer_info(buf);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (argbuf != NULL) {
- return;
- }
- }
-}
-
-/// Get line or list of lines from buffer "buf" into "rettv".
-///
-/// @param retlist if true, then the lines are returned as a Vim List.
-///
-/// @return range (from start to end) of lines in rettv from the specified
-/// buffer.
-static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
-{
- rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
- rettv->vval.v_string = NULL;
-
- if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0 || end < start) {
- if (retlist) {
- tv_list_alloc_ret(rettv, 0);
- }
- return;
- }
-
- if (retlist) {
- if (start < 1) {
- start = 1;
- }
- if (end > buf->b_ml.ml_line_count) {
- end = buf->b_ml.ml_line_count;
- }
- tv_list_alloc_ret(rettv, end - start + 1);
- while (start <= end) {
- tv_list_append_string(rettv->vval.v_list,
- (const char *)ml_get_buf(buf, start++, false), -1);
- }
- } else {
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = ((start >= 1 && start <= buf->b_ml.ml_line_count)
- ? xstrdup(ml_get_buf(buf, start, false)) : NULL);
- }
-}
-
-/// "getbufline()" function
-static void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
-
- const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
- const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
- ? lnum
- : tv_get_lnum_buf(&argvars[2], buf));
-
- get_buffer_lines(buf, lnum, end, true, rettv);
-}
-
/// "getchangelist()" function
static void f_getchangelist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -2729,15 +2412,6 @@ static void f_getcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fpt
tv_dict_add_nr(dict, S_LEN("until"), last_csearch_until());
}
-/// "getcmdwintype()" function
-static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- rettv->vval.v_string = xmallocz(1);
- rettv->vval.v_string[0] = (char)cmdwin_type;
-}
-
/// `getcwd([{win}[, {tab}]])` function
///
/// Every scope not specified implies the currently selected scope object.
@@ -2842,13 +2516,13 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
FALLTHROUGH; // In global directory, just need to get OS CWD.
case kCdScopeInvalid: // If called without any arguments, get OS CWD.
- if (os_dirname((char_u *)cwd, MAXPATHL) == FAIL) {
+ if (os_dirname(cwd, MAXPATHL) == FAIL) {
from = ""; // Return empty string on failure.
}
}
if (from) {
- STRLCPY(cwd, from, MAXPATHL);
+ xstrlcpy(cwd, from, MAXPATHL);
}
rettv->vval.v_string = xstrdup(cwd);
@@ -2870,7 +2544,7 @@ static void f_getfontname(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *perm = NULL;
- char_u flags[] = "rwx";
+ char flags[] = "rwx";
const char *filename = tv_get_string(&argvars[0]);
int32_t file_perm = os_getperm(filename);
@@ -2878,7 +2552,7 @@ static void f_getfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
perm = xstrdup("---------");
for (int i = 0; i < 9; i++) {
if (file_perm & (1 << (8 - i))) {
- perm[i] = (char)flags[i % 3];
+ perm[i] = flags[i % 3];
}
}
}
@@ -2989,24 +2663,6 @@ static void f_getjumplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
-/// "getline(lnum, [end])" function
-static void f_getline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- linenr_T end;
- bool retlist;
-
- const linenr_T lnum = tv_get_lnum(argvars);
- if (argvars[1].v_type == VAR_UNKNOWN) {
- end = lnum;
- retlist = false;
- } else {
- end = tv_get_lnum(&argvars[1]);
- retlist = true;
- }
-
- get_buffer_lines(curbuf, lnum, end, retlist, rettv);
-}
-
/// "getmarklist()" function
static void f_getmarklist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -3094,19 +2750,19 @@ static void f_getpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// Returns zero on error.
static int getreg_get_regname(typval_T *argvars)
{
- const char_u *strregname;
+ const char *strregname;
if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = (const char_u *)tv_get_string_chk(&argvars[0]);
+ strregname = tv_get_string_chk(&argvars[0]);
if (strregname == NULL) { // type error; errmsg already given
return 0;
}
} else {
// Default to v:register
- strregname = (char_u *)get_vim_var_str(VV_REG);
+ strregname = get_vim_var_str(VV_REG);
}
- return *strregname == 0 ? '"' : *strregname;
+ return *strregname == 0 ? '"' : (uint8_t)(*strregname);
}
/// "getreg()" function
@@ -3165,38 +2821,6 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_string = xstrdup(buf);
}
-/// "gettabinfo()" function
-static void f_gettabinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tabpage_T *tparg = NULL;
-
- tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
- ? 1
- : kListLenMayKnow));
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- // Information about one tab page
- tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
- if (tparg == NULL) {
- return;
- }
- }
-
- // Get information about a specific tab page or all tab pages
- int tpnr = 0;
- FOR_ALL_TABS(tp) {
- tpnr++;
- if (tparg != NULL && tp != tparg) {
- continue;
- }
- dict_T *const d = get_tabpage_info(tp, tpnr);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (tparg != NULL) {
- return;
- }
- }
-}
-
/// "gettagstack()" function
static void f_gettagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -3214,41 +2838,6 @@ static void f_gettagstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
get_tagstack(wp, rettv->vval.v_dict);
}
-/// "getwininfo()" function
-static void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wparg = NULL;
-
- tv_list_alloc_ret(rettv, kListLenMayKnow);
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wparg = win_id2wp((int)tv_get_number(&argvars[0]));
- if (wparg == NULL) {
- return;
- }
- }
-
- // Collect information about either all the windows across all the tab
- // pages or one particular window.
- int16_t tabnr = 0;
- FOR_ALL_TABS(tp) {
- tabnr++;
- int16_t winnr = 0;
- FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
- winnr++;
- if (wparg != NULL && wp != wparg) {
- continue;
- }
- dict_T *const d = get_win_info(wp, tabnr, winnr);
- tv_list_append_dict(rettv->vval.v_list, d);
- if (wparg != NULL) {
- // found information about a specific window
- return;
- }
- }
- }
-}
-
/// Dummy timer callback. Used by f_wait().
static void dummy_timer_due_cb(TimeWatcher *tw, void *data)
{}
@@ -3313,111 +2902,6 @@ static void f_wait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
time_watcher_close(tw, dummy_timer_close_cb);
}
-/// "win_screenpos()" function
-static void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tv_list_alloc_ret(rettv, 2);
- const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
- tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
- tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
-}
-
-/// Move the window wp into a new split of targetwin in a given direction
-static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
-{
- int height = wp->w_height;
- win_T *oldwin = curwin;
-
- if (wp == targetwin || wp == aucmd_win) {
- return;
- }
-
- // Jump to the target window
- if (curwin != targetwin) {
- win_goto(targetwin);
- }
-
- // Remove the old window and frame from the tree of frames
- int dir;
- (void)winframe_remove(wp, &dir, NULL);
- win_remove(wp, NULL);
- last_status(false); // may need to remove last status line
- (void)win_comp_pos(); // recompute window positions
-
- // Split a window on the desired side and put the old window there
- (void)win_split_ins(size, flags, wp, dir);
-
- // If splitting horizontally, try to preserve height
- if (size == 0 && !(flags & WSP_VERT)) {
- win_setheight_win(height, wp);
- if (p_ea) {
- win_equal(wp, true, 'v');
- }
- }
-
- if (oldwin != curwin) {
- win_goto(oldwin);
- }
-}
-
-/// "win_splitmove()" function
-static void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- win_T *targetwin = find_win_by_nr_or_id(&argvars[1]);
-
- if (wp == NULL || targetwin == NULL || wp == targetwin
- || !win_valid(wp) || !win_valid(targetwin)
- || win_valid_floating(wp) || win_valid_floating(targetwin)) {
- emsg(_(e_invalwindow));
- rettv->vval.v_number = -1;
- return;
- }
-
- int flags = 0, size = 0;
-
- if (argvars[2].v_type != VAR_UNKNOWN) {
- dict_T *d;
- dictitem_T *di;
-
- if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
- emsg(_(e_invarg));
- return;
- }
-
- d = argvars[2].vval.v_dict;
- if (tv_dict_get_number(d, "vertical")) {
- flags |= WSP_VERT;
- }
- if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
- flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
- }
- size = (int)tv_dict_get_number(d, "size");
- }
-
- win_move_into_split(wp, targetwin, size, flags);
-}
-
-/// "getwinpos({timeout})" function
-static void f_getwinpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tv_list_alloc_ret(rettv, 2);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
-}
-
-/// "getwinposx()" function
-static void f_getwinposx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = -1;
-}
-
-/// "getwinposy()" function
-static void f_getwinposy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = -1;
-}
-
/// "glob()" function
static void f_glob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -3498,7 +2982,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *const file = tv_get_string_buf_chk(&argvars[1], buf1);
if (file != NULL && !error) {
garray_T ga;
- ga_init(&ga, (int)sizeof(char_u *), 10);
+ ga_init(&ga, (int)sizeof(char *), 10);
globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags);
if (rettv->v_type == VAR_STRING) {
@@ -3526,6 +3010,19 @@ static void f_glob2regpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_string = (pat == NULL) ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, false);
}
+/// "gettext()" function
+static void f_gettext(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ if (argvars[0].v_type != VAR_STRING
+ || argvars[0].vval.v_string == NULL
+ || *argvars[0].vval.v_string == NUL) {
+ semsg(_(e_invarg2), tv_get_string(&argvars[0]));
+ } else {
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = xstrdup(_(argvars[0].vval.v_string));
+ }
+}
+
/// "has()" function
static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -3542,7 +3039,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
#ifdef UNIX
"unix",
#endif
-#if defined(MSWIN)
+#ifdef MSWIN
"win32",
#endif
#ifdef _WIN64
@@ -3565,7 +3062,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"cmdwin",
"comments",
"conceal",
- "cscope",
"cursorbind",
"cursorshape",
#ifdef DEBUG
@@ -3586,9 +3082,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"fork",
#endif
"gettext",
-#if defined(HAVE_ICONV)
"iconv",
-#endif
"insert_expand",
"jumplist",
"keymap",
@@ -3616,8 +3110,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"packages",
"path_extra",
"persistent_undo",
- "postscript",
- "printer",
"profile",
"pythonx",
"reltime",
@@ -3634,7 +3126,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"spell",
"syntax",
#if !defined(UNIX)
- "system", // TODO(SplinterOfChaos): This IS defined for UNIX!
+ "system",
#endif
"tablineat",
"tag_binary",
@@ -3870,13 +3362,11 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *const str = tv_get_string(&argvars[0]);
char buf1[NUMBUFLEN];
- char_u *const from =
- (char_u *)enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[1], buf1)));
+ char *const from = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[1], buf1)));
char buf2[NUMBUFLEN];
- char_u *const to =
- (char_u *)enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[2], buf2)));
+ char *const to = enc_canonize(enc_skip((char *)tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
- convert_setup(&vimconv, (char *)from, (char *)to);
+ convert_setup(&vimconv, from, to);
// If the encodings are equal, no conversion needed.
if (vimconv.vc_type == CONV_NONE) {
@@ -3942,33 +3432,36 @@ static void f_index(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg(_(e_listblobreq));
return;
}
+
list_T *const l = argvars[0].vval.v_list;
- if (l != NULL) {
- listitem_T *item = tv_list_first(l);
- if (argvars[2].v_type != VAR_UNKNOWN) {
- bool error = false;
+ if (l == NULL) {
+ return;
+ }
- // Start at specified item.
- idx = tv_list_uidx(l, (int)tv_get_number_chk(&argvars[2], &error));
- if (error || idx == -1) {
+ listitem_T *item = tv_list_first(l);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+
+ // Start at specified item.
+ idx = tv_list_uidx(l, (int)tv_get_number_chk(&argvars[2], &error));
+ if (error || idx == -1) {
+ item = NULL;
+ } else {
+ item = tv_list_find(l, (int)idx);
+ assert(item != NULL);
+ }
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ ic = !!tv_get_number_chk(&argvars[3], &error);
+ if (error) {
item = NULL;
- } else {
- item = tv_list_find(l, (int)idx);
- assert(item != NULL);
- }
- if (argvars[3].v_type != VAR_UNKNOWN) {
- ic = !!tv_get_number_chk(&argvars[3], &error);
- if (error) {
- item = NULL;
- }
}
}
+ }
- for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) {
- if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) {
- rettv->vval.v_number = idx;
- break;
- }
+ for (; item != NULL; item = TV_LIST_ITEM_NEXT(l, item), idx++) {
+ if (tv_equal(TV_LIST_ITEM_TV(item), &argvars[1], ic, false)) {
+ rettv->vval.v_number = idx;
+ break;
}
}
}
@@ -4061,8 +3554,8 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
blob_T *const b = argvars[0].vval.v_blob;
if (b == NULL
- || var_check_lock(b->bv_lock, N_("insert() argument"),
- TV_TRANSLATE)) {
+ || value_check_lock(b->bv_lock, N_("insert() argument"),
+ TV_TRANSLATE)) {
return;
}
@@ -4089,16 +3582,16 @@ static void f_insert(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
ga_grow(&b->bv_ga, 1);
- char_u *const p = (char_u *)b->bv_ga.ga_data;
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
memmove(p + before + 1, p + before, (size_t)(len - before));
- *(p + before) = (char_u)val;
+ *(p + before) = (uint8_t)val;
b->bv_ga.ga_len++;
tv_copy(&argvars[0], rettv);
} else if (argvars[0].v_type != VAR_LIST) {
semsg(_(e_listblobarg), "insert()");
- } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("insert() argument"), TV_TRANSLATE)) {
+ } else if (!value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ N_("insert() argument"), TV_TRANSLATE)) {
long before = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
before = tv_get_number_chk(&argvars[2], &error);
@@ -4148,11 +3641,11 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
lval_T lv;
rettv->vval.v_number = -1;
- const char_u *const end = (char_u *)get_lval((char *)tv_get_string(&argvars[0]),
- NULL,
- &lv, false, false,
- GLV_NO_AUTOLOAD|GLV_READ_ONLY,
- FNE_CHECK_START);
+ const char *const end = get_lval((char *)tv_get_string(&argvars[0]),
+ NULL,
+ &lv, false, false,
+ GLV_NO_AUTOLOAD|GLV_READ_ONLY,
+ FNE_CHECK_START);
if (end != NULL && lv.ll_name != NULL) {
if (*end != NUL) {
semsg(_(e_trailing_arg), end);
@@ -4880,9 +4373,9 @@ static void f_map(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
- char_u *str = NULL;
+ char *str = NULL;
long len = 0;
- char_u *expr = NULL;
+ char *expr = NULL;
regmatch_T regmatch;
long start = 0;
long nth = 1;
@@ -4890,7 +4383,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
bool match = false;
list_T *l = NULL;
long idx = 0;
- char_u *tofree = NULL;
+ char *tofree = NULL;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
char *save_cpo = p_cpo;
@@ -4927,8 +4420,8 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
}
li = tv_list_first(l);
} else {
- expr = str = (char_u *)tv_get_string(&argvars[0]);
- len = (long)STRLEN(str);
+ expr = str = (char *)tv_get_string(&argvars[0]);
+ len = (long)strlen(str);
}
char patbuf[NUMBUFLEN];
@@ -4987,8 +4480,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
break;
}
xfree(tofree);
- tofree = expr = str = (char_u *)encode_tv2echo(TV_LIST_ITEM_TV(li),
- NULL);
+ tofree = expr = str = encode_tv2echo(TV_LIST_ITEM_TV(li), NULL);
if (str == NULL) {
break;
}
@@ -5008,9 +4500,9 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
li = TV_LIST_ITEM_NEXT(l, li);
idx++;
} else {
- startcol = (colnr_T)((char_u *)regmatch.startp[0]
+ startcol = (colnr_T)(regmatch.startp[0]
+ utfc_ptr2len(regmatch.startp[0]) - str);
- if (startcol > (colnr_T)len || str + startcol <= (char_u *)regmatch.startp[0]) {
+ if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) {
match = false;
break;
}
@@ -5028,9 +4520,9 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
- TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz((const char *)regmatch.startp[0], rd);
- TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)((char_u *)regmatch.startp[0] - expr);
- TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(regmatch.endp[0] - (char *)expr);
+ TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz(regmatch.startp[0], rd);
+ TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(regmatch.startp[0] - expr);
+ TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(regmatch.endp[0] - expr);
if (l != NULL) {
TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx;
}
@@ -5064,11 +4556,9 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
rettv->vval.v_number = idx;
} else {
if (type == kSomeMatch) {
- rettv->vval.v_number =
- (varnumber_T)((char_u *)regmatch.startp[0] - str);
+ rettv->vval.v_number = (varnumber_T)(regmatch.startp[0] - str);
} else {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.endp[0] - (char *)str);
+ rettv->vval.v_number = (varnumber_T)(regmatch.endp[0] - str);
}
rettv->vval.v_number += (varnumber_T)(str - expr);
}
@@ -5142,7 +4632,7 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
TV_LIST_ITER_CONST(tv->vval.v_list, li, {
const varnumber_T i = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
if (error) {
- return;
+ return; // type error; errmsg already given
}
if (domax ? i > n : i < n) {
n = i;
@@ -5155,7 +4645,7 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
TV_DICT_ITER(tv->vval.v_dict, di, {
const varnumber_T i = tv_get_number_chk(&di->di_tv, &error);
if (error) {
- return;
+ return; // type error; errmsg already given
}
if (domax ? i > n : i < n) {
n = i;
@@ -5165,6 +4655,7 @@ static void max_min(const typval_T *const tv, typval_T *const rettv, const bool
semsg(_(e_listdictarg), domax ? "max()" : "min()");
return;
}
+
rettv->vval.v_number = n;
}
@@ -5216,10 +4707,9 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
xfree(failed_dir);
rettv->vval.v_number = FAIL;
return;
- } else {
- rettv->vval.v_number = OK;
- return;
}
+ rettv->vval.v_number = OK;
+ return;
}
}
rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
@@ -5470,7 +4960,7 @@ static void f_pathshorten(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_string = NULL;
} else {
rettv->vval.v_string = xstrdup(p);
- shorten_dir_len((char_u *)rettv->vval.v_string, trim_len);
+ shorten_dir_len(rettv->vval.v_string, trim_len);
}
}
@@ -5657,10 +5147,11 @@ static void init_srand(uint32_t *const x)
}
}
if (dev_urandom_state != OK) {
- // Reading /dev/urandom doesn't work, fall back to time().
+ // Reading /dev/urandom doesn't work, fall back to os_hrtime() XOR with process ID
#endif
// uncrustify:off
- *x = (uint32_t)time(NULL);
+ *x = (uint32_t)os_hrtime();
+ *x ^= (uint32_t)os_get_pid();
#ifndef MSWIN
}
#endif
@@ -5820,13 +5311,16 @@ static void f_range(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
if (stride == 0) {
emsg(_("E726: Stride is zero"));
- } else if (stride > 0 ? end + 1 < start : end - 1 > start) {
+ return;
+ }
+ if (stride > 0 ? end + 1 < start : end - 1 > start) {
emsg(_("E727: Start past end"));
- } else {
- tv_list_alloc_ret(rettv, (end - start) / stride);
- for (varnumber_T i = start; stride > 0 ? i <= end : i >= end; i += stride) {
- tv_list_append_number(rettv->vval.v_list, i);
- }
+ return;
+ }
+
+ tv_list_alloc_ret(rettv, (end - start) / stride);
+ for (varnumber_T i = start; stride > 0 ? i <= end : i >= end; i += stride) {
+ tv_list_append_number(rettv->vval.v_list, i);
}
}
@@ -5885,17 +5379,17 @@ static void f_readdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ga_clear_strings(&ga);
}
-/// "readfile()" function
-static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+/// "readfile()" or "readblob()" function
+static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_blob)
{
bool binary = false;
- bool blob = false;
+ bool blob = always_blob;
FILE *fd;
char buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1
int io_size = sizeof(buf);
char *prev = NULL; // previously read bytes, if any
- long prevlen = 0; // length of data in prev
- long prevsize = 0; // size of prev buffer
+ ptrdiff_t prevlen = 0; // length of data in prev
+ ptrdiff_t prevsize = 0; // size of prev buffer
long maxline = MAXLNUM;
if (argvars[1].v_type != VAR_UNKNOWN) {
@@ -5949,7 +5443,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
for (p = buf, start = buf;
p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
p++) {
- if (*p == '\n' || readlen <= 0) {
+ if (readlen <= 0 || *p == '\n') {
char *s = NULL;
size_t len = (size_t)(p - start);
@@ -6024,8 +5518,8 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int adjust_prevlen = 0;
if (dest < buf) { // -V782
- adjust_prevlen = (int)(buf - dest); // -V782
// adjust_prevlen must be 1 or 2.
+ adjust_prevlen = (int)(buf - dest); // -V782
dest = buf;
}
if (readlen > p - buf + 1) {
@@ -6050,17 +5544,17 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// small, to avoid repeatedly 'allocing' large and
// 'reallocing' small.
if (prevsize == 0) {
- prevsize = (long)(p - start);
+ prevsize = p - start;
} else {
- long grow50pc = (prevsize * 3) / 2;
- long growmin = (long)((p - start) * 2 + prevlen);
+ ptrdiff_t grow50pc = (prevsize * 3) / 2;
+ ptrdiff_t growmin = (p - start) * 2 + prevlen;
prevsize = grow50pc > growmin ? grow50pc : growmin;
}
prev = xrealloc(prev, (size_t)prevsize);
}
// Add the line part to end of "prev".
memmove(prev + prevlen, start, (size_t)(p - start));
- prevlen += (long)(p - start);
+ prevlen += p - start;
}
} // while
@@ -6068,6 +5562,18 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
fclose(fd);
}
+/// "readblob()" function
+static void f_readblob(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ read_file_or_blob(argvars, rettv, true);
+}
+
+/// "readfile()" function
+static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ read_file_or_blob(argvars, rettv, false);
+}
+
/// "getreginfo()" function
static void f_getreginfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -6377,7 +5883,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
q[-1] = NUL;
q = path_tail(p);
}
- if (q > p && !path_is_absolute((const char_u *)buf)) {
+ if (q > p && !path_is_absolute(buf)) {
// Symlink is relative to directory of argument. Replace the
// symlink with the resolved name in the same directory.
const size_t p_len = strlen(p);
@@ -6457,7 +5963,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
# endif
#endif
- simplify_filename((char_u *)rettv->vval.v_string);
+ simplify_filename(rettv->vval.v_string);
}
/// "reverse({list})" function
@@ -6468,7 +5974,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const int len = tv_blob_len(b);
for (int i = 0; i < len / 2; i++) {
- const char_u tmp = tv_blob_get(b, i);
+ const uint8_t tmp = tv_blob_get(b, i);
tv_blob_set(b, i, tv_blob_get(b, len - i - 1));
tv_blob_set(b, len - i - 1, tmp);
}
@@ -6477,8 +5983,8 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
semsg(_(e_listblobarg), "reverse()");
} else {
list_T *const l = argvars[0].vval.v_list;
- if (!var_check_lock(tv_list_locked(l), N_("reverse() argument"),
- TV_TRANSLATE)) {
+ if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"),
+ TV_TRANSLATE)) {
tv_list_reverse(l);
tv_list_set_ret(rettv, l);
}
@@ -6598,55 +6104,57 @@ static int get_search_arg(typval_T *varp, int *flagsp)
{
int dir = FORWARD;
- if (varp->v_type != VAR_UNKNOWN) {
- char nbuf[NUMBUFLEN];
- const char *flags = tv_get_string_buf_chk(varp, nbuf);
- if (flags == NULL) {
- return 0; // Type error; errmsg already given.
- }
- int mask;
- while (*flags != NUL) {
- switch (*flags) {
- case 'b':
- dir = BACKWARD; break;
- case 'w':
- p_ws = true; break;
- case 'W':
- p_ws = false; break;
- default:
- mask = 0;
- if (flagsp != NULL) {
- switch (*flags) {
- case 'c':
- mask = SP_START; break;
- case 'e':
- mask = SP_END; break;
- case 'm':
- mask = SP_RETCOUNT; break;
- case 'n':
- mask = SP_NOMOVE; break;
- case 'p':
- mask = SP_SUBPAT; break;
- case 'r':
- mask = SP_REPEAT; break;
- case 's':
- mask = SP_SETPCMARK; break;
- case 'z':
- mask = SP_COLUMN; break;
- }
- }
- if (mask == 0) {
- semsg(_(e_invarg2), flags);
- dir = 0;
- } else {
- *flagsp |= mask;
+ if (varp->v_type == VAR_UNKNOWN) {
+ return FORWARD;
+ }
+
+ char nbuf[NUMBUFLEN];
+ const char *flags = tv_get_string_buf_chk(varp, nbuf);
+ if (flags == NULL) {
+ return 0; // Type error; errmsg already given.
+ }
+ int mask;
+ while (*flags != NUL) {
+ switch (*flags) {
+ case 'b':
+ dir = BACKWARD; break;
+ case 'w':
+ p_ws = true; break;
+ case 'W':
+ p_ws = false; break;
+ default:
+ mask = 0;
+ if (flagsp != NULL) {
+ switch (*flags) {
+ case 'c':
+ mask = SP_START; break;
+ case 'e':
+ mask = SP_END; break;
+ case 'm':
+ mask = SP_RETCOUNT; break;
+ case 'n':
+ mask = SP_NOMOVE; break;
+ case 'p':
+ mask = SP_SUBPAT; break;
+ case 'r':
+ mask = SP_REPEAT; break;
+ case 's':
+ mask = SP_SETPCMARK; break;
+ case 'z':
+ mask = SP_COLUMN; break;
}
}
- if (dir == 0) {
- break;
+ if (mask == 0) {
+ semsg(_(e_invarg2), flags);
+ dir = 0;
+ } else {
+ *flagsp |= mask;
}
- flags++;
}
+ if (dir == 0) {
+ break;
+ }
+ flags++;
}
return dir;
}
@@ -6718,7 +6226,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
// Repeat until {skip} returns false.
for (;;) {
subpatnum
- = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1, options, RE_SEARCH, &sia);
+ = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia);
// finding the first match again means there is no match where {skip}
// evaluates to zero.
if (firstpos.lnum != 0 && equalpos(pos, firstpos)) {
@@ -6729,7 +6237,9 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
// didn't find it or no skip argument
break;
}
- firstpos = pos;
+ if (firstpos.lnum == 0) {
+ firstpos = pos;
+ }
// If the skip expression matches, ignore this match.
{
@@ -6811,12 +6321,15 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
ADD(args, vim_to_object(tv));
}
- if (!rpc_send_event((uint64_t)argvars[0].vval.v_number,
- tv_get_string(&argvars[1]), args)) {
+ bool ok = rpc_send_event((uint64_t)argvars[0].vval.v_number,
+ tv_get_string(&argvars[1]), args);
+
+ api_free_array(args);
+
+ if (!ok) {
semsg(_(e_invarg2), "Channel doesn't exist");
return;
}
-
rettv->vval.v_number = 1;
}
@@ -6955,7 +6468,7 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// Allocate extra memory for the argument vector and the NULL pointer
int argvl = argsl + 2;
- char **argv = xmalloc(sizeof(char_u *) * (size_t)argvl);
+ char **argv = xmalloc(sizeof(char *) * (size_t)argvl);
// Copy program name
argv[0] = xstrdup(argvars[0].vval.v_string);
@@ -7131,7 +6644,7 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
if (!error && name != NULL) {
- rettv->vval.v_number = find_decl((char_u *)name, strlen(name), locally,
+ rettv->vval.v_number = find_decl((char *)name, strlen(name), locally,
thisblock, SEARCH_KEEP) == FAIL;
}
}
@@ -7266,14 +6779,14 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
- char_u *pat2 = xmalloc(pat2_len);
+ char *pat2 = xmalloc(pat2_len);
const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
- char_u *pat3 = xmalloc(pat3_len);
- snprintf((char *)pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
+ char *pat3 = xmalloc(pat3_len);
+ snprintf(pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
if (*mpat == NUL) {
STRCPY(pat3, pat2);
} else {
- snprintf((char *)pat3, pat3_len,
+ snprintf(pat3, pat3_len,
"\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat);
}
if (flags & SP_START) {
@@ -7290,7 +6803,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
clearpos(&firstpos);
pos_T foundpos;
clearpos(&foundpos);
- char_u *pat = pat3;
+ char *pat = pat3;
for (;;) {
searchit_arg_T sia = {
.sa_stop_lnum = lnum_stop,
@@ -7449,9 +6962,8 @@ static void f_serverstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (argvars[0].v_type != VAR_STRING) {
emsg(_(e_invarg));
return;
- } else {
- address = xstrdup(tv_get_string(argvars));
}
+ address = xstrdup(tv_get_string(argvars));
} else {
address = server_address_new(NULL);
}
@@ -7498,21 +7010,6 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
-/// "setbufline()" function
-static void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- linenr_T lnum;
- buf_T *buf;
-
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
- }
-}
-
/// Set the cursor or mark position.
/// If 'charpos' is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
@@ -7522,31 +7019,35 @@ static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
rettv->vval.v_number = -1;
const char *const name = tv_get_string_chk(argvars);
- if (name != NULL) {
- pos_T pos;
- int fnum;
- if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK) {
- if (pos.col != MAXCOL && --pos.col < 0) {
- pos.col = 0;
- }
- if (name[0] == '.' && name[1] == NUL) {
- // set cursor; "fnum" is ignored
- curwin->w_cursor = pos;
- if (curswant >= 0) {
- curwin->w_curswant = curswant - 1;
- curwin->w_set_curswant = false;
- }
- check_cursor();
- rettv->vval.v_number = 0;
- } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
- // set mark
- if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
- rettv->vval.v_number = 0;
- }
- } else {
- emsg(_(e_invarg));
- }
+ if (name == NULL) {
+ return;
+ }
+
+ pos_T pos;
+ int fnum;
+ if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) != OK) {
+ return;
+ }
+
+ if (pos.col != MAXCOL && --pos.col < 0) {
+ pos.col = 0;
+ }
+ if (name[0] == '.' && name[1] == NUL) {
+ // set cursor; "fnum" is ignored
+ curwin->w_cursor = pos;
+ if (curswant >= 0) {
+ curwin->w_curswant = curswant - 1;
+ curwin->w_set_curswant = false;
+ }
+ check_cursor();
+ rettv->vval.v_number = 0;
+ } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
+ // set mark
+ if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
+ rettv->vval.v_number = 0;
}
+ } else {
+ emsg(_(e_invarg));
}
}
@@ -7564,23 +7065,25 @@ static void f_setcharsearch(typval_T *argvars, typval_T *rettv, EvalFuncData fpt
}
dict_T *d = argvars[0].vval.v_dict;
- if (d != NULL) {
- char_u *const csearch = (char_u *)tv_dict_get_string(d, "char", false);
- if (csearch != NULL) {
- int pcc[MAX_MCO];
- const int c = utfc_ptr2char((char *)csearch, pcc);
- set_last_csearch(c, csearch, utfc_ptr2len((char *)csearch));
- }
+ if (d == NULL) {
+ return;
+ }
- dictitem_T *di = tv_dict_find(d, S_LEN("forward"));
- if (di != NULL) {
- set_csearch_direction(tv_get_number(&di->di_tv) ? FORWARD : BACKWARD);
- }
+ char *const csearch = tv_dict_get_string(d, "char", false);
+ if (csearch != NULL) {
+ int pcc[MAX_MCO];
+ const int c = utfc_ptr2char(csearch, pcc);
+ set_last_csearch(c, csearch, utfc_ptr2len(csearch));
+ }
- di = tv_dict_find(d, S_LEN("until"));
- if (di != NULL) {
- set_csearch_until(!!tv_get_number(&di->di_tv));
- }
+ dictitem_T *di = tv_dict_find(d, S_LEN("forward"));
+ if (di != NULL) {
+ set_csearch_direction(tv_get_number(&di->di_tv) ? FORWARD : BACKWARD);
+ }
+
+ di = tv_dict_find(d, S_LEN("until"));
+ if (di != NULL) {
+ set_csearch_until(!!tv_get_number(&di->di_tv));
}
}
@@ -7636,13 +7139,6 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = os_setperm(fname, mode) == OK;
}
-/// "setline()" function
-static void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- linenr_T lnum = tv_get_lnum(&argvars[0]);
- set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
-}
-
/// "setpos()" function
static void f_setpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -7888,8 +7384,7 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const bool do_special = non_zero_arg(&argvars[1]);
rettv->vval.v_string =
- (char *)vim_strsave_shellescape((const char_u *)tv_get_string(&argvars[0]), do_special,
- do_special);
+ vim_strsave_shellescape(tv_get_string(&argvars[0]), do_special, do_special);
rettv->v_type = VAR_STRING;
}
@@ -7914,7 +7409,7 @@ static void f_simplify(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
const char *const p = tv_get_string(&argvars[0]);
rettv->vval.v_string = xstrdup(p);
- simplify_filename((char_u *)rettv->vval.v_string); // Simplify in place.
+ simplify_filename(rettv->vval.v_string); // Simplify in place.
rettv->v_type = VAR_STRING;
}
@@ -8058,7 +7553,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
if (str != NULL) {
// Check the argument for spelling.
while (*str != NUL) {
- len = spell_check(curwin, (char_u *)str, &attr, &capcol, false);
+ len = spell_check(curwin, (char *)str, &attr, &capcol, false);
if (attr != HLF_COUNT) {
word = str;
break;
@@ -8117,7 +7612,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
maxcount = 25;
}
- spell_suggest_list(&ga, (char_u *)str, maxcount, need_capital, false);
+ spell_suggest_list(&ga, (char *)str, maxcount, need_capital, false);
f_spellsuggest_return:
tv_list_alloc_ret(rettv, (ptrdiff_t)ga.ga_len);
@@ -8148,7 +7643,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
typeerr = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- keepempty = (bool)tv_get_number_chk(&argvars[2], &typeerr);
+ keepempty = (bool)tv_get_bool_chk(&argvars[2], &typeerr);
}
}
if (pat == NULL || *pat == NUL) {
@@ -8173,7 +7668,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (*str == NUL) {
match = false; // Empty item at the end.
} else {
- match = vim_regexec_nl(&regmatch, (char_u *)str, col);
+ match = vim_regexec_nl(&regmatch, (char *)str, col);
}
const char *end;
if (match) {
@@ -8259,10 +7754,10 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_str2list(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
tv_list_alloc_ret(rettv, kListLenUnknown);
- const char_u *p = (const char_u *)tv_get_string(&argvars[0]);
+ const char *p = tv_get_string(&argvars[0]);
- for (; *p != NUL; p += utf_ptr2len((char *)p)) {
- tv_list_append_number(rettv->vval.v_list, utf_ptr2char((char *)p));
+ for (; *p != NUL; p += utf_ptr2len(p)) {
+ tv_list_append_number(rettv->vval.v_list, utf_ptr2char(p));
}
}
@@ -8278,15 +7773,15 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg(_(e_invarg));
return;
}
- if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) {
+ if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2])) {
what |= STR2NR_QUOTE;
}
}
- char_u *p = (char_u *)skipwhite(tv_get_string(&argvars[0]));
+ char *p = skipwhite(tv_get_string(&argvars[0]));
bool isneg = (*p == '-');
if (*p == '+' || *p == '-') {
- p = (char_u *)skipwhite((char *)p + 1);
+ p = skipwhite(p + 1);
}
switch (base) {
case 2:
@@ -8300,7 +7795,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
break;
}
varnumber_T n;
- vim_str2nr((char *)p, NULL, NULL, what, &n, NULL, 0, false);
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false);
// Text after the number is silently ignored.
if (isneg) {
rettv->vval.v_number = -n;
@@ -8332,15 +7827,13 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
vimconv_T conv;
conv.vc_type = CONV_NONE;
- char *enc = (char *)enc_locale();
+ char *enc = enc_locale();
convert_setup(&conv, p_enc, enc);
if (conv.vc_type != CONV_NONE) {
p = string_convert(&conv, p, NULL);
}
char result_buf[256];
- if (p != NULL) {
- (void)strftime(result_buf, sizeof(result_buf), p, curtime_ptr);
- } else {
+ if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
result_buf[0] = NUL;
}
@@ -8433,26 +7926,38 @@ static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
}
-/// "strchars()" function
-static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc)
{
const char *s = tv_get_string(&argvars[0]);
- int skipcc = 0;
varnumber_T len = 0;
- int (*func_mb_ptr2char_adv)(const char_u **pp);
+ int (*func_mb_ptr2char_adv)(const char **pp);
+
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL) {
+ func_mb_ptr2char_adv(&s);
+ len++;
+ }
+ rettv->vval.v_number = len;
+}
+
+/// "strcharlen()" function
+static void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ strchar_common(argvars, rettv, true);
+}
+
+/// "strchars()" function
+static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int skipcc = false;
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
+ skipcc = (int)tv_get_bool(&argvars[1]);
}
if (skipcc < 0 || skipcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), skipcc);
} else {
- func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
- while (*s != NUL) {
- func_mb_ptr2char_adv((const char_u **)&s);
- len++;
- }
- rettv->vval.v_number = len;
+ strchar_common(argvars, rettv, skipcc);
}
}
@@ -8592,7 +8097,7 @@ static void f_strptime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
vimconv_T conv = {
.vc_type = CONV_NONE,
};
- char *enc = (char *)enc_locale();
+ char *enc = enc_locale();
convert_setup(&conv, p_enc, enc);
if (conv.vc_type != CONV_NONE) {
fmt = string_convert(&conv, fmt, NULL);
@@ -8866,7 +8371,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
int syntax_flags = 0;
int cchar;
int matchid = 0;
- char_u str[NUMBUFLEN];
+ char str[NUMBUFLEN];
tv_list_set_ret(rettv, NULL);
@@ -8890,7 +8395,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
: curwin->w_p_lcs_chars.conceal;
}
if (cchar != NUL) {
- utf_char2bytes(cchar, (char *)str);
+ utf_char2bytes(cchar, str);
}
}
}
@@ -8898,7 +8403,7 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
tv_list_alloc_ret(rettv, 3);
tv_list_append_number(rettv->vval.v_list, (syntax_flags & HL_CONCEAL) != 0);
// -1 to auto-determine strlen
- tv_list_append_string(rettv->vval.v_list, (const char *)str, -1);
+ tv_list_append_string(rettv->vval.v_list, str, -1);
tv_list_append_number(rettv->vval.v_list, matchid);
}
@@ -8959,105 +8464,6 @@ static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, EvalFuncData fp
}
}
-/// "tabpagenr()" function
-static void f_tabpagenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- int nr = 1;
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- const char *const arg = tv_get_string_chk(&argvars[0]);
- nr = 0;
- if (arg != NULL) {
- if (strcmp(arg, "$") == 0) {
- nr = tabpage_index(NULL) - 1;
- } else if (strcmp(arg, "#") == 0) {
- nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0;
- } else {
- semsg(_(e_invexpr2), arg);
- }
- }
- } else {
- nr = tabpage_index(curtab);
- }
- rettv->vval.v_number = nr;
-}
-
-/// Common code for tabpagewinnr() and winnr().
-static int get_winnr(tabpage_T *tp, typval_T *argvar)
-{
- int nr = 1;
-
- win_T *twin = (tp == curtab) ? curwin : tp->tp_curwin;
- if (argvar->v_type != VAR_UNKNOWN) {
- bool invalid_arg = false;
- const char *const arg = tv_get_string_chk(argvar);
- if (arg == NULL) {
- nr = 0; // Type error; errmsg already given.
- } else if (strcmp(arg, "$") == 0) {
- twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
- } else if (strcmp(arg, "#") == 0) {
- twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
- if (twin == NULL) {
- nr = 0;
- }
- } else {
- // Extract the window count (if specified). e.g. winnr('3j')
- char *endp;
- long count = strtol((char *)arg, &endp, 10);
- if (count <= 0) {
- // if count is not specified, default to 1
- count = 1;
- }
- if (endp != NULL && *endp != '\0') {
- if (strequal(endp, "j")) {
- twin = win_vert_neighbor(tp, twin, false, count);
- } else if (strequal(endp, "k")) {
- twin = win_vert_neighbor(tp, twin, true, count);
- } else if (strequal(endp, "h")) {
- twin = win_horz_neighbor(tp, twin, true, count);
- } else if (strequal(endp, "l")) {
- twin = win_horz_neighbor(tp, twin, false, count);
- } else {
- invalid_arg = true;
- }
- } else {
- invalid_arg = true;
- }
- }
-
- if (invalid_arg) {
- semsg(_(e_invexpr2), arg);
- nr = 0;
- }
- }
-
- if (nr > 0) {
- for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
- wp != twin; wp = wp->w_next) {
- if (wp == NULL) {
- // didn't find it in this tabpage
- nr = 0;
- break;
- }
- nr++;
- }
- }
- return nr;
-}
-
-/// "tabpagewinnr()" function
-static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- int nr = 1;
- tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
- if (tp == NULL) {
- nr = 0;
- } else {
- nr = get_winnr(tp, &argvars[1]);
- }
- rettv->vval.v_number = nr;
-}
-
/// "tagfiles()" function
static void f_tagfiles(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -9090,7 +8496,7 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
fname = tv_get_string(&argvars[1]);
}
(void)get_tags(tv_list_alloc_ret(rettv, kListLenUnknown),
- (char_u *)tag_pattern, (char_u *)fname);
+ (char *)tag_pattern, (char *)fname);
}
/// "tempname()" function
@@ -9184,9 +8590,9 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int pid = chan->stream.pty.process.pid;
// "./…" => "/home/foo/…"
- vim_FullName(cwd, (char *)NameBuff, sizeof(NameBuff), false);
+ vim_FullName(cwd, NameBuff, sizeof(NameBuff), false);
// "/home/foo/…" => "~/…"
- size_t len = home_replace(NULL, (char *)NameBuff, (char *)IObuff, sizeof(IObuff), true);
+ size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = '\0';
@@ -9199,14 +8605,14 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
// Terminal URI: "term://$CWD//$PID:$CMD"
- snprintf((char *)NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
- (char *)IObuff, pid, cmd);
+ snprintf(NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
+ IObuff, pid, cmd);
// at this point the buffer has no terminal instance associated yet, so unset
// the 'swapfile' option to ensure no swap file will be created
curbuf->b_p_swf = false;
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
- (void)setfname(curbuf, (char *)NameBuff, NULL, true);
+ (void)setfname(curbuf, NameBuff, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
// Save the job id and pid in b:terminal_job_{id,pid}
@@ -9357,7 +8763,7 @@ static void f_tr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int fromlen;
for (const char *p = fromstr; *p != NUL; p += fromlen) {
fromlen = utfc_ptr2len(p);
- if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) {
+ if (fromlen == inlen && strncmp(in_str, p, (size_t)inlen) == 0) {
int tolen;
for (p = tostr; *p != NUL; p += tolen) {
tolen = utfc_ptr2len(p);
@@ -9612,276 +9018,6 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
}
}
-/// "win_findbuf()" function
-static void f_win_findbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tv_list_alloc_ret(rettv, kListLenMayKnow);
- win_findbuf(argvars, rettv->vval.v_list);
-}
-
-/// "win_getid()" function
-static void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = win_getid(argvars);
-}
-
-/// "win_gettype(nr)" function
-static void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp = curwin;
-
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_string = xstrdup("unknown");
- return;
- }
- }
- if (wp == aucmd_win) {
- rettv->vval.v_string = xstrdup("autocmd");
- } else if (wp->w_p_pvw) {
- rettv->vval.v_string = xstrdup("preview");
- } else if (wp->w_floating) {
- rettv->vval.v_string = xstrdup("popup");
- } else if (wp == curwin && cmdwin_type != 0) {
- rettv->vval.v_string = xstrdup("command");
- } else if (bt_quickfix(wp->w_buffer)) {
- rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
- }
-}
-
-/// "win_gotoid()" function
-static void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- int id = (int)tv_get_number(&argvars[0]);
-
- if (cmdwin_type != 0) {
- emsg(_(e_cmdwin));
- return;
- }
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp->handle == id) {
- goto_tabpage_win(tp, wp);
- rettv->vval.v_number = 1;
- return;
- }
- }
-}
-
-/// "win_id2tabwin()" function
-static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_id2tabwin(argvars, rettv);
-}
-
-/// "win_id2win()" function
-static void f_win_id2win(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = win_id2win(argvars);
-}
-
-/// "win_move_separator()" function
-static void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = false;
-
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL || wp->w_floating) {
- return;
- }
-
- int offset = (int)tv_get_number(&argvars[1]);
- win_drag_vsep_line(wp, offset);
- rettv->vval.v_number = true;
-}
-
-/// "win_move_statusline()" function
-static void f_win_move_statusline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp;
- int offset;
-
- rettv->vval.v_number = false;
-
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL || wp->w_floating) {
- return;
- }
-
- offset = (int)tv_get_number(&argvars[1]);
- win_drag_status_line(wp, offset);
- rettv->vval.v_number = true;
-}
-
-/// "winbufnr(nr)" function
-static void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_buffer->b_fnum;
- }
-}
-
-/// "wincol()" function
-static void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- validate_cursor();
- rettv->vval.v_number = curwin->w_wcol + 1;
-}
-
-/// "winheight(nr)" function
-static void f_winheight(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_height_inner;
- }
-}
-
-/// "winlayout()" function
-static void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tabpage_T *tp;
-
- tv_list_alloc_ret(rettv, 2);
-
- if (argvars[0].v_type == VAR_UNKNOWN) {
- tp = curtab;
- } else {
- tp = find_tabpage((int)tv_get_number(&argvars[0]));
- if (tp == NULL) {
- return;
- }
- }
-
- get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
-}
-
-/// "winline()" function
-static void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- validate_cursor();
- rettv->vval.v_number = curwin->w_wrow + 1;
-}
-
-/// "winnr()" function
-static void f_winnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- rettv->vval.v_number = get_winnr(curtab, &argvars[0]);
-}
-
-/// "winrestcmd()" function
-static void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- char_u buf[50];
-
- garray_T ga;
- ga_init(&ga, (int)sizeof(char), 70);
-
- // Do this twice to handle some window layouts properly.
- for (int i = 0; i < 2; i++) {
- int winnr = 1;
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- snprintf((char *)buf, sizeof(buf), "%dresize %d|", winnr,
- wp->w_height);
- ga_concat(&ga, (char *)buf);
- snprintf((char *)buf, sizeof(buf), "vert %dresize %d|", winnr,
- wp->w_width);
- ga_concat(&ga, (char *)buf);
- winnr++;
- }
- }
- ga_append(&ga, NUL);
-
- rettv->vval.v_string = ga.ga_data;
- rettv->v_type = VAR_STRING;
-}
-
-/// "winrestview()" function
-static void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- dict_T *dict = argvars[0].vval.v_dict;
-
- if (argvars[0].v_type != VAR_DICT || dict == NULL) {
- emsg(_(e_invarg));
- } else {
- dictitem_T *di;
- if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
- curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
- curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
- curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
- curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
- curwin->w_set_curswant = false;
- }
- if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
- set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
- }
- if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
- curwin->w_topfill = (int)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
- curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
- }
- if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
- curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
- }
-
- check_cursor();
- win_new_height(curwin, curwin->w_height);
- win_new_width(curwin, curwin->w_width);
- changed_window_setting();
-
- if (curwin->w_topline <= 0) {
- curwin->w_topline = 1;
- }
- if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
- curwin->w_topline = curbuf->b_ml.ml_line_count;
- }
- check_topfill(curwin, true);
- }
-}
-
-/// "winsaveview()" function
-static void f_winsaveview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- tv_dict_alloc_ret(rettv);
- dict_T *dict = rettv->vval.v_dict;
-
- tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
- tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
- tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
- update_curswant();
- tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
-
- tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
- tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
- tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
- tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
-}
-
-/// "winwidth(nr)" function
-static void f_winwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
-{
- win_T *wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- rettv->vval.v_number = -1;
- } else {
- rettv->vval.v_number = wp->w_width_inner;
- }
-}
-
/// "windowsversion()" function
static void f_windowsversion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -9920,6 +9056,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool binary = false;
bool append = false;
bool do_fsync = !!p_fs;
+ bool mkdir_p = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
const char *const flags = tv_get_string_chk(&argvars[2]);
if (flags == NULL) {
@@ -9935,6 +9072,8 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
do_fsync = true; break;
case 'S':
do_fsync = false; break;
+ case 'p':
+ mkdir_p = true; break;
default:
// Using %s, p and not %c, *p to preserve multibyte characters
semsg(_("E5060: Unknown flag: %s"), p);
@@ -9954,6 +9093,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg(_("E482: Can't open file with an empty name"));
} else if ((error = file_open(&fp, fname,
((append ? kFileAppend : kFileTruncate)
+ | (mkdir_p ? kFileMkDir : kFileCreate)
| kFileCreate), 0666)) != 0) {
semsg(_("E482: Can't open file %s for writing: %s"),
fname, os_strerror(error));
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index adff0b2441..1ae031a952 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -1,9 +1,14 @@
#ifndef NVIM_EVAL_FUNCS_H
#define NVIM_EVAL_FUNCS_H
+#include <stdbool.h>
+#include <stdint.h>
+
#include "nvim/api/private/dispatch.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/types.h"
/// Prototype of C function that implements VimL function
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, EvalFuncData data);
diff --git a/src/nvim/eval/gc.c b/src/nvim/eval/gc.c
index 633e6abacf..6a54c4ddc1 100644
--- a/src/nvim/eval/gc.c
+++ b/src/nvim/eval/gc.c
@@ -1,11 +1,12 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <stddef.h>
+
#include "nvim/eval/gc.h"
-#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "eval/gc.c.generated.h"
+# include "eval/gc.c.generated.h" // IWYU pragma: export
#endif
/// Head of list of all dictionaries
diff --git a/src/nvim/eval/gc.h b/src/nvim/eval/gc.h
index c2e862e469..3185750c3b 100644
--- a/src/nvim/eval/gc.h
+++ b/src/nvim/eval/gc.h
@@ -2,6 +2,7 @@
#define NVIM_EVAL_GC_H
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
extern dict_T *gc_first_dict;
extern list_T *gc_first_list;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index a0b06aaaf4..05b4737206 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -28,9 +28,9 @@
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/mbyte.h"
+#include "nvim/mbyte_defs.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/os/fileio.h"
#include "nvim/os/input.h"
#include "nvim/pos.h"
#include "nvim/types.h"
@@ -43,9 +43,11 @@
static char e_string_required_for_argument_nr[]
= N_("E1174: String required for argument %d");
static char e_non_empty_string_required_for_argument_nr[]
- = N_("E1142: Non-empty string required for argument %d");
+ = N_("E1175: Non-empty string required for argument %d");
static char e_number_required_for_argument_nr[]
= N_("E1210: Number required for argument %d");
+static char e_string_or_list_required_for_argument_nr[]
+ = N_("E1222: String or List required for argument %d");
bool tv_in_free_unref_items = false;
@@ -324,10 +326,12 @@ void tv_list_free_list(list_T *const l)
void tv_list_free(list_T *const l)
FUNC_ATTR_NONNULL_ALL
{
- if (!tv_in_free_unref_items) {
- tv_list_free_contents(l);
- tv_list_free_list(l);
+ if (tv_in_free_unref_items) {
+ return;
}
+
+ tv_list_free_contents(l);
+ tv_list_free_list(l);
}
/// Unreference a list
@@ -896,8 +900,8 @@ void tv_list_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
list_T *l;
bool error = false;
- if (var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- arg_errmsg, TV_TRANSLATE)) {
+ if (value_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ arg_errmsg, TV_TRANSLATE)) {
return;
}
@@ -1094,7 +1098,9 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
tv_clear(&argv[1]);
if (res == FAIL) {
+ // XXX: ITEM_COMPARE_FAIL is unused
res = ITEM_COMPARE_FAIL;
+ sortinfo->item_compare_func_err = true;
} else {
res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
if (res > 0) {
@@ -1150,7 +1156,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
semsg(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
list_T *const l = argvars[0].vval.v_list;
- if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
+ if (value_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
goto theend;
}
tv_list_set_ret(rettv, l);
@@ -1257,7 +1263,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
} else {
li = TV_LIST_ITEM_NEXT(l, li);
}
- if (info.item_compare_func_err) { // -V547
+ if (info.item_compare_func_err) {
emsg(_("E882: Uniq compare function failed"));
break;
}
@@ -1361,7 +1367,7 @@ void tv_list_reverse(list_T *const l)
/// true list will not be modified. Must be initialized to false
/// by the caller.
void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
- const ListSorter item_compare_func, bool *errp)
+ const ListSorter item_compare_func, const bool *errp)
FUNC_ATTR_NONNULL_ARG(3, 4)
{
const int len = tv_list_len(l);
@@ -1593,7 +1599,7 @@ void callback_free(Callback *callback)
{
switch (callback->type) {
case kCallbackFuncref:
- func_unref((char_u *)callback->data.funcref);
+ func_unref(callback->data.funcref);
xfree(callback->data.funcref);
break;
case kCallbackPartial:
@@ -1622,7 +1628,7 @@ void callback_put(Callback *cb, typval_T *tv)
case kCallbackFuncref:
tv->v_type = VAR_FUNC;
tv->vval.v_string = xstrdup(cb->data.funcref);
- func_ref((char_u *)cb->data.funcref);
+ func_ref(cb->data.funcref);
break;
case kCallbackLua:
// TODO(tjdevries): Unified Callback.
@@ -1648,7 +1654,7 @@ void callback_copy(Callback *dest, Callback *src)
break;
case kCallbackFuncref:
dest->data.funcref = xstrdup(src->data.funcref);
- func_ref((char_u *)src->data.funcref);
+ func_ref(src->data.funcref);
break;
case kCallbackLua:
dest->data.luaref = api_new_luaref(src->data.luaref);
@@ -1745,9 +1751,8 @@ static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key)
const size_t len = watcher->key_pattern_len;
if (len && watcher->key_pattern[len - 1] == '*') {
return strncmp(key, watcher->key_pattern, len - 1) == 0;
- } else {
- return strcmp(key, watcher->key_pattern) == 0;
}
+ return strcmp(key, watcher->key_pattern) == 0;
}
/// Send a change notification to all dictionary watchers that match given key
@@ -1839,6 +1844,7 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
di->di_key[key_len] = NUL;
di->di_flags = DI_FLAGS_ALLOC;
di->di_tv.v_lock = VAR_UNLOCKED;
+ di->di_tv.v_type = VAR_UNKNOWN;
return di;
}
@@ -2058,9 +2064,24 @@ int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
+ return tv_dict_get_number_def(d, key, 0);
+}
+
+/// Get a number item from a dictionary.
+///
+/// Returns "def" if the entry doesn't exist.
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Key to find in dictionary.
+/// @param[in] def Default value.
+///
+/// @return Dictionary item.
+varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key, const int def)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
dictitem_T *const di = tv_dict_find(d, key, -1);
if (di == NULL) {
- return 0;
+ return def;
}
return tv_get_number(&di->di_tv);
}
@@ -2079,7 +2100,7 @@ char **tv_dict_to_env(dict_T *denv)
TV_DICT_ITER(denv, var, {
const char *str = tv_get_string(&var->di_tv);
assert(str);
- size_t len = STRLEN(var->di_key) + strlen(str) + strlen("=") + 1;
+ size_t len = strlen((char *)var->di_key) + strlen(str) + strlen("=") + 1;
env[i] = xmalloc(len);
snprintf(env[i], len, "%s=%s", (char *)var->di_key, str);
i++;
@@ -2188,6 +2209,15 @@ bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_
return res;
}
+/// Check for adding a function to g: or l:.
+/// If the name is wrong give an error message and return true.
+int tv_dict_wrong_func_name(dict_T *d, typval_T *tv, const char *name)
+{
+ return (d == &globvardict || &d->dv_hashtab == get_funccal_local_ht())
+ && tv_is_func(*tv)
+ && var_wrong_func_name(name, true);
+}
+
//{{{2 dict_add*
/// Add item to dictionary
@@ -2199,7 +2229,10 @@ bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_
int tv_dict_add(dict_T *const d, dictitem_T *const item)
FUNC_ATTR_NONNULL_ALL
{
- return hash_add(&d->dv_hashtab, item->di_key);
+ if (tv_dict_wrong_func_name(d, &item->di_tv, (const char *)item->di_key)) {
+ return FAIL;
+ }
+ return hash_add(&d->dv_hashtab, (char *)item->di_key);
}
/// Add a list entry to dictionary
@@ -2415,10 +2448,10 @@ void tv_dict_clear(dict_T *const d)
///
/// @param d1 Dictionary to extend.
/// @param[in] d2 Dictionary to extend with.
-/// @param[in] action "error", "force", "keep":
-///
+/// @param[in] action "error", "force", "move", "keep":
/// e*, including "error": duplicate key gives an error.
/// f*, including "force": duplicate d2 keys override d1.
+/// m*, including "move": move items instead of copying.
/// other, including "keep": duplicate d2 keys ignored.
void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action)
FUNC_ATTR_NONNULL_ALL
@@ -2427,27 +2460,33 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
const char *const arg_errmsg = _("extend() argument");
const size_t arg_errmsg_len = strlen(arg_errmsg);
- TV_DICT_ITER(d2, di2, {
+ if (*action == 'm') {
+ hash_lock(&d2->dv_hashtab); // don't rehash on hash_remove()
+ }
+
+ HASHTAB_ITER(&d2->dv_hashtab, hi2, {
+ dictitem_T *const di2 = TV_DICT_HI2DI(hi2);
dictitem_T *const di1 = tv_dict_find(d1, (const char *)di2->di_key, -1);
- if (d1->dv_scope != VAR_NO_SCOPE) {
- // Disallow replacing a builtin function in l: and g:.
- // Check the key to be valid when adding to any scope.
- if (d1->dv_scope == VAR_DEF_SCOPE
- && tv_is_func(di2->di_tv)
- && !var_check_func_name((const char *)di2->di_key, di1 == NULL)) {
- break;
- }
- if (!valid_varname((const char *)di2->di_key)) {
- break;
- }
+ // Check the key to be valid when adding to any scope.
+ if (d1->dv_scope != VAR_NO_SCOPE && !valid_varname((const char *)di2->di_key)) {
+ break;
}
if (di1 == NULL) {
- dictitem_T *const new_di = tv_dict_item_copy(di2);
- if (tv_dict_add(d1, new_di) == FAIL) {
- tv_dict_item_free(new_di);
- } else if (watched) {
- tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv,
- NULL);
+ if (*action == 'm') {
+ // Cheap way to move a dict item from "d2" to "d1".
+ // If dict_add() fails then "d2" won't be empty.
+ dictitem_T *const new_di = di2;
+ if (tv_dict_add(d1, new_di) == OK) {
+ hash_remove(&d2->dv_hashtab, hi2);
+ tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv, NULL);
+ }
+ } else {
+ dictitem_T *const new_di = tv_dict_item_copy(di2);
+ if (tv_dict_add(d1, new_di) == FAIL) {
+ tv_dict_item_free(new_di);
+ } else if (watched) {
+ tv_dict_watcher_notify(d1, (const char *)new_di->di_key, &new_di->di_tv, NULL);
+ }
}
} else if (*action == 'e') {
semsg(_("E737: Key already exists: %s"), di2->di_key);
@@ -2455,10 +2494,14 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
} else if (*action == 'f' && di2 != di1) {
typval_T oldtv;
- if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
+ if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
|| var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
break;
}
+ // Disallow replacing a builtin function.
+ if (tv_dict_wrong_func_name(d1, &di2->di_tv, (const char *)di2->di_key)) {
+ break;
+ }
if (watched) {
tv_copy(&di1->di_tv, &oldtv);
@@ -2474,6 +2517,10 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action
}
}
});
+
+ if (*action == 'm') {
+ hash_unlock(&d2->dv_hashtab);
+ }
}
/// Compare two dictionaries
@@ -2488,10 +2535,14 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool
if (d1 == d2) {
return true;
}
- if (d1 == NULL || d2 == NULL) {
+ if (tv_dict_len(d1) != tv_dict_len(d2)) {
return false;
}
- if (tv_dict_len(d1) != tv_dict_len(d2)) {
+ if (tv_dict_len(d1) == 0) {
+ // empty and NULL dicts are considered equal
+ return true;
+ }
+ if (d1 == NULL || d2 == NULL) {
return false;
}
@@ -2537,7 +2588,7 @@ dict_T *tv_dict_copy(const vimconv_T *const conv, dict_T *const orig, const bool
if (conv == NULL || conv->vc_type == CONV_NONE) {
new_di = tv_dict_item_alloc((const char *)di->di_key);
} else {
- size_t len = STRLEN(di->di_key);
+ size_t len = strlen((char *)di->di_key);
char *const key = (char *)string_convert(conv, (char *)di->di_key, &len);
if (key == NULL) {
new_di = tv_dict_item_alloc_len((const char *)di->di_key, len);
@@ -2659,7 +2710,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
{
blob_T *const b = argvars[0].vval.v_blob;
- if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
+ if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
return;
}
@@ -2679,7 +2730,7 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
}
if (argvars[2].v_type == VAR_UNKNOWN) {
// Remove one item, return its value.
- char_u *const p = (char_u *)b->bv_ga.ga_data;
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
rettv->vval.v_number = (varnumber_T)(*(p + idx));
memmove(p + idx, p + idx + 1, (size_t)(len - idx - 1));
b->bv_ga.ga_len--;
@@ -2701,9 +2752,8 @@ void tv_blob_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
blob->bv_ga.ga_len = (int)(end - idx + 1);
ga_grow(&blob->bv_ga, (int)(end - idx + 1));
- char_u *const p = (char_u *)b->bv_ga.ga_data;
- memmove((char_u *)blob->bv_ga.ga_data, p + idx,
- (size_t)(end - idx + 1));
+ uint8_t *const p = (uint8_t *)b->bv_ga.ga_data;
+ memmove(blob->bv_ga.ga_data, p + idx, (size_t)(end - idx + 1));
tv_blob_set_ret(rettv, blob);
if (len - end - 1 > 0) {
@@ -2851,7 +2901,7 @@ void tv_dict_remove(typval_T *argvars, typval_T *rettv, const char *arg_errmsg)
if (argvars[2].v_type != VAR_UNKNOWN) {
semsg(_(e_toomanyarg), "remove()");
} else if ((d = argvars[0].vval.v_dict) != NULL
- && !var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ && !value_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *key = tv_get_string_chk(&argvars[1]);
if (key != NULL) {
dictitem_T *di = tv_dict_find(d, key, -1);
@@ -2956,7 +3006,7 @@ void tv_blob_copy(typval_T *const from, typval_T *const to)
(tv)->v_lock = VAR_UNLOCKED; \
} while (0)
-static inline int _nothing_conv_func_start(typval_T *const tv, char_u *const fun)
+static inline int _nothing_conv_func_start(typval_T *const tv, char *const fun)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
{
tv->v_lock = VAR_UNLOCKED;
@@ -3119,6 +3169,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic
#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
#include "nvim/eval/typval_encode.c.h"
+
#undef TYPVAL_ENCODE_SCOPE
#undef TYPVAL_ENCODE_NAME
#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
@@ -3183,7 +3234,7 @@ void tv_free(typval_T *tv)
partial_unref(tv->vval.v_partial);
break;
case VAR_FUNC:
- func_unref((char_u *)tv->vval.v_string);
+ func_unref(tv->vval.v_string);
FALLTHROUGH;
case VAR_STRING:
xfree(tv->vval.v_string);
@@ -3236,7 +3287,7 @@ void tv_copy(const typval_T *const from, typval_T *const to)
if (from->vval.v_string != NULL) {
to->vval.v_string = xstrdup(from->vval.v_string);
if (from->v_type == VAR_FUNC) {
- func_ref((char_u *)to->vval.v_string);
+ func_ref(to->vval.v_string);
}
}
break;
@@ -3408,12 +3459,12 @@ bool tv_check_lock(const typval_T *tv, const char *name, size_t name_len)
default:
break;
}
- return var_check_lock(tv->v_lock, name, name_len)
- || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len));
+ return value_check_lock(tv->v_lock, name, name_len)
+ || (lock != VAR_UNLOCKED && value_check_lock(lock, name, name_len));
}
-/// @return true if variable "name" is locked (immutable)
-bool var_check_lock(VarLockStatus lock, const char *name, size_t name_len)
+/// @return true if variable "name" has a locked (immutable) value
+bool value_check_lock(VarLockStatus lock, const char *name, size_t name_len)
{
const char *error_message = NULL;
switch (lock) {
@@ -3588,13 +3639,13 @@ bool tv_check_str_or_nr(const typval_T *const tv)
#define FUNC_ERROR "E703: Using a Funcref as a Number"
static const char *const num_errors[] = {
- [VAR_PARTIAL]=N_(FUNC_ERROR),
- [VAR_FUNC]=N_(FUNC_ERROR),
- [VAR_LIST]=N_("E745: Using a List as a Number"),
- [VAR_DICT]=N_("E728: Using a Dictionary as a Number"),
- [VAR_FLOAT]=N_("E805: Using a Float as a Number"),
- [VAR_BLOB]=N_("E974: Using a Blob as a Number"),
- [VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
+ [VAR_PARTIAL]= N_(FUNC_ERROR),
+ [VAR_FUNC]= N_(FUNC_ERROR),
+ [VAR_LIST]= N_("E745: Using a List as a Number"),
+ [VAR_DICT]= N_("E728: Using a Dictionary as a Number"),
+ [VAR_FLOAT]= N_("E805: Using a Float as a Number"),
+ [VAR_BLOB]= N_("E974: Using a Blob as a Number"),
+ [VAR_UNKNOWN]= N_("E685: using an invalid value as a Number"),
};
#undef FUNC_ERROR
@@ -3633,13 +3684,13 @@ bool tv_check_num(const typval_T *const tv)
#define FUNC_ERROR "E729: using Funcref as a String"
static const char *const str_errors[] = {
- [VAR_PARTIAL]=N_(FUNC_ERROR),
- [VAR_FUNC]=N_(FUNC_ERROR),
- [VAR_LIST]=N_("E730: using List as a String"),
- [VAR_DICT]=N_("E731: using Dictionary as a String"),
- [VAR_FLOAT]=((const char *)e_float_as_string),
- [VAR_BLOB]=N_("E976: using Blob as a String"),
- [VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
+ [VAR_PARTIAL]= N_(FUNC_ERROR),
+ [VAR_FUNC]= N_(FUNC_ERROR),
+ [VAR_LIST]= N_("E730: using List as a String"),
+ [VAR_DICT]= N_("E731: using Dictionary as a String"),
+ [VAR_FLOAT]= ((const char *)e_float_as_string),
+ [VAR_BLOB]= N_("E976: using Blob as a String"),
+ [VAR_UNKNOWN]= N_("E908: using an invalid value as a String"),
};
#undef FUNC_ERROR
@@ -3851,6 +3902,17 @@ int tv_check_for_opt_number_arg(const typval_T *const args, const int idx)
|| tv_check_for_number_arg(args, idx) != FAIL) ? OK : FAIL;
}
+/// Give an error and return FAIL unless "args[idx]" is a string or a list.
+int tv_check_for_string_or_list_arg(const typval_T *const args, const int idx)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ if (args[idx].v_type != VAR_STRING && args[idx].v_type != VAR_LIST) {
+ semsg(_(e_string_or_list_required_for_argument_nr), idx + 1);
+ return FAIL;
+ }
+ return OK;
+}
+
/// Get the string value of a "stringish" VimL object.
///
/// @param[in] tv Object to get value of.
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 0a4adc1f53..3f59cd3547 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -4,14 +4,19 @@
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/gettext.h"
+#include "nvim/hashtab.h"
+#include "nvim/lib/queue.h"
#include "nvim/macros.h"
#include "nvim/mbyte_defs.h"
#include "nvim/message.h"
+#include "nvim/types.h"
#ifdef LOG_LIST_ACTIONS
# include "nvim/memory.h"
@@ -43,10 +48,8 @@ static inline ListLog *list_log_new(const size_t size)
return ret;
}
-static inline void list_log(const list_T *const l,
- const listitem_T *const li1,
- const listitem_T *const li2,
- const char *const action)
+static inline void list_log(const list_T *const l, const listitem_T *const li1,
+ const listitem_T *const li2, const char *const action)
REAL_FATTR_ALWAYS_INLINE;
/// Add new entry to log
@@ -90,7 +93,7 @@ static inline void list_log(const list_T *const l, const listitem_T *const li1,
#define TV_DICT_HI2DI(hi) \
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
-static inline void tv_list_ref(list_T *const l)
+static inline void tv_list_ref(list_T *l)
REAL_FATTR_ALWAYS_INLINE;
/// Increase reference count for a given list
@@ -106,7 +109,7 @@ static inline void tv_list_ref(list_T *const l)
l->lv_refcount++;
}
-static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
+static inline void tv_list_set_ret(typval_T *tv, list_T *l)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a list as the return value. Increments the reference count.
@@ -120,7 +123,7 @@ static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
tv_list_ref(l);
}
-static inline VarLockStatus tv_list_locked(const list_T *const l)
+static inline VarLockStatus tv_list_locked(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get list lock status
@@ -163,7 +166,7 @@ static inline void tv_list_set_copyid(list_T *const l, const int copyid)
l->lv_copyID = copyid;
}
-static inline int tv_list_len(const list_T *const l)
+static inline int tv_list_len(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a list
@@ -178,7 +181,7 @@ static inline int tv_list_len(const list_T *const l)
return l->lv_len;
}
-static inline int tv_list_copyid(const list_T *const l)
+static inline int tv_list_copyid(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
/// Get list copyID
@@ -191,7 +194,7 @@ static inline int tv_list_copyid(const list_T *const l)
return l->lv_copyID;
}
-static inline list_T *tv_list_latest_copy(const list_T *const l)
+static inline list_T *tv_list_latest_copy(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
/// Get latest list copy
@@ -206,7 +209,7 @@ static inline list_T *tv_list_latest_copy(const list_T *const l)
return l->lv_copylist;
}
-static inline int tv_list_uidx(const list_T *const l, int n)
+static inline int tv_list_uidx(const list_T *l, int n)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Normalize index: that is, return either -1 or non-negative index
@@ -229,7 +232,7 @@ static inline int tv_list_uidx(const list_T *const l, int n)
return n;
}
-static inline bool tv_list_has_watchers(const list_T *const l)
+static inline bool tv_list_has_watchers(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check whether list has watchers
@@ -244,7 +247,7 @@ static inline bool tv_list_has_watchers(const list_T *const l)
return l && l->lv_watch;
}
-static inline listitem_T *tv_list_first(const list_T *const l)
+static inline listitem_T *tv_list_first(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get first list item
@@ -262,7 +265,7 @@ static inline listitem_T *tv_list_first(const list_T *const l)
return l->lv_first;
}
-static inline listitem_T *tv_list_last(const list_T *const l)
+static inline listitem_T *tv_list_last(const list_T *l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get last list item
@@ -280,7 +283,7 @@ static inline listitem_T *tv_list_last(const list_T *const l)
return l->lv_last;
}
-static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
+static inline void tv_dict_set_ret(typval_T *tv, dict_T *d)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a dictionary as the return value
@@ -296,7 +299,7 @@ static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
}
}
-static inline long tv_dict_len(const dict_T *const d)
+static inline long tv_dict_len(const dict_T *d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a Dictionary
@@ -310,7 +313,7 @@ static inline long tv_dict_len(const dict_T *const d)
return (long)d->dv_hashtab.ht_used;
}
-static inline bool tv_dict_is_watched(const dict_T *const d)
+static inline bool tv_dict_is_watched(const dict_T *d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check if dictionary is watched
@@ -323,7 +326,7 @@ static inline bool tv_dict_is_watched(const dict_T *const d)
return d && !QUEUE_EMPTY(&d->watchers);
}
-static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
+static inline void tv_blob_set_ret(typval_T *tv, blob_T *b)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
/// Set a blob as the return value.
@@ -341,7 +344,7 @@ static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
}
}
-static inline int tv_blob_len(const blob_T *const b)
+static inline int tv_blob_len(const blob_T *b)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the length of the data in the blob, in bytes.
@@ -355,7 +358,7 @@ static inline int tv_blob_len(const blob_T *const b)
return b->bv_ga.ga_len;
}
-static inline char_u tv_blob_get(const blob_T *const b, int idx)
+static inline uint8_t tv_blob_get(const blob_T *b, int idx)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the byte at index `idx` in the blob.
@@ -364,12 +367,12 @@ static inline char_u tv_blob_get(const blob_T *const b, int idx)
/// @param[in] idx Index in a blob. Must be valid.
///
/// @return Byte value at the given index.
-static inline char_u tv_blob_get(const blob_T *const b, int idx)
+static inline uint8_t tv_blob_get(const blob_T *const b, int idx)
{
- return ((char_u *)b->bv_ga.ga_data)[idx];
+ return ((uint8_t *)b->bv_ga.ga_data)[idx];
}
-static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+static inline void tv_blob_set(blob_T *b, int idx, uint8_t c)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
/// Store the byte `c` at index `idx` in the blob.
@@ -377,9 +380,9 @@ static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
/// @param[in] b Blob to index. Cannot be NULL.
/// @param[in] idx Index in a blob. Must be valid.
/// @param[in] c Value to store.
-static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+static inline void tv_blob_set(blob_T *const b, int idx, uint8_t c)
{
- ((char_u *)b->bv_ga.ga_data)[idx] = c;
+ ((uint8_t *)b->bv_ga.ga_data)[idx] = c;
}
/// Initialize VimL object
@@ -431,7 +434,7 @@ extern bool tv_in_free_unref_items;
/// @param li Name of the variable with current listitem_T entry.
/// @param code Cycle body.
#define TV_LIST_ITER(l, li, code) \
- _TV_LIST_ITER_MOD( , l, li, code)
+ _TV_LIST_ITER_MOD( , l, li, code) // NOLINT(whitespace/parens)
/// Iterate over a list
///
@@ -488,8 +491,7 @@ extern bool tv_in_free_unref_items;
} \
})
-static inline bool tv_get_float_chk(const typval_T *const tv,
- float_T *const ret_f)
+static inline bool tv_get_float_chk(const typval_T *tv, float_T *ret_f)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the float value
@@ -527,7 +529,7 @@ static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
return QUEUE_DATA(q, DictWatcher, node);
}
-static inline bool tv_is_func(const typval_T tv)
+static inline bool tv_is_func(typval_T tv)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
/// Check whether given typval_T contains a function
@@ -562,4 +564,9 @@ EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h"
#endif
+
+#define tv_get_bool tv_get_number
+#define tv_get_bool_chk tv_get_number_chk
+#define tv_dict_get_bool tv_dict_get_number_def
+
#endif // NVIM_EVAL_TYPVAL_H
diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h
index 1c0a438751..4615198441 100644
--- a/src/nvim/eval/typval_defs.h
+++ b/src/nvim/eval/typval_defs.h
@@ -206,7 +206,7 @@ typedef struct {
struct { \
typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
uint8_t di_flags; /* Flags. */ \
- char_u di_key[__VA_ARGS__]; /* Key value. */ \
+ char_u di_key[__VA_ARGS__]; /* Key value. */ /* NOLINT(runtime/arrays)*/ \
}
/// Structure to hold a scope dictionary
@@ -337,9 +337,9 @@ struct ufunc {
///< used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
- char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with
+ char *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with
///< "<SNR>" as a string, otherwise NULL
- char_u uf_name[]; ///< Name of function (actual size equals name);
+ char uf_name[]; ///< Name of function (actual size equals name);
///< can start with <SNR>123_
///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
};
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index ff4f92e40b..6d29286a58 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -266,7 +266,7 @@ static inline int _TYPVAL_ENCODE_CHECK_SELF_REFERENCE(
const MPConvStack *const mpstack, const int copyID,
const MPConvStackValType conv_type,
const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 3, 4, 7) REAL_FATTR_WARN_UNUSED_RESULT
+ REAL_FATTR_NONNULL_ARG(2, 3, 4, 7) REAL_FATTR_WARN_UNUSED_RESULT
REAL_FATTR_ALWAYS_INLINE;
/// Function for checking whether container references itself
@@ -301,7 +301,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
MPConvStack *const mpstack, MPConvStackVal *const cur_mpsv,
typval_T *const tv, const int copyID,
const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 4, 6) REAL_FATTR_WARN_UNUSED_RESULT;
+ REAL_FATTR_NONNULL_ARG(2, 4, 6) REAL_FATTR_WARN_UNUSED_RESULT;
/// Convert single value
///
@@ -339,7 +339,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
tv_blob_len(tv->vval.v_blob));
break;
case VAR_FUNC:
- TYPVAL_ENCODE_CONV_FUNC_START(tv, (char_u *)tv->vval.v_string);
+ TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string);
TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0);
TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, -1);
TYPVAL_ENCODE_CONV_FUNC_END(tv);
@@ -347,7 +347,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_PARTIAL: {
partial_T *const pt = tv->vval.v_partial;
(void)pt;
- TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : (char_u *)partial_name(pt))); // -V547
+ TYPVAL_ENCODE_CONV_FUNC_START(tv, (pt == NULL ? NULL : partial_name(pt))); // -V547
_mp_push(*mpstack, ((MPConvStackVal) { // -V779
.type = kMPConvPartial,
.tv = tv,
@@ -358,7 +358,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.pt = tv->vval.v_partial,
},
},
- }));
+ }));
break;
}
case VAR_LIST: {
@@ -381,7 +381,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(tv->vval.v_list),
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, _mp_last(*mpstack));
break;
}
@@ -459,8 +459,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const listitem_T *const highest_bits_li = (
TV_LIST_ITEM_NEXT(val_list, sign_li));
if (TV_LIST_ITEM_TV(highest_bits_li)->v_type != VAR_NUMBER
- || ((highest_bits
- = TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
+ || ((highest_bits = TV_LIST_ITEM_TV(highest_bits_li)->vval.v_number)
< 0)) {
goto _convert_one_value_regular_dict;
}
@@ -536,7 +535,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(val_di->di_tv.vval.v_list),
},
},
- }));
+ }));
break;
}
case kMPMap: {
@@ -571,7 +570,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
.li = tv_list_first(val_list),
},
},
- }));
+ }));
break;
}
case kMPExt: {
@@ -581,8 +580,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
|| tv_list_len((val_list = val_di->di_tv.vval.v_list)) != 2
|| (TV_LIST_ITEM_TV(tv_list_first(val_list))->v_type
!= VAR_NUMBER)
- || ((type
- = TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
+ || ((type = TV_LIST_ITEM_TV(tv_list_first(val_list))->vval.v_number)
> INT8_MAX)
|| type < INT8_MIN
|| (TV_LIST_ITEM_TV(tv_list_last(val_list))->v_type
@@ -622,7 +620,7 @@ _convert_one_value_regular_dict: {}
.todo = tv->vval.v_dict->dv_hashtab.ht_used,
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, tv->vval.v_dict,
_mp_last(*mpstack));
break;
@@ -640,7 +638,7 @@ typval_encode_stop_converting_one_item:
TYPVAL_ENCODE_SCOPE int _TYPVAL_ENCODE_ENCODE(
TYPVAL_ENCODE_FIRST_ARG_TYPE TYPVAL_ENCODE_FIRST_ARG_NAME,
typval_T *const tv, const char *const objname)
-REAL_FATTR_NONNULL_ARG(2, 3) REAL_FATTR_WARN_UNUSED_RESULT;
+ REAL_FATTR_NONNULL_ARG(2, 3) REAL_FATTR_WARN_UNUSED_RESULT;
/// Convert the whole typval
///
@@ -758,7 +756,7 @@ typval_encode_stop_converting_one_item:
.todo = (size_t)pt->pt_argc,
},
},
- }));
+ }));
}
break;
case kMPConvPartialSelf: {
@@ -797,7 +795,7 @@ typval_encode_stop_converting_one_item:
.todo = dict->dv_hashtab.ht_used,
},
},
- }));
+ }));
TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(NULL, pt->pt_dict,
_mp_last(mpstack));
} else {
diff --git a/src/nvim/eval/typval_encode.h b/src/nvim/eval/typval_encode.h
index 33e19c531c..2f19144da3 100644
--- a/src/nvim/eval/typval_encode.h
+++ b/src/nvim/eval/typval_encode.h
@@ -71,7 +71,7 @@ typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;
#define _mp_pop kv_pop
#define _mp_last kv_last
-static inline size_t tv_strlen(const typval_T *const tv)
+static inline size_t tv_strlen(const typval_T *tv)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT
REAL_FATTR_NONNULL_ALL;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index b0a56c4440..22c5b1954d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3,28 +3,49 @@
// User defined function support
+#include <assert.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lauxlib.h"
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
-#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
#include "nvim/globals.h"
#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline_defs.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/option_defs.h"
#include "nvim/os/input.h"
+#include "nvim/path.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/search.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -48,6 +69,8 @@ static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace
static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_nofunc = N_("E130: Unknown function: %s");
+static char e_no_white_space_allowed_before_str_str[]
+ = N_("E1068: No white space allowed before '%s': %s");
void func_init(void)
{
@@ -61,7 +84,7 @@ hashtab_T *func_tbl_get(void)
}
/// Get function arguments.
-static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int *varargs,
+static int get_function_args(char **argp, char endchar, garray_T *newargs, int *varargs,
garray_T *default_args, bool skip)
{
bool mustend = false;
@@ -71,10 +94,10 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
int i;
if (newargs != NULL) {
- ga_init(newargs, (int)sizeof(char_u *), 3);
+ ga_init(newargs, (int)sizeof(char *), 3);
}
if (default_args != NULL) {
- ga_init(default_args, (int)sizeof(char_u *), 3);
+ ga_init(default_args, (int)sizeof(char *), 3);
}
if (varargs != NULL) {
@@ -83,7 +106,7 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
// Isolate the arguments: "arg1, arg2, ...)"
bool any_default = false;
- while (*p != (char)endchar) {
+ while (*p != endchar) {
if (p[0] == '.' && p[1] == '.' && p[2] == '.') {
if (varargs != NULL) {
*varargs = true;
@@ -95,9 +118,9 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
while (ASCII_ISALNUM(*p) || *p == '_') {
p++;
}
- if (arg == p || isdigit(*arg)
- || (p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
- || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0)) {
+ if (arg == p || isdigit((uint8_t)(*arg))
+ || (p - arg == 9 && strncmp(arg, "firstline", 9) == 0)
+ || (p - arg == 8 && strncmp(arg, "lastline", 8) == 0)) {
if (!skip) {
semsg(_("E125: Illegal argument: %s"), arg);
}
@@ -149,6 +172,15 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
emsg(_("E989: Non-default argument follows default argument"));
mustend = true;
}
+
+ if (ascii_iswhite(*p) && *skipwhite(p) == ',') {
+ // Be tolerant when skipping
+ if (!skip) {
+ semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
+ goto err_ret;
+ }
+ p = skipwhite(p);
+ }
if (*p == ',') {
p++;
} else {
@@ -156,14 +188,14 @@ static int get_function_args(char **argp, char_u endchar, garray_T *newargs, int
}
}
p = skipwhite(p);
- if (mustend && *p != (char)endchar) {
+ if (mustend && *p != endchar) {
if (!skip) {
semsg(_(e_invarg2), *argp);
}
break;
}
}
- if (*p != (char)endchar) {
+ if (*p != endchar) {
goto err_ret;
}
p++; // skip "endchar"
@@ -197,21 +229,21 @@ static void register_closure(ufunc_T *fp)
}
/// @return a name for a lambda. Returned in static memory.
-char_u *get_lambda_name(void)
+char *get_lambda_name(void)
{
- static char_u name[30];
+ static char name[30];
static int lambda_no = 0;
- snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
+ snprintf(name, sizeof(name), "<lambda>%d", ++lambda_no);
return name;
}
-static void set_ufunc_name(ufunc_T *fp, char_u *name)
+static void set_ufunc_name(ufunc_T *fp, char *name)
{
STRCPY(fp->uf_name, name);
- if (name[0] == K_SPECIAL) {
- fp->uf_name_exp = xmalloc(STRLEN(name) + 3);
+ if ((uint8_t)name[0] == K_SPECIAL) {
+ fp->uf_name_exp = xmalloc(strlen(name) + 3);
STRCPY(fp->uf_name_exp, "<SNR>");
STRCAT(fp->uf_name_exp, fp->uf_name + 3);
}
@@ -228,13 +260,13 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
partial_T *pt = NULL;
int varargs;
int ret;
- char_u *start = (char_u *)skipwhite(*arg + 1);
- char_u *s, *e;
+ char *start = skipwhite(*arg + 1);
+ char *s, *e;
bool *old_eval_lavars = eval_lavars_used;
bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
- ret = get_function_args((char **)&start, '-', NULL, NULL, NULL, true);
+ ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
if (ret == FAIL || *start != '>') {
return NOTDONE;
}
@@ -258,38 +290,39 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
// Get the start and the end of the expression.
*arg = skipwhite((*arg) + 1);
- s = (char_u *)(*arg);
+ s = *arg;
ret = skip_expr(arg);
if (ret == FAIL) {
goto errret;
}
- e = (char_u *)(*arg);
+ e = *arg;
*arg = skipwhite(*arg);
if (**arg != '}') {
+ semsg(_("E451: Expected }: %s"), *arg);
goto errret;
}
(*arg)++;
if (evaluate) {
int flags = 0;
- char_u *p;
+ char *p;
garray_T newlines;
- char_u *name = get_lambda_name();
+ char *name = get_lambda_name();
- fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1);
pt = xcalloc(1, sizeof(partial_T));
- ga_init(&newlines, (int)sizeof(char_u *), 1);
+ ga_init(&newlines, (int)sizeof(char *), 1);
ga_grow(&newlines, 1);
// Add "return " before the expression.
size_t len = (size_t)(7 + e - s + 1);
- p = (char_u *)xmalloc(len);
- ((char **)(newlines.ga_data))[newlines.ga_len++] = (char *)p;
+ p = xmalloc(len);
+ ((char **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
- STRLCPY(p + 7, s, e - s + 1);
- if (strstr((char *)p + 7, "a:") == NULL) {
+ xstrlcpy(p + 7, s, (size_t)(e - s) + 1);
+ if (strstr(p + 7, "a:") == NULL) {
// No a: variables are used for sure.
flags |= FC_NOARGS;
}
@@ -298,7 +331,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
set_ufunc_name(fp, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
- ga_init(&fp->uf_def_args, (int)sizeof(char_u *), 1);
+ ga_init(&fp->uf_def_args, (int)sizeof(char *), 1);
fp->uf_lines = newlines;
if (current_funccal != NULL && eval_lavars) {
flags |= FC_CLOSURE;
@@ -351,7 +384,7 @@ errret:
/// was not found.
///
/// @return name of the function.
-char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
+char *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
if (partialp != NULL) {
@@ -362,10 +395,10 @@ char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp,
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
if (v->di_tv.vval.v_string == NULL) { // just in case
*lenp = 0;
- return (char_u *)"";
+ return "";
}
*lenp = (int)strlen(v->di_tv.vval.v_string);
- return (char_u *)v->di_tv.vval.v_string;
+ return v->di_tv.vval.v_string;
}
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) {
@@ -373,31 +406,31 @@ char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp,
if (pt == NULL) { // just in case
*lenp = 0;
- return (char_u *)"";
+ return "";
}
if (partialp != NULL) {
*partialp = pt;
}
- char_u *s = (char_u *)partial_name(pt);
- *lenp = (int)STRLEN(s);
+ char *s = partial_name(pt);
+ *lenp = (int)strlen(s);
return s;
}
- return (char_u *)name;
+ return (char *)name;
}
/// Give an error message with a function name. Handle <SNR> things.
///
/// @param ermsg must be passed without translation (use N_() instead of _()).
/// @param name function name
-void emsg_funcname(char *ermsg, const char_u *name)
+void emsg_funcname(char *ermsg, const char *name)
{
- char_u *p;
+ char *p;
- if (*name == K_SPECIAL) {
- p = (char_u *)concat_str("<SNR>", (char *)name + 3);
+ if ((uint8_t)(*name) == K_SPECIAL) {
+ p = concat_str("<SNR>", name + 3);
} else {
- p = (char_u *)name;
+ p = (char *)name;
}
semsg(_(ermsg), p);
@@ -415,7 +448,7 @@ void emsg_funcname(char *ermsg, const char_u *name)
/// @param funcexe various values
///
/// @return OK or FAIL.
-int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe)
+int get_func_tv(const char *name, int len, typval_T *rettv, char **arg, funcexe_T *funcexe)
{
char *argp;
int ret = OK;
@@ -449,7 +482,7 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
int i = 0;
if (get_vim_var_nr(VV_TESTING)) {
- // Prepare for calling garbagecollect_for_testing(), need to know
+ // Prepare for calling test_garbagecollect_now(), need to know
// what variables are used on the call stack.
if (funcargs.ga_itemsize == 0) {
ga_init(&funcargs, (int)sizeof(typval_T *), 50);
@@ -459,7 +492,7 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = &argvars[i];
}
}
- ret = call_func((char *)name, len, rettv, argcount, argvars, funcexe);
+ ret = call_func(name, len, rettv, argcount, argvars, funcexe);
funcargs.ga_len -= i;
} else if (!aborting()) {
@@ -549,9 +582,9 @@ static char *fname_trans_sid(const char *const name, char *const fname_buf, char
/// Find a function by name, return pointer to it in ufuncs.
///
/// @return NULL for unknown function.
-ufunc_T *find_func(const char_u *name)
+ufunc_T *find_func(const char *name)
{
- hashitem_T *hi = hash_find(&func_hashtab, (char *)name);
+ hashitem_T *hi = hash_find(&func_hashtab, name);
if (!HASHITEM_EMPTY(hi)) {
return HI2UF(hi);
}
@@ -561,9 +594,9 @@ ufunc_T *find_func(const char_u *name)
/// Copy the function name of "fp" to buffer "buf".
/// "buf" must be able to hold the function name plus three bytes.
/// Takes care of script-local function names.
-static void cat_func_name(char_u *buf, ufunc_T *fp)
+static void cat_func_name(char *buf, ufunc_T *fp)
{
- if (fp->uf_name[0] == K_SPECIAL) {
+ if ((uint8_t)fp->uf_name[0] == K_SPECIAL) {
STRCPY(buf, "<SNR>");
STRCAT(buf, fp->uf_name + 3);
} else {
@@ -578,7 +611,7 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr)
STRCPY(v->di_key, name);
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(dp, v);
+ hash_add(&dp->dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_NUMBER;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_number = nr;
@@ -813,7 +846,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
int fixvar_idx = 0; // index in fixvar[]
int ai;
bool islambda = false;
- char_u numbuf[NUMBUFLEN];
+ char numbuf[NUMBUFLEN];
char *name;
typval_T *tv_to_free[MAX_FUNC_ARGS];
int tv_to_free_len = 0;
@@ -855,7 +888,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
ga_init(&fc->fc_funcs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
- if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0) {
+ if (strncmp(fp->uf_name, "<lambda>", 8) == 0) {
islambda = true;
}
@@ -874,7 +907,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
STRCPY(name, "self");
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_vars, v);
+ hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_DICT;
v->di_tv.v_lock = VAR_UNLOCKED;
v->di_tv.vval.v_dict = selfdict;
@@ -900,7 +933,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
STRCPY(name, "000");
#endif
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_avars, v);
+ hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key);
v->di_tv.v_type = VAR_LIST;
v->di_tv.v_lock = VAR_FIXED;
v->di_tv.vval.v_list = &fc->l_varlist;
@@ -952,8 +985,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
break;
}
// "..." argument a:1, a:2, etc.
- snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1);
- name = (char *)numbuf;
+ snprintf(numbuf, sizeof(numbuf), "%d", ai + 1);
+ name = numbuf;
}
if (fixvar_idx < FIXVAR_CNT && strlen(name) <= VAR_SHORT_LEN) {
v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
@@ -978,16 +1011,16 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
// Named arguments can be accessed without the "a:" prefix in lambda
// expressions. Add to the l: dict.
tv_copy(&v->di_tv, &v->di_tv);
- tv_dict_add(&fc->l_vars, v);
+ hash_add(&fc->l_vars.dv_hashtab, (char *)v->di_key);
} else {
- tv_dict_add(&fc->l_avars, v);
+ hash_add(&fc->l_avars.dv_hashtab, (char *)v->di_key);
}
if (ai >= 0 && ai < MAX_FUNC_ARGS) {
listitem_T *li = &fc->l_listitems[ai];
*TV_LIST_ITEM_TV(li) = argvars[i];
- TV_LIST_ITEM_TV(li)->v_lock = VAR_FIXED;
+ TV_LIST_ITEM_TV(li)->v_lock = VAR_FIXED;
tv_list_append(&fc->l_varlist, li);
}
}
@@ -1193,9 +1226,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
/// For the first we only count the name stored in func_hashtab as a reference,
/// using function() does not count as a reference, because the function is
/// looked up by name.
-static bool func_name_refcount(char_u *name)
+static bool func_name_refcount(const char *name)
{
- return isdigit(*name) || *name == '<';
+ return isdigit((uint8_t)(*name)) || *name == '<';
}
/// Call a user function after checking the arguments.
@@ -1265,7 +1298,7 @@ void free_all_functions(void)
ufunc_T *fp;
uint64_t skipped = 0;
uint64_t todo = 1;
- uint64_t used;
+ int changed;
// Clean up the current_funccal chain and the funccal stack.
while (current_funccal != NULL) {
@@ -1289,9 +1322,9 @@ void free_all_functions(void)
if (func_name_refcount(fp->uf_name)) {
skipped++;
} else {
- used = func_hashtab.ht_used;
+ changed = func_hashtab.ht_changed;
func_clear(fp, true);
- if (used != func_hashtab.ht_used) {
+ if (changed != func_hashtab.ht_changed) {
skipped = 0;
break;
}
@@ -1335,10 +1368,10 @@ void free_all_functions(void)
/// @param[in] len length of "name", or -1 for NUL terminated.
///
/// @return true if "name" looks like a builtin function name: starts with a
-/// lower case letter and doesn't contain AUTOLOAD_CHAR.
+/// lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
static bool builtin_function(const char *name, int len)
{
- if (!ASCII_ISLOWER(name[0])) {
+ if (!ASCII_ISLOWER(name[0]) || name[1] == ':') {
return false;
}
@@ -1349,7 +1382,7 @@ static bool builtin_function(const char *name, int len)
return p == NULL;
}
-int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
+int func_call(char *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
{
typval_T argv[MAX_FUNC_ARGS + 1];
int argc = 0;
@@ -1371,7 +1404,7 @@ int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict
funcexe.fe_evaluate = true;
funcexe.fe_partial = partial;
funcexe.fe_selfdict = selfdict;
- r = call_func((char *)name, -1, rettv, argc, argv, &funcexe);
+ r = call_func(name, -1, rettv, argc, argv, &funcexe);
func_call_skip_call:
// Free the arguments.
@@ -1382,9 +1415,27 @@ func_call_skip_call:
return r;
}
+/// call the 'callback' function and return the result as a number.
+/// Returns -2 when calling the function fails. Uses argv[0] to argv[argc - 1]
+/// for the function arguments. argv[argc] should have type VAR_UNKNOWN.
+///
+/// @param argcount number of "argvars"
+/// @param argvars vars for arguments, must have "argcount" PLUS ONE elements!
+varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argvars)
+{
+ typval_T rettv;
+ if (!callback_call(callback, argcount, argvars, &rettv)) {
+ return -2;
+ }
+
+ varnumber_T retval = tv_get_number_chk(&rettv, NULL);
+ tv_clear(&rettv);
+ return retval;
+}
+
/// Give an error message for the result of a function.
/// Nothing if "error" is FCERR_NONE.
-static void user_func_error(int error, const char_u *name)
+static void user_func_error(int error, const char *name)
FUNC_ATTR_NONNULL_ALL
{
switch (error) {
@@ -1401,16 +1452,13 @@ static void user_func_error(int error, const char_u *name)
emsg_funcname(_(e_toomanyarg), name);
break;
case FCERR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"),
- name);
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"), name);
break;
case FCERR_SCRIPT:
- emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
- name);
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), name);
break;
case FCERR_DICT:
- emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
- name);
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name);
break;
}
}
@@ -1477,7 +1525,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
// Make a copy of the name, if it comes from a funcref variable it could
// be changed or deleted in the called function.
name = xstrnsave(funcname, (size_t)len);
- fname = fname_trans_sid(name, (char *)fname_buf, &tofree, &error);
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
}
if (funcexe->fe_doesrange != NULL) {
@@ -1532,7 +1580,7 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
if (fp == NULL) {
- fp = find_func((char_u *)rfname);
+ fp = find_func(rfname);
}
// Trigger FuncUndefined event, may load the function.
@@ -1540,13 +1588,13 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
&& apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL)
&& !aborting()) {
// executed an autocommand, search for the function again
- fp = find_func((char_u *)rfname);
+ fp = find_func(rfname);
}
// Try loading a package.
if (fp == NULL && script_autoload((const char *)rfname, strlen(rfname),
true) && !aborting()) {
// Loaded a package, search for the function again.
- fp = find_func((char_u *)rfname);
+ fp = find_func(rfname);
}
if (fp != NULL && (fp->uf_flags & FC_DELETED)) {
@@ -1564,11 +1612,11 @@ int call_func(const char *funcname, int len, typval_T *rettv, int argcount_in, t
} else if (funcexe->fe_basetv != NULL) {
// expr->method(): Find the method name in the table, call its
// implementation with the base as one of the arguments.
- error = call_internal_method((char_u *)fname, argcount, argvars, rettv,
+ error = call_internal_method(fname, argcount, argvars, rettv,
funcexe->fe_basetv);
} else {
// Find the function name in the table, call its implementation.
- error = call_internal_func((char_u *)fname, argcount, argvars, rettv);
+ error = call_internal_func(fname, argcount, argvars, rettv);
}
// The function call (or "FuncUndefined" autocommand sequence) might
// have been aborted by an error, an interrupt, or an explicitly thrown
@@ -1588,7 +1636,7 @@ theend:
// Report an error unless the argument evaluation or function call has been
// cancelled due to an aborting error, an interrupt, or an exception.
if (!aborting()) {
- user_func_error(error, (name != NULL) ? (char_u *)name : (char_u *)funcname);
+ user_func_error(error, (name != NULL) ? name : funcname);
}
// clear the copies made from the partial
@@ -1602,6 +1650,11 @@ theend:
return ret;
}
+char *printable_func_name(ufunc_T *fp)
+{
+ return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
+}
+
/// List the head of the function: "name(arg1, arg2)".
///
/// @param[in] fp Function pointer.
@@ -1671,12 +1724,12 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
/// @param partial return: partial of a FuncRef
///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial)
+char *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, partial_T **partial)
FUNC_ATTR_NONNULL_ARG(1)
{
char *name = NULL;
- const char_u *start;
- const char_u *end;
+ const char *start;
+ const char *end;
int lead;
int len;
lval_T lv;
@@ -1684,7 +1737,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
if (fdp != NULL) {
CLEAR_POINTER(fdp);
}
- start = (char_u *)(*pp);
+ start = *pp;
// Check for hard coded <SNR>: already translated function ID (from a user
// command).
@@ -1692,19 +1745,19 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
&& (*pp)[2] == KE_SNR) {
*pp += 3;
len = get_id_len((const char **)pp) + 3;
- return (char_u *)xmemdupz(start, (size_t)len);
+ return xmemdupz(start, (size_t)len);
}
// A name starting with "<SID>" or "<SNR>" is local to a script. But
// don't skip over "s:", get_lval() needs it for "s:dict.func".
- lead = eval_fname_script((const char *)start);
+ lead = eval_fname_script(start);
if (lead > 2) {
start += lead;
}
// Note that TFN_ flags use the same values as GLV_ flags.
- end = (char_u *)get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
- lead > 2 ? 0 : FNE_CHECK_START);
+ end = get_lval((char *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
+ lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
if (!skip) {
emsg(_("E129: Function name required"));
@@ -1728,7 +1781,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
if (lv.ll_tv != NULL) {
if (fdp != NULL) {
fdp->fd_dict = lv.ll_dict;
- fdp->fd_newkey = (char_u *)lv.ll_newkey;
+ fdp->fd_newkey = lv.ll_newkey;
lv.ll_newkey = NULL;
fdp->fd_di = lv.ll_di;
}
@@ -1738,7 +1791,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
} else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL) {
if (is_luafunc(lv.ll_tv->vval.v_partial) && *end == '.') {
- len = check_luafunc_name((const char *)end + 1, true);
+ len = check_luafunc_name(end + 1, true);
if (len == 0) {
semsg(e_invexpr2, "v:lua");
goto theend;
@@ -1775,15 +1828,14 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
// Check if the name is a Funcref. If so, use the value.
if (lv.ll_exp_name != NULL) {
len = (int)strlen(lv.ll_exp_name);
- name = (char *)deref_func_name(lv.ll_exp_name, &len, partial,
- flags & TFN_NO_AUTOLOAD);
+ name = deref_func_name(lv.ll_exp_name, &len, partial,
+ flags & TFN_NO_AUTOLOAD);
if ((const char *)name == lv.ll_exp_name) {
name = NULL;
}
} else if (!(flags & TFN_NO_DEREF)) {
- len = (int)(end - (char_u *)(*pp));
- name = (char *)deref_func_name((const char *)(*pp), &len, partial,
- flags & TFN_NO_AUTOLOAD);
+ len = (int)(end - *pp);
+ name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
if (name == *pp) {
name = NULL;
}
@@ -1791,7 +1843,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
if (name != NULL) {
name = xstrdup(name);
*pp = (char *)end;
- if (STRNCMP(name, "<SNR>", 5) == 0) {
+ if (strncmp(name, "<SNR>", 5) == 0) {
// Change "<SNR>" to the byte sequence.
name[0] = (char)K_SPECIAL;
name[1] = (char)KS_EXTRA;
@@ -1818,7 +1870,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
lv.ll_name += 2;
lv.ll_name_len -= 2;
}
- len = (int)((const char *)end - lv.ll_name);
+ len = (int)(end - lv.ll_name);
}
size_t sid_buf_len = 0;
@@ -1849,7 +1901,7 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
}
if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF)) {
- char_u *cp = xmemrchr(lv.ll_name, ':', lv.ll_name_len);
+ char *cp = xmemrchr(lv.ll_name, ':', lv.ll_name_len);
if (cp != NULL && cp < end) {
semsg(_("E884: Function name cannot contain a colon: %s"), start);
@@ -1872,11 +1924,96 @@ char_u *trans_function_name(char **pp, bool skip, int flags, funcdict_T *fdp, pa
theend:
clear_lval(&lv);
- return (char_u *)name;
+ return name;
+}
+
+/// If the "funcname" starts with "s:" or "<SID>", then expands it to the
+/// current script ID and returns the expanded function name. The caller should
+/// free the returned name. If not called from a script context or the function
+/// name doesn't start with these prefixes, then returns NULL.
+/// This doesn't check whether the script-local function exists or not.
+char *get_scriptlocal_funcname(char *funcname)
+{
+ if (funcname == NULL) {
+ return NULL;
+ }
+
+ if (strncmp(funcname, "s:", 2) != 0
+ && strncmp(funcname, "<SID>", 5) != 0) {
+ // The function name is not a script-local function name
+ return NULL;
+ }
+
+ if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) {
+ emsg(_(e_usingsid));
+ return NULL;
+ }
+
+ char sid_buf[25];
+ // Expand s: and <SID> prefix into <SNR>nr_<name>
+ snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
+ (int64_t)current_sctx.sc_sid);
+ const int off = *funcname == 's' ? 2 : 5;
+ char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1);
+ STRCPY(newname, sid_buf);
+ STRCAT(newname, funcname + off);
+
+ return newname;
+}
+
+/// Call trans_function_name(), except that a lambda is returned as-is.
+/// Returns the name in allocated memory.
+char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
+{
+ char *p = *name;
+ char *saved;
+
+ if (strncmp(p, "<lambda>", 8) == 0) {
+ p += 8;
+ (void)getdigits(&p, false, 0);
+ saved = xstrndup(*name, (size_t)(p - *name));
+ if (fudi != NULL) {
+ CLEAR_POINTER(fudi);
+ }
+ } else {
+ saved = trans_function_name(&p, skip, flags, fudi, NULL);
+ }
+ *name = p;
+ return saved;
}
#define MAX_FUNC_NESTING 50
+/// List functions.
+///
+/// @param regmatch When NULL, all of them.
+/// Otherwise functions matching "regmatch".
+static void list_functions(regmatch_T *regmatch)
+{
+ const int changed = func_hashtab.ht_changed;
+ size_t todo = func_hashtab.ht_used;
+ const hashitem_T *const ht_array = func_hashtab.ht_array;
+
+ for (const hashitem_T *hi = ht_array; todo > 0 && !got_int; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ ufunc_T *fp = HI2UF(hi);
+ todo--;
+ if ((fp->uf_flags & FC_DEAD) == 0
+ && (regmatch == NULL
+ ? (!message_filtered((char *)fp->uf_name)
+ && !func_name_refcount(fp->uf_name))
+ : (!isdigit((uint8_t)(*fp->uf_name))
+ && vim_regexec(regmatch, (char *)fp->uf_name, 0)))) {
+ list_func_head(fp, false, false);
+ if (changed != func_hashtab.ht_changed) {
+ emsg(_("E454: function list was modified"));
+ return;
+ }
+ }
+ }
+ }
+}
+
/// ":function"
void ex_function(exarg_T *eap)
{
@@ -1903,7 +2040,6 @@ void ex_function(exarg_T *eap)
static int func_nr = 0; // number for nameless function
int paren;
hashtab_T *ht;
- int todo;
hashitem_T *hi;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
@@ -1916,19 +2052,7 @@ void ex_function(exarg_T *eap)
// ":function" without argument: list functions.
if (ends_excmd(*eap->arg)) {
if (!eap->skip) {
- todo = (int)func_hashtab.ht_used;
- for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- fp = HI2UF(hi);
- if (message_filtered((char *)fp->uf_name)) {
- continue;
- }
- if (!func_name_refcount(fp->uf_name)) {
- list_func_head(fp, false, false);
- }
- }
- }
+ list_functions(NULL);
}
eap->nextcmd = check_nextcmd(eap->arg);
return;
@@ -1936,7 +2060,7 @@ void ex_function(exarg_T *eap)
// ":function /pat": list functions matching pattern.
if (*eap->arg == '/') {
- p = skip_regexp(eap->arg + 1, '/', true, NULL);
+ p = skip_regexp(eap->arg + 1, '/', true);
if (!eap->skip) {
regmatch_T regmatch;
@@ -1946,18 +2070,7 @@ void ex_function(exarg_T *eap)
*p = c;
if (regmatch.regprog != NULL) {
regmatch.rm_ic = p_ic;
-
- todo = (int)func_hashtab.ht_used;
- for (hi = func_hashtab.ht_array; todo > 0 && !got_int; hi++) {
- if (!HASHITEM_EMPTY(hi)) {
- todo--;
- fp = HI2UF(hi);
- if (!isdigit(*fp->uf_name)
- && vim_regexec(&regmatch, (char *)fp->uf_name, 0)) {
- list_func_head(fp, false, false);
- }
- }
- }
+ list_functions(&regmatch);
vim_regfree(regmatch.regprog);
}
}
@@ -1983,14 +2096,7 @@ void ex_function(exarg_T *eap)
// s:func script-local function name
// g:func global function name, same as "func"
p = eap->arg;
- if (strncmp(p, "<lambda>", 8) == 0) {
- p += 8;
- (void)getdigits(&p, false, 0);
- name = xstrndup(eap->arg, (size_t)(p - eap->arg));
- CLEAR_FIELD(fudi);
- } else {
- name = (char *)trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL);
- }
+ name = save_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi);
paren = (vim_strchr(p, '(') != NULL);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) {
// Return on an invalid expression in braces, unless the expression
@@ -2002,9 +2108,8 @@ void ex_function(exarg_T *eap)
}
xfree(fudi.fd_newkey);
return;
- } else {
- eap->skip = true;
}
+ eap->skip = true;
}
// An error in a function call during evaluation of an expression in magic
@@ -2028,7 +2133,7 @@ void ex_function(exarg_T *eap)
*p = NUL;
}
if (!eap->skip && !got_int) {
- fp = find_func((char_u *)name);
+ fp = find_func(name);
if (fp != NULL) {
list_func_head(fp, !eap->forceit, eap->forceit);
for (int j = 0; j < fp->uf_lines.ga_len && !got_int; j++) {
@@ -2054,7 +2159,7 @@ void ex_function(exarg_T *eap)
msg_puts(eap->forceit ? "endfunction" : " endfunction");
}
} else {
- emsg_funcname(N_("E123: Undefined function: %s"), (char_u *)name);
+ emsg_funcname(N_("E123: Undefined function: %s"), name);
}
}
goto ret_free;
@@ -2074,8 +2179,8 @@ void ex_function(exarg_T *eap)
}
p = skipwhite(p + 1);
- ga_init(&newargs, (int)sizeof(char_u *), 3);
- ga_init(&newlines, (int)sizeof(char_u *), 3);
+ ga_init(&newargs, (int)sizeof(char *), 3);
+ ga_init(&newlines, (int)sizeof(char *), 3);
if (!eap->skip) {
// Check the name of the function. Unless it's a dictionary function
@@ -2083,7 +2188,7 @@ void ex_function(exarg_T *eap)
if (name != NULL) {
arg = name;
} else {
- arg = (char *)fudi.fd_newkey;
+ arg = fudi.fd_newkey;
}
if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) {
int j = ((uint8_t)(*arg) == K_SPECIAL) ? 3 : 0;
@@ -2091,7 +2196,7 @@ void ex_function(exarg_T *eap)
j++;
}
if (arg[j] != NUL) {
- emsg_funcname((char *)e_invarg2, (char_u *)arg);
+ emsg_funcname((char *)e_invarg2, arg);
}
}
// Disallow using the g: dict.
@@ -2113,21 +2218,21 @@ void ex_function(exarg_T *eap)
// find extra arguments "range", "dict", "abort" and "closure"
for (;;) {
p = skipwhite(p);
- if (STRNCMP(p, "range", 5) == 0) {
+ if (strncmp(p, "range", 5) == 0) {
flags |= FC_RANGE;
p += 5;
- } else if (STRNCMP(p, "dict", 4) == 0) {
+ } else if (strncmp(p, "dict", 4) == 0) {
flags |= FC_DICT;
p += 4;
- } else if (STRNCMP(p, "abort", 5) == 0) {
+ } else if (strncmp(p, "abort", 5) == 0) {
flags |= FC_ABORT;
p += 5;
- } else if (STRNCMP(p, "closure", 7) == 0) {
+ } else if (strncmp(p, "closure", 7) == 0) {
flags |= FC_CLOSURE;
p += 7;
if (current_funccal == NULL) {
emsg_funcname(N_("E932: Closure function should not be at top level: %s"),
- name == NULL ? (char_u *)"" : (char_u *)name);
+ name == NULL ? "" : name);
goto erret;
}
} else {
@@ -2151,8 +2256,8 @@ void ex_function(exarg_T *eap)
if (!eap->skip && !eap->forceit) {
if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) {
emsg(_(e_funcdict));
- } else if (name != NULL && find_func((char_u *)name) != NULL) {
- emsg_funcname(e_funcexts, (char_u *)name);
+ } else if (name != NULL && find_func(name) != NULL) {
+ emsg_funcname(e_funcexts, name);
}
}
@@ -2191,7 +2296,7 @@ void ex_function(exarg_T *eap)
} else {
xfree(line_to_free);
if (eap->getline == NULL) {
- theline = (char *)getcmdline(':', 0L, indent, do_concat);
+ theline = getcmdline(':', 0L, indent, do_concat);
} else {
theline = eap->getline(':', eap->cookie, indent, do_concat);
}
@@ -2224,7 +2329,7 @@ void ex_function(exarg_T *eap)
// * ":let {var-name} =<< [trim] {marker}" and "{marker}"
if (heredoc_trimmed == NULL
|| (is_heredoc && skipwhite(theline) == theline)
- || STRNCMP(theline, heredoc_trimmed,
+ || strncmp(theline, heredoc_trimmed,
strlen(heredoc_trimmed)) == 0) {
if (heredoc_trimmed == NULL) {
p = theline;
@@ -2274,12 +2379,12 @@ void ex_function(exarg_T *eap)
// Increase indent inside "if", "while", "for" and "try", decrease
// at "end".
- if (indent > 2 && STRNCMP(p, "end", 3) == 0) {
+ if (indent > 2 && strncmp(p, "end", 3) == 0) {
indent -= 2;
- } else if (STRNCMP(p, "if", 2) == 0
- || STRNCMP(p, "wh", 2) == 0
- || STRNCMP(p, "for", 3) == 0
- || STRNCMP(p, "try", 3) == 0) {
+ } else if (strncmp(p, "if", 2) == 0
+ || strncmp(p, "wh", 2) == 0
+ || strncmp(p, "for", 3) == 0
+ || strncmp(p, "try", 3) == 0) {
indent += 2;
}
@@ -2307,7 +2412,7 @@ void ex_function(exarg_T *eap)
&& (!ASCII_ISALPHA(p[1])
|| (p[1] == 'h' && (!ASCII_ISALPHA(p[2])
|| (p[2] == 'a'
- && (STRNCMP(&p[3], "nge", 3) != 0
+ && (strncmp(&p[3], "nge", 3) != 0
|| !ASCII_ISALPHA(p[6])))))))
|| (p[0] == 'i'
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
@@ -2358,7 +2463,7 @@ void ex_function(exarg_T *eap)
&& (!ASCII_ISALNUM(p[2])
|| (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) {
p = skipwhite(arg + 3);
- if (STRNCMP(p, "trim", 4) == 0) {
+ if (strncmp(p, "trim", 4) == 0) {
// Ignore leading white space.
p = skipwhite(p + 4);
heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline));
@@ -2401,24 +2506,22 @@ void ex_function(exarg_T *eap)
if (fudi.fd_dict == NULL) {
v = find_var((const char *)name, strlen(name), &ht, false);
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
- emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
- (char_u *)name);
+ emsg_funcname(N_("E707: Function name conflicts with variable: %s"), name);
goto erret;
}
- fp = find_func((char_u *)name);
+ fp = find_func(name);
if (fp != NULL) {
// Function can be replaced with "function!" and when sourcing the
// same script again, but only once.
if (!eap->forceit
&& (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid
|| fp->uf_script_ctx.sc_seq == current_sctx.sc_seq)) {
- emsg_funcname(e_funcexts, (char_u *)name);
+ emsg_funcname(e_funcexts, name);
goto erret;
}
if (fp->uf_calls > 0) {
- emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
- (char_u *)name);
+ emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"), name);
goto erret;
}
if (fp->uf_refcount > 1) {
@@ -2429,7 +2532,7 @@ void ex_function(exarg_T *eap)
fp = NULL;
overwrite = true;
} else {
- char_u *exp_name = fp->uf_name_exp;
+ char *exp_name = fp->uf_name_exp;
// redefine existing function, keep the expanded name
XFREE_CLEAR(name);
fp->uf_name_exp = NULL;
@@ -2448,13 +2551,13 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fudi.fd_di == NULL) {
- if (var_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ if (value_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't add a function to a locked dictionary
goto erret;
}
- } else if (var_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ } else if (value_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't change an existing function if it is locked
goto erret;
}
@@ -2469,15 +2572,15 @@ void ex_function(exarg_T *eap)
if (fp == NULL) {
if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) {
int slen, plen;
- char_u *scriptname;
+ char *scriptname;
// Check that the autoload name matches the script name.
int j = FAIL;
if (SOURCING_NAME != NULL) {
- scriptname = (char_u *)autoload_name((const char *)name, strlen(name));
- p = vim_strchr((char *)scriptname, '/');
- plen = (int)STRLEN(p);
- slen = (int)STRLEN(SOURCING_NAME);
+ scriptname = autoload_name(name, strlen(name));
+ p = vim_strchr(scriptname, '/');
+ plen = (int)strlen(p);
+ slen = (int)strlen(SOURCING_NAME);
if (slen > plen && path_fnamecmp(p, SOURCING_NAME + slen - plen) == 0) {
j = OK;
}
@@ -2513,10 +2616,10 @@ void ex_function(exarg_T *eap)
}
// insert the new function in the function list
- set_ufunc_name(fp, (char_u *)name);
+ set_ufunc_name(fp, name);
if (overwrite) {
hi = hash_find(&func_hashtab, name);
- hi->hi_key = UF2HIKEY(fp);
+ hi->hi_key = (char *)UF2HIKEY(fp);
} else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) {
xfree(fp);
goto erret;
@@ -2587,7 +2690,7 @@ bool translated_function_exists(const char *name)
if (builtin_function(name, -1)) {
return find_internal_func((char *)name) != NULL;
}
- return find_func((const char_u *)name) != NULL;
+ return find_func(name) != NULL;
}
/// Check whether function with the given name exists
@@ -2598,15 +2701,15 @@ bool translated_function_exists(const char *name)
/// @return true if it exists, false otherwise.
bool function_exists(const char *const name, bool no_deref)
{
- const char_u *nm = (const char_u *)name;
+ const char *nm = name;
bool n = false;
int flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
if (no_deref) {
flag |= TFN_NO_DEREF;
}
- char *const p = (char *)trans_function_name((char **)&nm, false, flag, NULL, NULL);
- nm = (char_u *)skipwhite((char *)nm);
+ char *const p = trans_function_name((char **)&nm, false, flag, NULL, NULL);
+ nm = skipwhite(nm);
// Only accept "funcname", "funcname ", "funcname (..." and
// "funcname(...", not "funcname!...".
@@ -2622,15 +2725,17 @@ bool function_exists(const char *const name, bool no_deref)
char *get_user_func_name(expand_T *xp, int idx)
{
static size_t done;
+ static int changed;
static hashitem_T *hi;
ufunc_T *fp;
if (idx == 0) {
done = 0;
hi = func_hashtab.ht_array;
+ changed = func_hashtab.ht_changed;
}
assert(hi);
- if (done < func_hashtab.ht_used) {
+ if (changed == func_hashtab.ht_changed && done < func_hashtab.ht_used) {
if (done++ > 0) {
hi++;
}
@@ -2640,22 +2745,22 @@ char *get_user_func_name(expand_T *xp, int idx)
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DICT)
- || STRNCMP(fp->uf_name, "<lambda>", 8) == 0) {
+ || strncmp(fp->uf_name, "<lambda>", 8) == 0) {
return ""; // don't show dict and lambda functions
}
- if (STRLEN(fp->uf_name) + 4 >= IOSIZE) {
+ if (strlen(fp->uf_name) + 4 >= IOSIZE) {
return (char *)fp->uf_name; // Prevent overflow.
}
- cat_func_name((char_u *)IObuff, fp);
+ cat_func_name(IObuff, fp);
if (xp->xp_context != EXPAND_USER_FUNC) {
STRCAT(IObuff, "(");
if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) {
STRCAT(IObuff, ")");
}
}
- return (char *)IObuff;
+ return IObuff;
}
return NULL;
}
@@ -2664,12 +2769,12 @@ char *get_user_func_name(expand_T *xp, int idx)
void ex_delfunction(exarg_T *eap)
{
ufunc_T *fp = NULL;
- char_u *p;
- char_u *name;
+ char *p;
+ char *name;
funcdict_T fudi;
- p = (char_u *)eap->arg;
- name = trans_function_name((char **)&p, eap->skip, 0, &fudi, NULL);
+ p = eap->arg;
+ name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
xfree(fudi.fd_newkey);
if (name == NULL) {
if (fudi.fd_dict != NULL && !eap->skip) {
@@ -2677,16 +2782,23 @@ void ex_delfunction(exarg_T *eap)
}
return;
}
- if (!ends_excmd(*skipwhite((char *)p))) {
+ if (!ends_excmd(*skipwhite(p))) {
xfree(name);
semsg(_(e_trailing_arg), p);
return;
}
- eap->nextcmd = check_nextcmd((char *)p);
+ eap->nextcmd = check_nextcmd(p);
if (eap->nextcmd != NULL) {
*p = NUL;
}
+ if (isdigit((uint8_t)(*name)) && fudi.fd_dict == NULL) {
+ if (!eap->skip) {
+ semsg(_(e_invarg2), eap->arg);
+ }
+ xfree(name);
+ return;
+ }
if (!eap->skip) {
fp = find_func(name);
}
@@ -2737,7 +2849,7 @@ void ex_delfunction(exarg_T *eap)
/// Unreference a Function: decrement the reference count and free it when it
/// becomes zero.
-void func_unref(char_u *name)
+void func_unref(char *name)
{
ufunc_T *fp = NULL;
@@ -2746,7 +2858,7 @@ void func_unref(char_u *name)
}
fp = find_func(name);
- if (fp == NULL && isdigit(*name)) {
+ if (fp == NULL && isdigit((uint8_t)(*name))) {
#ifdef EXITFREE
if (!entered_free_all_mem) {
internal_error("func_unref()");
@@ -2779,7 +2891,7 @@ void func_ptr_unref(ufunc_T *fp)
}
/// Count a reference to a Function.
-void func_ref(char_u *name)
+void func_ref(char *name)
{
ufunc_T *fp;
@@ -2789,7 +2901,7 @@ void func_ref(char_u *name)
fp = find_func(name);
if (fp != NULL) {
(fp->uf_refcount)++;
- } else if (isdigit(*name)) {
+ } else if (isdigit((uint8_t)(*name))) {
// Only give an error for a numbered function.
// Fail silently, when named or lambda function isn't found.
internal_error("func_ref()");
@@ -2833,7 +2945,7 @@ static int can_free_funccal(funccall_T *fc, int copyID)
/// ":return [expr]"
void ex_return(exarg_T *eap)
{
- char_u *arg = (char_u *)eap->arg;
+ char *arg = eap->arg;
typval_T rettv;
int returning = false;
@@ -2848,7 +2960,7 @@ void ex_return(exarg_T *eap)
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
- && eval0((char *)arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
+ && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) {
if (!eap->skip) {
returning = do_return(eap, false, true, &rettv);
} else {
@@ -2871,7 +2983,7 @@ void ex_return(exarg_T *eap)
if (returning) {
eap->nextcmd = NULL;
} else if (eap->nextcmd == NULL) { // no argument
- eap->nextcmd = check_nextcmd((char *)arg);
+ eap->nextcmd = check_nextcmd(arg);
}
if (eap->skip) {
@@ -2879,15 +2991,13 @@ void ex_return(exarg_T *eap)
}
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// ":1,25call func(arg1, arg2)" function call.
void ex_call(exarg_T *eap)
{
- char_u *arg = (char_u *)eap->arg;
- char_u *startarg;
- char_u *name;
- char_u *tofree;
+ char *arg = eap->arg;
+ char *startarg;
+ char *name;
+ char *tofree;
int len;
typval_T rettv;
linenr_T lnum;
@@ -2908,7 +3018,7 @@ void ex_call(exarg_T *eap)
return;
}
- tofree = trans_function_name((char **)&arg, false, TFN_INT, &fudi, &partial);
+ tofree = trans_function_name(&arg, false, TFN_INT, &fudi, &partial);
if (fudi.fd_newkey != NULL) {
// Still need to give an error message for missing key.
semsg(_(e_dictkey), fudi.fd_newkey);
@@ -2927,13 +3037,12 @@ void ex_call(exarg_T *eap)
// If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
// contents. For VAR_PARTIAL get its partial, unless we already have one
// from trans_function_name().
- len = (int)STRLEN(tofree);
- name = deref_func_name((const char *)tofree, &len,
- partial != NULL ? NULL : &partial, false);
+ len = (int)strlen(tofree);
+ name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial, false);
// Skip white space to allow ":call func ()". Not good, but required for
// backward compatibility.
- startarg = (char_u *)skipwhite((char *)arg);
+ startarg = skipwhite(arg);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
if (*startarg != '(') {
@@ -2963,7 +3072,7 @@ void ex_call(exarg_T *eap)
funcexe.fe_evaluate = true;
funcexe.fe_partial = partial;
funcexe.fe_selfdict = fudi.fd_dict;
- if (get_func_tv(name, -1, &rettv, (char **)&arg, &funcexe) == FAIL) {
+ if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) {
failed = true;
break;
}
@@ -3000,7 +3109,7 @@ void ex_call(exarg_T *eap)
semsg(_(e_trailing_arg), arg);
}
} else {
- eap->nextcmd = check_nextcmd((char *)arg);
+ eap->nextcmd = check_nextcmd(arg);
}
}
@@ -3100,12 +3209,12 @@ char *get_return_cmd(void *rettv)
}
STRCPY(IObuff, ":return ");
- STRLCPY(IObuff + 8, s, IOSIZE - 8);
+ xstrlcpy(IObuff + 8, s, IOSIZE - 8);
if (strlen(s) + 8 >= IOSIZE) {
STRCPY(IObuff + IOSIZE - 4, "...");
}
xfree(tofree);
- return xstrdup((char *)IObuff);
+ return xstrdup(IObuff);
}
/// Get next function line.
@@ -3182,20 +3291,20 @@ int func_has_abort(void *cookie)
/// Changes "rettv" in-place.
void make_partial(dict_T *const selfdict, typval_T *const rettv)
{
- char_u *fname;
- char_u *tofree = NULL;
+ char *fname;
+ char *tofree = NULL;
ufunc_T *fp;
- char_u fname_buf[FLEN_FIXED + 1];
+ char fname_buf[FLEN_FIXED + 1];
int error;
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL) {
fp = rettv->vval.v_partial->pt_func;
} else {
fname = rettv->v_type == VAR_FUNC || rettv->v_type == VAR_STRING
- ? (char_u *)rettv->vval.v_string
- : (char_u *)rettv->vval.v_partial->pt_name;
+ ? rettv->vval.v_string
+ : rettv->vval.v_partial->pt_name;
// Translate "s:func" to the stored function name.
- fname = (char_u *)fname_trans_sid((char *)fname, (char *)fname_buf, (char **)&tofree, &error);
+ fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
fp = find_func(fname);
xfree(tofree);
}
@@ -3219,7 +3328,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv)
// be referenced elsewhere.
if (ret_pt->pt_name != NULL) {
pt->pt_name = xstrdup(ret_pt->pt_name);
- func_ref((char_u *)pt->pt_name);
+ func_ref(pt->pt_name);
} else {
pt->pt_func = ret_pt->pt_func;
func_ptr_ref(pt->pt_func);
@@ -3240,7 +3349,7 @@ void make_partial(dict_T *const selfdict, typval_T *const rettv)
}
/// @return the name of the executed function.
-char_u *func_name(void *cookie)
+char *func_name(void *cookie)
{
return ((funccall_T *)cookie)->func->uf_name;
}
@@ -3527,21 +3636,21 @@ bool set_ref_in_func_args(int copyID)
/// "ht_stack" is used to add hashtabs to be marked. Can be NULL.
///
/// @return true if setting references failed somehow.
-bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
+bool set_ref_in_func(char *name, ufunc_T *fp_in, int copyID)
{
ufunc_T *fp = fp_in;
funccall_T *fc;
int error = FCERR_NONE;
- char_u fname_buf[FLEN_FIXED + 1];
- char_u *tofree = NULL;
- char_u *fname;
+ char fname_buf[FLEN_FIXED + 1];
+ char *tofree = NULL;
+ char *fname;
bool abort = false;
if (name == NULL && fp_in == NULL) {
return false;
}
if (fp_in == NULL) {
- fname = (char_u *)fname_trans_sid((char *)name, (char *)fname_buf, (char **)&tofree, &error);
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
fp = find_func(fname);
}
if (fp != NULL) {
@@ -3554,10 +3663,10 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
}
/// Registers a luaref as a lambda.
-char_u *register_luafunc(LuaRef ref)
+char *register_luafunc(LuaRef ref)
{
- char_u *name = get_lambda_name();
- ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
+ char *name = get_lambda_name();
+ ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + strlen(name) + 1);
fp->uf_refcount = 1;
fp->uf_varargs = true;
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index 4098622a14..c8583f232c 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -1,8 +1,18 @@
#ifndef NVIM_EVAL_USERFUNC_H
#define NVIM_EVAL_USERFUNC_H
+#include <stdbool.h>
+#include <stddef.h>
+
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds_defs.h"
+#include "nvim/garray.h"
+#include "nvim/hashtab.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+
+struct funccal_entry;
// From user function to hashitem and back.
#define UF2HIKEY(fp) ((fp)->uf_name)
@@ -23,10 +33,10 @@
#define FC_VIM9 0x400 // defined in vim9 script file
#define FC_LUAREF 0x800 // luaref callback
-///< Structure used by trans_function_name()
+/// Structure used by trans_function_name()
typedef struct {
dict_T *fd_dict; ///< Dictionary used.
- char_u *fd_newkey; ///< New key in "dict" in allocated memory.
+ char *fd_newkey; ///< New key in "dict" in allocated memory.
dictitem_T *fd_di; ///< Dictionary item used.
} funcdict_T;
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 4d7214205d..3e593151fc 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -3,24 +3,43 @@
// eval/vars.c: functions for dealing with variables
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
-#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/vars.h"
+#include "nvim/eval/window.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/hashtab.h"
+#include "nvim/macros.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/screen.h"
+#include "nvim/os/os.h"
#include "nvim/search.h"
+#include "nvim/strings.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -62,7 +81,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// Check for the optional 'trim' word before the marker
cmd = skipwhite(cmd);
- if (STRNCMP(cmd, "trim", 4) == 0
+ if (strncmp(cmd, "trim", 4) == 0
&& (cmd[4] == NUL || ascii_iswhite(cmd[4]))) {
cmd = skipwhite(cmd + 4);
@@ -87,7 +106,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
return NULL;
}
*p = NUL;
- if (islower(*marker)) {
+ if (islower((uint8_t)(*marker))) {
emsg(_("E221: Marker cannot start with lower case letter"));
return NULL;
}
@@ -110,7 +129,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// with "trim": skip the indent matching the :let line to find the
// marker
if (marker_indent_len > 0
- && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
+ && strncmp(theline, *eap->cmdlinep, (size_t)marker_indent_len) == 0) {
mi = marker_indent_len;
}
if (strcmp(marker, theline + mi) == 0) {
@@ -189,8 +208,8 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
argend--;
}
expr = skipwhite(argend);
- if (*expr != '=' && !((vim_strchr("+-*/%.", *expr) != NULL
- && expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
+ if (*expr != '=' && !((vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL
+ && expr[1] == '=') || strncmp(expr, "..=", 3) == 0)) {
// ":let" without "=": list variables
if (*arg == '[') {
emsg(_(e_invarg));
@@ -225,17 +244,19 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
op[0] = '=';
op[1] = NUL;
if (*expr != '=') {
- if (vim_strchr("+-*/%.", *expr) != NULL) {
+ if (vim_strchr("+-*/%.", (uint8_t)(*expr)) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
}
- expr = skipwhite(expr + 2);
+ expr += 2;
} else {
- expr = skipwhite(expr + 1);
+ expr += 1;
}
+ expr = skipwhite(expr);
+
if (eap->skip) {
emsg_skip++;
}
@@ -378,9 +399,8 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon)
}
}
return p + 1;
- } else {
- return skip_var_one((char *)arg);
}
+ return skip_var_one((char *)arg);
}
/// Skip one (assignable) variable name, including @r, $VAR, &option, d.key,
@@ -539,8 +559,6 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
return arg;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Set one item of `:let var = expr` or `:let [v1, v2] = list` to its value
///
/// @param[in] arg Start of the variable name.
@@ -558,8 +576,6 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
{
char *arg_end = NULL;
int len;
- int opt_flags;
- char *tofree = NULL;
// ":let $VAR = expr": Set environment variable.
if (*arg == '$') {
@@ -574,18 +590,18 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (len == 0) {
semsg(_(e_invarg2), name - 1);
} else {
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg)) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg))) == NULL) {
emsg(_(e_letunexp));
} else if (!check_secure()) {
+ char *tofree = NULL;
const char c1 = name[len];
name[len] = NUL;
const char *p = tv_get_string_chk(tv);
if (p != NULL && op != NULL && *op == '.') {
char *s = vim_getenv(name);
-
if (s != NULL) {
tofree = concat_str(s, p);
p = (const char *)tofree;
@@ -609,10 +625,11 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
return NULL;
}
// Find the end of the name.
- char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
+ int scope;
+ char *const p = (char *)find_option_end((const char **)&arg, &scope);
if (p == NULL
|| (endchars != NULL
- && vim_strchr(endchars, *skipwhite(p)) == NULL)) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL)) {
emsg(_(e_letunexp));
} else {
varnumber_T n = 0;
@@ -621,11 +638,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
char *stringval = NULL;
const char *s = NULL;
bool failed = false;
+ uint32_t opt_p_flags;
+ char *tofree = NULL;
const char c1 = *p;
*p = NUL;
- opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
+ opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, scope);
if (opt_type == gov_bool
|| opt_type == gov_number
|| opt_type == gov_hidden_bool
@@ -634,8 +653,13 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
n = (long)tv_get_number(tv);
}
- // Avoid setting a string option to the text "v:false" or similar.
- if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ if ((opt_p_flags & P_FUNC) && tv_is_func(*tv)) {
+ // If the option can be set to a function reference or a lambda
+ // and the passed value is a function reference, then convert it to
+ // the name (string) of the function reference.
+ s = tofree = encode_tv2string(tv, NULL);
+ } else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) {
+ // Avoid setting a string option to the text "v:false" or similar.
s = tv_get_string_chk(tv);
}
@@ -672,7 +696,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
if (!failed) {
if (opt_type != gov_string || s != NULL) {
- char *err = set_option_value(arg, n, s, opt_flags);
+ char *err = set_option_value(arg, n, s, scope);
arg_end = p;
if (err != NULL) {
emsg(_(err));
@@ -683,6 +707,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
}
*p = c1;
xfree(stringval);
+ xfree(tofree);
}
// ":let @r = expr": Set register contents.
} else if (*arg == '@') {
@@ -691,10 +716,10 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
return NULL;
}
arg++;
- if (op != NULL && vim_strchr("+-*/%", *op) != NULL) {
+ if (op != NULL && vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) {
semsg(_(e_letwrong), op);
} else if (endchars != NULL
- && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
+ && vim_strchr(endchars, (uint8_t)(*skipwhite(arg + 1))) == NULL) {
emsg(_(e_letunexp));
} else {
char *s;
@@ -722,7 +747,7 @@ static char *ex_let_one(char *arg, typval_T *const tv, const bool copy, const bo
char *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START);
if (p != NULL && lv.ll_name != NULL) {
- if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
+ if (endchars != NULL && vim_strchr(endchars, (uint8_t)(*skipwhite(p))) == NULL) {
emsg(_(e_letunexp));
} else {
set_var_lval(&lv, p, tv, copy, is_const, op);
@@ -743,8 +768,6 @@ void ex_unlet(exarg_T *eap)
ex_unletlock(eap, eap->arg, 0, do_unlet_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// ":lockvar" and ":unlockvar" commands
void ex_lockvar(exarg_T *eap)
{
@@ -761,8 +784,6 @@ void ex_lockvar(exarg_T *eap)
ex_unletlock(eap, arg, deep, do_lock_var);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Common parsing logic for :unlet, :lockvar and :unlockvar.
///
/// Invokes `callback` afterwards if successful and `eap->skip == false`.
@@ -827,8 +848,6 @@ static void ex_unletlock(exarg_T *eap, char *argstart, int deep, ex_unletlock_ca
eap->nextcmd = check_nextcmd(arg);
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Unlet a variable indicated by `lp`.
///
/// @param[in] lp The lvalue.
@@ -845,7 +864,7 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
int cc;
if (lp->ll_tv == NULL) {
- cc = (char_u)(*name_end);
+ cc = (uint8_t)(*name_end);
*name_end = NUL;
// Environment variable, normal name or expanded name.
@@ -858,13 +877,13 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
} else if ((lp->ll_list != NULL
// ll_list is not NULL when lvalue is not in a list, NULL lists
// yield E689.
- && var_check_lock(tv_list_locked(lp->ll_list),
- lp->ll_name,
- lp->ll_name_len))
+ && value_check_lock(tv_list_locked(lp->ll_list),
+ lp->ll_name,
+ lp->ll_name_len))
|| (lp->ll_dict != NULL
- && var_check_lock(lp->ll_dict->dv_lock,
- lp->ll_name,
- lp->ll_name_len))) {
+ && value_check_lock(lp->ll_dict->dv_lock,
+ lp->ll_name,
+ lp->ll_name_len))) {
return FAIL;
} else if (lp->ll_range) {
assert(lp->ll_list != NULL);
@@ -873,18 +892,17 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
listitem_T *last_li = first_li;
for (;;) {
listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
- if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
- lp->ll_name,
- lp->ll_name_len)) {
+ if (value_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
+ lp->ll_name,
+ lp->ll_name_len)) {
return false;
}
lp->ll_li = li;
lp->ll_n1++;
if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) {
break;
- } else {
- last_li = lp->ll_li;
}
+ last_li = lp->ll_li;
}
tv_list_remove_items(lp->ll_list, first_li, last_li);
} else {
@@ -919,8 +937,6 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_
return ret;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// unlet a variable
///
/// @param[in] name Variable name to unlet.
@@ -960,11 +976,11 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
dictitem_T *const di = TV_DICT_HI2DI(hi);
if (var_check_fixed(di->di_flags, name, TV_CSTRING)
|| var_check_ro(di->di_flags, name, TV_CSTRING)
- || var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ || value_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
- if (var_check_lock(d->dv_lock, name, TV_CSTRING)) {
+ if (value_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
@@ -991,8 +1007,6 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
return FAIL;
}
-// TODO(ZyX-I): move to eval/ex_cmds
-
/// Lock or unlock variable indicated by `lp`.
///
/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise.
@@ -1009,10 +1023,6 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap
bool lock = eap->cmdidx == CMD_lockvar;
int ret = OK;
- if (deep == 0) { // Nothing to do.
- return OK;
- }
-
if (lp->ll_tv == NULL) {
if (*lp->ll_name == '$') {
semsg(_(e_lock_unlock), lp->ll_name);
@@ -1036,9 +1046,13 @@ static int do_lock_var(lval_T *lp, char *name_end FUNC_ATTR_UNUSED, exarg_T *eap
} else {
di->di_flags &= (uint8_t)(~DI_FLAGS_LOCK);
}
- tv_item_lock(&di->di_tv, deep, lock, false);
+ if (deep != 0) {
+ tv_item_lock(&di->di_tv, deep, lock, false);
+ }
}
}
+ } else if (deep == 0) {
+ // nothing to do
} else if (lp->ll_range) {
listitem_T *li = lp->ll_li;
@@ -1098,7 +1112,7 @@ int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, boo
/// NULL when it doesn't exist.
///
/// @see tv_get_string() for how long the pointer remains valid.
-char_u *get_var_value(const char *const name)
+char *get_var_value(const char *const name)
{
dictitem_T *v;
@@ -1106,7 +1120,7 @@ char_u *get_var_value(const char *const name)
if (v == NULL) {
return NULL;
}
- return (char_u *)tv_get_string(&v->di_tv);
+ return (char *)tv_get_string(&v->di_tv);
}
/// Clean up a list of internal variables.
@@ -1161,7 +1175,7 @@ void delete_var(hashtab_T *ht, hashitem_T *hi)
static void list_one_var(dictitem_T *v, const char *prefix, int *first)
{
char *const s = encode_tv2echo(&v->di_tv, NULL);
- list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)STRLEN(v->di_key),
+ list_one_var_a(prefix, (const char *)v->di_key, (ptrdiff_t)strlen((char *)v->di_key),
v->di_tv.v_type, (s == NULL ? "" : s), first);
xfree(s);
}
@@ -1257,7 +1271,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = find_var_in_scoped_ht(name, name_len, true);
}
- if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) {
+ if (tv_is_func(*tv) && var_wrong_func_name(name, v == NULL)) {
return;
}
@@ -1268,12 +1282,18 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
return;
}
- // existing variable, need to clear the value
+ // Check in this order for backwards compatibility:
+ // - Whether the variable is read-only
+ // - Whether the variable value is locked
+ // - Whether the variable is locked
if (var_check_ro(v->di_flags, name, name_len)
- || var_check_lock(v->di_tv.v_lock, name, name_len)) {
+ || value_check_lock(v->di_tv.v_lock, name, name_len)
+ || var_check_lock(v->di_flags, name, name_len)) {
return;
}
+ // existing variable, need to clear the value
+
// Handle setting internal v: variables separately where needed to
// prevent changing the type.
if (is_vimvarht(ht)) {
@@ -1329,7 +1349,7 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
v = xmalloc(sizeof(dictitem_T) + strlen(varname));
STRCPY(v->di_key, varname);
- if (tv_dict_add(dict, v) == FAIL) {
+ if (hash_add(ht, (char *)v->di_key) == FAIL) {
xfree(v);
return;
}
@@ -1404,6 +1424,26 @@ bool var_check_ro(const int flags, const char *name, size_t name_len)
return true;
}
+/// Return true if di_flags "flags" indicates variable "name" is locked.
+/// Also give an error message.
+bool var_check_lock(const int flags, const char *name, size_t name_len)
+{
+ if (!(flags & DI_FLAGS_LOCK)) {
+ return false;
+ }
+
+ if (name_len == TV_TRANSLATE) {
+ name = _(name);
+ name_len = strlen(name);
+ } else if (name_len == TV_CSTRING) {
+ name_len = strlen(name);
+ }
+
+ semsg(_("E1122: Variable is locked: %*s"), (int)name_len, name);
+
+ return true;
+}
+
/// Check whether variable is fixed (DI_FLAGS_FIX)
///
/// Also gives an error message.
@@ -1438,37 +1478,34 @@ bool var_check_fixed(const int flags, const char *name, size_t name_len)
return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if name is a valid name to assign funcref to
///
/// @param[in] name Possible function/funcref name.
/// @param[in] new_var True if it is a name for a variable.
///
-/// @return false in case of error, true in case of success. Also gives an
+/// @return false in case of success, true in case of failure. Also gives an
/// error message if appropriate.
-bool var_check_func_name(const char *const name, const bool new_var)
+bool var_wrong_func_name(const char *const name, const bool new_var)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
// Allow for w: b: s: and t:.
- if (!(vim_strchr("wbst", name[0]) != NULL && name[1] == ':')
- && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
- ? name[2] : name[0])) {
+ // Allow autoload variable.
+ if (!(vim_strchr("wbst", (uint8_t)name[0]) != NULL && name[1] == ':')
+ && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2] : name[0])
+ && vim_strchr(name, '#') == NULL) {
semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
- return false;
+ return true;
}
// Don't allow hiding a function. When "v" is not NULL we might be
// assigning another function to the same var, the type is checked
// below.
if (new_var && function_exists(name, false)) {
semsg(_("E705: Variable name conflicts with existing function: %s"), name);
- return false;
+ return true;
}
- return true;
+ return false;
}
-// TODO(ZyX-I): move to eval/expressions
-
/// Check if a variable name is valid
///
/// @param[in] varname Variable name to check.
@@ -1643,25 +1680,27 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
const char *varname = tv_get_string_chk(&argvars[off + 1]);
typval_T *varp = &argvars[off + 2];
- if (win != NULL && varname != NULL && varp != NULL) {
- bool need_switch_win = !(tp == curtab && win == curwin);
- switchwin_T switchwin;
- if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
- if (*varname == '&') {
- set_option_from_tv(varname + 1, varp);
- } else {
- const size_t varname_len = strlen(varname);
- char *const winvarname = xmalloc(varname_len + 3);
- memcpy(winvarname, "w:", 2);
- memcpy(winvarname + 2, varname, varname_len + 1);
- set_var(winvarname, varname_len + 2, varp, true);
- xfree(winvarname);
- }
- }
- if (need_switch_win) {
- restore_win(&switchwin, true);
+ if (win == NULL || varname == NULL) {
+ return;
+ }
+
+ bool need_switch_win = !(tp == curtab && win == curwin);
+ switchwin_T switchwin;
+ if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) {
+ if (*varname == '&') {
+ set_option_from_tv(varname + 1, varp);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const winvarname = xmalloc(varname_len + 3);
+ memcpy(winvarname, "w:", 2);
+ memcpy(winvarname + 2, varname, varname_len + 1);
+ set_var(winvarname, varname_len + 2, varp, true);
+ xfree(winvarname);
}
}
+ if (need_switch_win) {
+ restore_win(&switchwin, true);
+ }
}
bool var_exists(const char *var)
@@ -1744,21 +1783,23 @@ void f_settabvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
const char *const varname = tv_get_string_chk(&argvars[1]);
typval_T *const varp = &argvars[2];
- if (varname != NULL && tp != NULL) {
- tabpage_T *const save_curtab = curtab;
- goto_tabpage_tp(tp, false, false);
+ if (varname == NULL || tp == NULL) {
+ return;
+ }
- const size_t varname_len = strlen(varname);
- char *const tabvarname = xmalloc(varname_len + 3);
- memcpy(tabvarname, "t:", 2);
- memcpy(tabvarname + 2, varname, varname_len + 1);
- set_var(tabvarname, varname_len + 2, varp, true);
- xfree(tabvarname);
-
- // Restore current tabpage.
- if (valid_tabpage(save_curtab)) {
- goto_tabpage_tp(save_curtab, false, false);
- }
+ tabpage_T *const save_curtab = curtab;
+ goto_tabpage_tp(tp, false, false);
+
+ const size_t varname_len = strlen(varname);
+ char *const tabvarname = xmalloc(varname_len + 3);
+ memcpy(tabvarname, "t:", 2);
+ memcpy(tabvarname + 2, varname, varname_len + 1);
+ set_var(tabvarname, varname_len + 2, varp, true);
+ xfree(tabvarname);
+
+ // Restore current tabpage.
+ if (valid_tabpage(save_curtab)) {
+ goto_tabpage_tp(save_curtab, false, false);
}
}
@@ -1785,27 +1826,29 @@ void f_setbufvar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
buf_T *const buf = tv_get_buf(&argvars[0], false);
typval_T *varp = &argvars[2];
- if (buf != NULL && varname != NULL) {
- if (*varname == '&') {
- aco_save_T aco;
+ if (buf == NULL || varname == NULL) {
+ return;
+ }
- // set curbuf to be our buf, temporarily
- aucmd_prepbuf(&aco, buf);
+ if (*varname == '&') {
+ aco_save_T aco;
- set_option_from_tv(varname + 1, varp);
+ // Set curbuf to be our buf, temporarily.
+ aucmd_prepbuf(&aco, buf);
- // reset notion of buffer
- aucmd_restbuf(&aco);
- } else {
- const size_t varname_len = strlen(varname);
- char *const bufvarname = xmalloc(varname_len + 3);
- buf_T *const save_curbuf = curbuf;
- curbuf = buf;
- memcpy(bufvarname, "b:", 2);
- memcpy(bufvarname + 2, varname, varname_len + 1);
- set_var(bufvarname, varname_len + 2, varp, true);
- xfree(bufvarname);
- curbuf = save_curbuf;
- }
+ set_option_from_tv(varname + 1, varp);
+
+ // reset notion of buffer
+ aucmd_restbuf(&aco);
+ } else {
+ const size_t varname_len = strlen(varname);
+ char *const bufvarname = xmalloc(varname_len + 3);
+ buf_T *const save_curbuf = curbuf;
+ curbuf = buf;
+ memcpy(bufvarname, "b:", 2);
+ memcpy(bufvarname + 2, varname, varname_len + 1);
+ set_var(bufvarname, varname_len + 2, varp, true);
+ xfree(bufvarname);
+ curbuf = save_curbuf;
}
}
diff --git a/src/nvim/eval/vars.h b/src/nvim/eval/vars.h
index 73efc4938a..b87c9d62cb 100644
--- a/src/nvim/eval/vars.h
+++ b/src/nvim/eval/vars.h
@@ -1,7 +1,7 @@
#ifndef NVIM_EVAL_VARS_H
#define NVIM_EVAL_VARS_H
-#include "nvim/ex_cmds_defs.h" // For exarg_T
+#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/vars.h.generated.h"
diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c
new file mode 100644
index 0000000000..f58a0c488a
--- /dev/null
+++ b/src/nvim/eval/window.c
@@ -0,0 +1,954 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// eval/window.c: Window related builtin functions
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/cursor.h"
+#include "nvim/eval/funcs.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/window.h"
+#include "nvim/garray.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/macros.h"
+#include "nvim/memline_defs.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/move.h"
+#include "nvim/option_defs.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/window.c.generated.h"
+#endif
+
+static char *e_invalwindow = N_("E957: Invalid window number");
+static char e_cannot_resize_window_in_another_tab_page[]
+ = N_("E1308: Cannot resize a window in another tab page");
+
+static int win_getid(typval_T *argvars)
+{
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ return curwin->handle;
+ }
+ int winnr = (int)tv_get_number(&argvars[0]);
+ win_T *wp;
+ if (winnr <= 0) {
+ return 0;
+ }
+
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ wp = firstwin;
+ } else {
+ tabpage_T *tp = NULL;
+ int tabnr = (int)tv_get_number(&argvars[1]);
+ FOR_ALL_TABS(tp2) {
+ if (--tabnr == 0) {
+ tp = tp2;
+ break;
+ }
+ }
+ if (tp == NULL) {
+ return -1;
+ }
+ if (tp == curtab) {
+ wp = firstwin;
+ } else {
+ wp = tp->tp_firstwin;
+ }
+ }
+ for (; wp != NULL; wp = wp->w_next) {
+ if (--winnr == 0) {
+ return wp->handle;
+ }
+ }
+ return 0;
+}
+
+static void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
+{
+ handle_T id = (handle_T)tv_get_number(&argvars[0]);
+
+ int winnr = 1;
+ int tabnr = 1;
+ win_get_tabwin(id, &tabnr, &winnr);
+
+ list_T *const list = tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(list, tabnr);
+ tv_list_append_number(list, winnr);
+}
+
+win_T *win_id2wp(int id)
+{
+ return win_id2wp_tp(id, NULL);
+}
+
+/// Return the window and tab pointer of window "id".
+win_T *win_id2wp_tp(int id, tabpage_T **tpp)
+{
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ if (tpp != NULL) {
+ *tpp = tp;
+ }
+ return wp;
+ }
+ }
+
+ return NULL;
+}
+
+static int win_id2win(typval_T *argvars)
+{
+ int nr = 1;
+ int id = (int)tv_get_number(&argvars[0]);
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->handle == id) {
+ return nr;
+ }
+ nr++;
+ }
+ return 0;
+}
+
+void win_findbuf(typval_T *argvars, list_T *list)
+{
+ int bufnr = (int)tv_get_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer->b_fnum == bufnr) {
+ tv_list_append_number(list, wp->handle);
+ }
+ }
+}
+
+/// Find window specified by "vp" in tabpage "tp".
+///
+/// @param tp NULL for current tab page
+/// @return current window if "vp" is number zero.
+/// NULL if not found.
+win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr < 0) {
+ return NULL;
+ }
+
+ if (nr == 0) {
+ return curwin;
+ }
+
+ // This method accepts NULL as an alias for curtab.
+ if (tp == NULL) {
+ tp = curtab;
+ }
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ if (nr >= LOWEST_WIN_ID) {
+ if (wp->handle == nr) {
+ return wp;
+ }
+ } else if (--nr <= 0) {
+ return wp;
+ }
+ }
+ return NULL;
+}
+
+/// Find a window: When using a Window ID in any tab page, when using a number
+/// in the current tab page.
+win_T *find_win_by_nr_or_id(typval_T *vp)
+{
+ int nr = (int)tv_get_number_chk(vp, NULL);
+
+ if (nr >= LOWEST_WIN_ID) {
+ return win_id2wp((int)tv_get_number(vp));
+ }
+
+ return find_win_by_nr(vp, NULL);
+}
+
+/// Find window specified by "wvp" in tabpage "tvp".
+win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
+{
+ win_T *wp = NULL;
+ tabpage_T *tp = NULL;
+
+ if (wvp->v_type != VAR_UNKNOWN) {
+ if (tvp->v_type != VAR_UNKNOWN) {
+ long n = tv_get_number(tvp);
+ if (n >= 0) {
+ tp = find_tabpage((int)n);
+ }
+ } else {
+ tp = curtab;
+ }
+
+ if (tp != NULL) {
+ wp = find_win_by_nr(wvp, tp);
+ }
+ } else {
+ wp = curwin;
+ }
+
+ return wp;
+}
+
+/// Get the layout of the given tab page for winlayout().
+static void get_framelayout(const frame_T *fr, list_T *l, bool outer)
+{
+ if (fr == NULL) {
+ return;
+ }
+
+ list_T *fr_list;
+ if (outer) {
+ // outermost call from f_winlayout()
+ fr_list = l;
+ } else {
+ fr_list = tv_list_alloc(2);
+ tv_list_append_list(l, fr_list);
+ }
+
+ if (fr->fr_layout == FR_LEAF) {
+ if (fr->fr_win != NULL) {
+ tv_list_append_string(fr_list, "leaf", -1);
+ tv_list_append_number(fr_list, fr->fr_win->handle);
+ }
+ } else {
+ tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
+
+ list_T *const win_list = tv_list_alloc(kListLenUnknown);
+ tv_list_append_list(fr_list, win_list);
+ const frame_T *child = fr->fr_child;
+ while (child != NULL) {
+ get_framelayout(child, win_list, false);
+ child = child->fr_next;
+ }
+ }
+}
+
+/// Common code for tabpagewinnr() and winnr().
+static int get_winnr(tabpage_T *tp, typval_T *argvar)
+{
+ int nr = 1;
+
+ win_T *twin = (tp == curtab) ? curwin : tp->tp_curwin;
+ if (argvar->v_type != VAR_UNKNOWN) {
+ bool invalid_arg = false;
+ const char *const arg = tv_get_string_chk(argvar);
+ if (arg == NULL) {
+ nr = 0; // Type error; errmsg already given.
+ } else if (strcmp(arg, "$") == 0) {
+ twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
+ } else if (strcmp(arg, "#") == 0) {
+ twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
+ if (twin == NULL) {
+ nr = 0;
+ }
+ } else {
+ // Extract the window count (if specified). e.g. winnr('3j')
+ char *endp;
+ long count = strtol((char *)arg, &endp, 10);
+ if (count <= 0) {
+ // if count is not specified, default to 1
+ count = 1;
+ }
+ if (endp != NULL && *endp != '\0') {
+ if (strequal(endp, "j")) {
+ twin = win_vert_neighbor(tp, twin, false, count);
+ } else if (strequal(endp, "k")) {
+ twin = win_vert_neighbor(tp, twin, true, count);
+ } else if (strequal(endp, "h")) {
+ twin = win_horz_neighbor(tp, twin, true, count);
+ } else if (strequal(endp, "l")) {
+ twin = win_horz_neighbor(tp, twin, false, count);
+ } else {
+ invalid_arg = true;
+ }
+ } else {
+ invalid_arg = true;
+ }
+ }
+
+ if (invalid_arg) {
+ semsg(_(e_invexpr2), arg);
+ nr = 0;
+ }
+ }
+
+ if (nr <= 0) {
+ return 0;
+ }
+
+ for (win_T *wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ wp != twin; wp = wp->w_next) {
+ if (wp == NULL) {
+ // didn't find it in this tabpage
+ nr = 0;
+ break;
+ }
+ nr++;
+ }
+ return nr;
+}
+
+/// @return information about a window as a dictionary.
+static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ // make sure w_botline is valid
+ validate_botline(wp);
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr);
+ tv_dict_add_nr(dict, S_LEN("winnr"), winnr);
+ tv_dict_add_nr(dict, S_LEN("winid"), wp->handle);
+ tv_dict_add_nr(dict, S_LEN("height"), wp->w_height_inner);
+ tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1);
+ tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline);
+ tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1);
+ tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height);
+ tv_dict_add_nr(dict, S_LEN("width"), wp->w_width_inner);
+ tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
+ tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
+ tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
+ tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
+ tv_dict_add_nr(dict, S_LEN("loclist"),
+ (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
+
+ // Add a reference to window variables
+ tv_dict_add_dict(dict, S_LEN("variables"), wp->w_vars);
+
+ return dict;
+}
+
+/// @return information (variables, options, etc.) about a tab page
+/// as a dictionary.
+static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx)
+{
+ dict_T *const dict = tv_dict_alloc();
+
+ tv_dict_add_nr(dict, S_LEN("tabnr"), tp_idx);
+
+ list_T *const l = tv_list_alloc(kListLenMayKnow);
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ tv_list_append_number(l, (varnumber_T)wp->handle);
+ }
+ tv_dict_add_list(dict, S_LEN("windows"), l);
+
+ // Make a reference to tabpage variables
+ tv_dict_add_dict(dict, S_LEN("variables"), tp->tp_vars);
+
+ return dict;
+}
+
+/// "gettabinfo()" function
+void f_gettabinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tabpage_T *tparg = NULL;
+
+ tv_list_alloc_ret(rettv, (argvars[0].v_type == VAR_UNKNOWN
+ ? 1
+ : kListLenMayKnow));
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ // Information about one tab page
+ tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+ if (tparg == NULL) {
+ return;
+ }
+ }
+
+ // Get information about a specific tab page or all tab pages
+ int tpnr = 0;
+ FOR_ALL_TABS(tp) {
+ tpnr++;
+ if (tparg != NULL && tp != tparg) {
+ continue;
+ }
+ dict_T *const d = get_tabpage_info(tp, tpnr);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (tparg != NULL) {
+ return;
+ }
+ }
+}
+
+/// "getwininfo()" function
+void f_getwininfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wparg = NULL;
+
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wparg = win_id2wp((int)tv_get_number(&argvars[0]));
+ if (wparg == NULL) {
+ return;
+ }
+ }
+
+ // Collect information about either all the windows across all the tab
+ // pages or one particular window.
+ int16_t tabnr = 0;
+ FOR_ALL_TABS(tp) {
+ tabnr++;
+ int16_t winnr = 0;
+ FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
+ winnr++;
+ if (wparg != NULL && wp != wparg) {
+ continue;
+ }
+ dict_T *const d = get_win_info(wp, tabnr, winnr);
+ tv_list_append_dict(rettv->vval.v_list, d);
+ if (wparg != NULL) {
+ // found information about a specific window
+ return;
+ }
+ }
+ }
+}
+
+/// "getwinpos({timeout})" function
+void f_getwinpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, 2);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+}
+
+/// "getwinposx()" function
+void f_getwinposx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+}
+
+/// "getwinposy()" function
+void f_getwinposy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = -1;
+}
+
+/// "tabpagenr()" function
+void f_tabpagenr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int nr = 1;
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ const char *const arg = tv_get_string_chk(&argvars[0]);
+ nr = 0;
+ if (arg != NULL) {
+ if (strcmp(arg, "$") == 0) {
+ nr = tabpage_index(NULL) - 1;
+ } else if (strcmp(arg, "#") == 0) {
+ nr = valid_tabpage(lastused_tabpage) ? tabpage_index(lastused_tabpage) : 0;
+ } else {
+ semsg(_(e_invexpr2), arg);
+ }
+ }
+ } else {
+ nr = tabpage_index(curtab);
+ }
+ rettv->vval.v_number = nr;
+}
+
+/// "tabpagewinnr()" function
+void f_tabpagewinnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int nr = 1;
+ tabpage_T *const tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ nr = 0;
+ } else {
+ nr = get_winnr(tp, &argvars[1]);
+ }
+ rettv->vval.v_number = nr;
+}
+
+/// "win_execute(win_id, command)" function
+void f_win_execute(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ // Return an empty string if something fails.
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+
+ int id = (int)tv_get_number(argvars);
+ tabpage_T *tp;
+ win_T *wp = win_id2wp_tp(id, &tp);
+ if (wp == NULL || tp == NULL) {
+ return;
+ }
+
+ WIN_EXECUTE(wp, tp, execute_common(argvars, rettv, 1));
+}
+
+/// "win_findbuf()" function
+void f_win_findbuf(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ win_findbuf(argvars, rettv->vval.v_list);
+}
+
+/// "win_getid()" function
+void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = win_getid(argvars);
+}
+
+/// "win_gotoid()" function
+void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int id = (int)tv_get_number(&argvars[0]);
+
+ if (cmdwin_type != 0) {
+ emsg(_(e_cmdwin));
+ return;
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->handle == id) {
+ goto_tabpage_win(tp, wp);
+ rettv->vval.v_number = 1;
+ return;
+ }
+ }
+}
+
+/// "win_id2tabwin()" function
+void f_win_id2tabwin(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_id2tabwin(argvars, rettv);
+}
+
+/// "win_id2win()" function
+void f_win_id2win(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = win_id2win(argvars);
+}
+
+/// "win_move_separator()" function
+void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = false;
+
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL || wp->w_floating) {
+ return;
+ }
+ if (!win_valid(wp)) {
+ emsg(_(e_cannot_resize_window_in_another_tab_page));
+ return;
+ }
+
+ int offset = (int)tv_get_number(&argvars[1]);
+ win_drag_vsep_line(wp, offset);
+ rettv->vval.v_number = true;
+}
+
+/// "win_move_statusline()" function
+void f_win_move_statusline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp;
+ int offset;
+
+ rettv->vval.v_number = false;
+
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL || wp->w_floating) {
+ return;
+ }
+ if (!win_valid(wp)) {
+ emsg(_(e_cannot_resize_window_in_another_tab_page));
+ return;
+ }
+
+ offset = (int)tv_get_number(&argvars[1]);
+ win_drag_status_line(wp, offset);
+ rettv->vval.v_number = true;
+}
+
+/// "win_screenpos()" function
+void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_list_alloc_ret(rettv, 2);
+ const win_T *const wp = find_win_by_nr_or_id(&argvars[0]);
+ tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
+ tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
+}
+
+/// Move the window wp into a new split of targetwin in a given direction
+static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
+{
+ int height = wp->w_height;
+ win_T *oldwin = curwin;
+
+ if (wp == targetwin || is_aucmd_win(wp)) {
+ return;
+ }
+
+ // Jump to the target window
+ if (curwin != targetwin) {
+ win_goto(targetwin);
+ }
+
+ // Remove the old window and frame from the tree of frames
+ int dir;
+ (void)winframe_remove(wp, &dir, NULL);
+ win_remove(wp, NULL);
+ last_status(false); // may need to remove last status line
+ (void)win_comp_pos(); // recompute window positions
+
+ // Split a window on the desired side and put the old window there
+ (void)win_split_ins(size, flags, wp, dir);
+
+ // If splitting horizontally, try to preserve height
+ if (size == 0 && !(flags & WSP_VERT)) {
+ win_setheight_win(height, wp);
+ if (p_ea) {
+ win_equal(wp, true, 'v');
+ }
+ }
+
+ if (oldwin != curwin) {
+ win_goto(oldwin);
+ }
+}
+
+/// "win_splitmove()" function
+void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ win_T *targetwin = find_win_by_nr_or_id(&argvars[1]);
+
+ if (wp == NULL || targetwin == NULL || wp == targetwin
+ || !win_valid(wp) || !win_valid(targetwin)
+ || win_valid_floating(wp) || win_valid_floating(targetwin)) {
+ emsg(_(e_invalwindow));
+ rettv->vval.v_number = -1;
+ return;
+ }
+
+ int flags = 0, size = 0;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ dict_T *d;
+ dictitem_T *di;
+
+ if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
+ emsg(_(e_invarg));
+ return;
+ }
+
+ d = argvars[2].vval.v_dict;
+ if (tv_dict_get_number(d, "vertical")) {
+ flags |= WSP_VERT;
+ }
+ if ((di = tv_dict_find(d, "rightbelow", -1)) != NULL) {
+ flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
+ }
+ size = (int)tv_dict_get_number(d, "size");
+ }
+
+ win_move_into_split(wp, targetwin, size, flags);
+}
+
+/// "win_gettype(nr)" function
+void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = curwin;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_string = xstrdup("unknown");
+ return;
+ }
+ }
+ if (is_aucmd_win(wp)) {
+ rettv->vval.v_string = xstrdup("autocmd");
+ } else if (wp->w_p_pvw) {
+ rettv->vval.v_string = xstrdup("preview");
+ } else if (wp->w_floating) {
+ rettv->vval.v_string = xstrdup("popup");
+ } else if (wp == curwin && cmdwin_type != 0) {
+ rettv->vval.v_string = xstrdup("command");
+ } else if (bt_quickfix(wp->w_buffer)) {
+ rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
+ }
+}
+
+/// "getcmdwintype()" function
+void f_getcmdwintype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ rettv->vval.v_string = xmallocz(1);
+ rettv->vval.v_string[0] = (char)cmdwin_type;
+}
+
+/// "winbufnr(nr)" function
+void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_buffer->b_fnum;
+ }
+}
+
+/// "wincol()" function
+void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wcol + 1;
+}
+
+/// "winheight(nr)" function
+void f_winheight(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_height_inner;
+ }
+}
+
+/// "winlayout()" function
+void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tabpage_T *tp;
+
+ tv_list_alloc_ret(rettv, 2);
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ return;
+ }
+ }
+
+ get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
+}
+
+/// "winline()" function
+void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ validate_cursor();
+ rettv->vval.v_number = curwin->w_wrow + 1;
+}
+
+/// "winnr()" function
+void f_winnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ rettv->vval.v_number = get_winnr(curtab, &argvars[0]);
+}
+
+/// "winrestcmd()" function
+void f_winrestcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ char buf[50];
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 70);
+
+ // Do this twice to handle some window layouts properly.
+ for (int i = 0; i < 2; i++) {
+ int winnr = 1;
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ snprintf(buf, sizeof(buf), "%dresize %d|", winnr,
+ wp->w_height);
+ ga_concat(&ga, buf);
+ snprintf(buf, sizeof(buf), "vert %dresize %d|", winnr,
+ wp->w_width);
+ ga_concat(&ga, buf);
+ winnr++;
+ }
+ }
+ ga_append(&ga, NUL);
+
+ rettv->vval.v_string = ga.ga_data;
+ rettv->v_type = VAR_STRING;
+}
+
+/// "winrestview()" function
+void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ dict_T *dict = argvars[0].vval.v_dict;
+
+ if (argvars[0].v_type != VAR_DICT || dict == NULL) {
+ emsg(_(e_invarg));
+ } else {
+ dictitem_T *di;
+ if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
+ curwin->w_cursor.lnum = (linenr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("col"))) != NULL) {
+ curwin->w_cursor.col = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("coladd"))) != NULL) {
+ curwin->w_cursor.coladd = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("curswant"))) != NULL) {
+ curwin->w_curswant = (colnr_T)tv_get_number(&di->di_tv);
+ curwin->w_set_curswant = false;
+ }
+ if ((di = tv_dict_find(dict, S_LEN("topline"))) != NULL) {
+ set_topline(curwin, (linenr_T)tv_get_number(&di->di_tv));
+ }
+ if ((di = tv_dict_find(dict, S_LEN("topfill"))) != NULL) {
+ curwin->w_topfill = (int)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("leftcol"))) != NULL) {
+ curwin->w_leftcol = (colnr_T)tv_get_number(&di->di_tv);
+ }
+ if ((di = tv_dict_find(dict, S_LEN("skipcol"))) != NULL) {
+ curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv);
+ }
+
+ check_cursor();
+ win_new_height(curwin, curwin->w_height);
+ win_new_width(curwin, curwin->w_width);
+ changed_window_setting();
+
+ if (curwin->w_topline <= 0) {
+ curwin->w_topline = 1;
+ }
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
+ curwin->w_topline = curbuf->b_ml.ml_line_count;
+ }
+ check_topfill(curwin, true);
+ }
+}
+
+/// "winsaveview()" function
+void f_winsaveview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ tv_dict_alloc_ret(rettv);
+ dict_T *dict = rettv->vval.v_dict;
+
+ tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)curwin->w_cursor.lnum);
+ tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)curwin->w_cursor.col);
+ tv_dict_add_nr(dict, S_LEN("coladd"), (varnumber_T)curwin->w_cursor.coladd);
+ update_curswant();
+ tv_dict_add_nr(dict, S_LEN("curswant"), (varnumber_T)curwin->w_curswant);
+
+ tv_dict_add_nr(dict, S_LEN("topline"), (varnumber_T)curwin->w_topline);
+ tv_dict_add_nr(dict, S_LEN("topfill"), (varnumber_T)curwin->w_topfill);
+ tv_dict_add_nr(dict, S_LEN("leftcol"), (varnumber_T)curwin->w_leftcol);
+ tv_dict_add_nr(dict, S_LEN("skipcol"), (varnumber_T)curwin->w_skipcol);
+}
+
+/// "winwidth(nr)" function
+void f_winwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ win_T *wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = wp->w_width_inner;
+ }
+}
+
+/// Set "win" to be the curwin and "tp" to be the current tab page.
+/// restore_win() MUST be called to undo, also when FAIL is returned.
+/// No autocommands will be executed until restore_win() is called.
+///
+/// @param no_display if true the display won't be affected, no redraw is
+/// triggered, another tabpage access is limited.
+///
+/// @return FAIL if switching to "win" failed.
+int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
+{
+ block_autocmds();
+ return switch_win_noblock(switchwin, win, tp, no_display);
+}
+
+// As switch_win() but without blocking autocommands.
+int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
+{
+ CLEAR_POINTER(switchwin);
+ switchwin->sw_curwin = curwin;
+ if (win == curwin) {
+ switchwin->sw_same_win = true;
+ } else {
+ // Disable Visual selection, because redrawing may fail.
+ switchwin->sw_visual_active = VIsual_active;
+ VIsual_active = false;
+ }
+
+ if (tp != NULL) {
+ switchwin->sw_curtab = curtab;
+ if (no_display) {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = tp;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ } else {
+ goto_tabpage_tp(tp, false, false);
+ }
+ }
+ if (!win_valid(win)) {
+ return FAIL;
+ }
+ curwin = win;
+ curbuf = curwin->w_buffer;
+ return OK;
+}
+
+// Restore current tabpage and window saved by switch_win(), if still valid.
+// When "no_display" is true the display won't be affected, no redraw is
+// triggered.
+void restore_win(switchwin_T *switchwin, bool no_display)
+{
+ restore_win_noblock(switchwin, no_display);
+ unblock_autocmds();
+}
+
+// As restore_win() but without unblocking autocommands.
+void restore_win_noblock(switchwin_T *switchwin, bool no_display)
+{
+ if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
+ if (no_display) {
+ curtab->tp_firstwin = firstwin;
+ curtab->tp_lastwin = lastwin;
+ curtab = switchwin->sw_curtab;
+ firstwin = curtab->tp_firstwin;
+ lastwin = curtab->tp_lastwin;
+ } else {
+ goto_tabpage_tp(switchwin->sw_curtab, false, false);
+ }
+ }
+
+ if (!switchwin->sw_same_win) {
+ VIsual_active = switchwin->sw_visual_active;
+ }
+
+ if (win_valid(switchwin->sw_curwin)) {
+ curwin = switchwin->sw_curwin;
+ curbuf = curwin->w_buffer;
+ }
+}
diff --git a/src/nvim/eval/window.h b/src/nvim/eval/window.h
new file mode 100644
index 0000000000..995f0a55a9
--- /dev/null
+++ b/src/nvim/eval/window.h
@@ -0,0 +1,78 @@
+#ifndef NVIM_EVAL_WINDOW_H
+#define NVIM_EVAL_WINDOW_H
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/cursor.h"
+#include "nvim/eval/typval_defs.h"
+#include "nvim/globals.h"
+#include "nvim/mark.h"
+#include "nvim/option_defs.h"
+#include "nvim/os/os.h"
+#include "nvim/pos.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+/// Structure used by switch_win() to pass values to restore_win()
+typedef struct {
+ win_T *sw_curwin;
+ tabpage_T *sw_curtab;
+ bool sw_same_win; ///< VIsual_active was not reset
+ bool sw_visual_active;
+} switchwin_T;
+
+/// Execute a block of code in the context of window `wp` in tabpage `tp`.
+/// Ensures the status line is redrawn and cursor position is valid if it is moved.
+#define WIN_EXECUTE(wp, tp, block) \
+ do { \
+ win_T *const wp_ = (wp); \
+ const pos_T curpos_ = wp_->w_cursor; \
+ char cwd_[MAXPATHL]; \
+ char autocwd_[MAXPATHL]; \
+ bool apply_acd_ = false; \
+ int cwd_status_ = FAIL; \
+ /* Getting and setting directory can be slow on some systems, only do */ \
+ /* this when the current or target window/tab have a local directory or */ \
+ /* 'acd' is set. */ \
+ if (curwin != wp \
+ && (curwin->w_localdir != NULL || wp->w_localdir != NULL \
+ || (curtab != tp && (curtab->tp_localdir != NULL || tp->tp_localdir != NULL)) \
+ || p_acd)) { \
+ cwd_status_ = os_dirname(cwd_, MAXPATHL); \
+ } \
+ /* If 'acd' is set, check we are using that directory. If yes, then */ \
+ /* apply 'acd' afterwards, otherwise restore the current directory. */ \
+ if (cwd_status_ == OK && p_acd) { \
+ do_autochdir(); \
+ apply_acd_ = os_dirname(autocwd_, MAXPATHL) == OK && strcmp(cwd_, autocwd_) == 0; \
+ } \
+ switchwin_T switchwin_; \
+ if (switch_win_noblock(&switchwin_, wp_, (tp), true) == OK) { \
+ check_cursor(); \
+ block; \
+ } \
+ restore_win_noblock(&switchwin_, true); \
+ if (apply_acd_) { \
+ do_autochdir(); \
+ } else if (cwd_status_ == OK) { \
+ os_chdir(cwd_); \
+ } \
+ /* Update the status line if the cursor moved. */ \
+ if (win_valid(wp_) && !equalpos(curpos_, wp_->w_cursor)) { \
+ wp_->w_redr_status = true; \
+ } \
+ /* In case the command moved the cursor or changed the Visual area, */ \
+ /* check it is valid. */ \
+ check_cursor(); \
+ if (VIsual_active) { \
+ check_pos(curbuf, &VIsual); \
+ } \
+ } while (false)
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/window.h.generated.h"
+#endif
+#endif // NVIM_EVAL_WINDOW_H