diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 256 | ||||
-rw-r--r-- | src/nvim/eval.lua | 3 | ||||
-rw-r--r-- | src/nvim/option.c | 25 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_bufwintabinfo.vim | 38 | ||||
-rw-r--r-- | src/nvim/version.c | 2 | ||||
-rw-r--r-- | src/nvim/window.c | 13 |
7 files changed, 337 insertions, 1 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index bdbd77337d..91f7233a21 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6611,6 +6611,23 @@ int dict_add_list(dict_T *d, char *key, list_T *list) return OK; } +/// Add a dict entry to dictionary "d". +/// Returns FAIL when out of memory and when key already exists. +int dict_add_dict(dict_T *d, char *key, dict_T *dict) +{ + dictitem_T *item = dictitem_alloc((char_u *)key); + + item->di_tv.v_lock = 0; + item->di_tv.v_type = VAR_DICT; + item->di_tv.vval.v_dict = dict; + if (dict_add(d, item) == FAIL) { + dictitem_free(item); + return FAIL; + } + dict->dv_refcount++; + return OK; +} + /// Set all existing keys in "dict" as read-only. /// /// This does not protect against adding new keys to the Dictionary. @@ -9832,6 +9849,127 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) copy_tv(tv, rettv); } +/// Returns information about signs placed in a buffer as list of dicts. +static void get_buffer_signs(buf_T *buf, list_T *l) +{ + for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) { + dict_T *d = dict_alloc(); + + dict_add_nr_str(d, "id", sign->id, NULL); + dict_add_nr_str(d, "lnum", sign->lnum, NULL); + dict_add_nr_str(d, "name", 0L, vim_strsave(sign_typenr2name(sign->typenr))); + + list_append_dict(l, d); + } +} + +/// Returns buffer options, variables and other attributes in a dictionary. +static dict_T *get_buffer_info(buf_T *buf) +{ + dict_T *dict = dict_alloc(); + + dict_add_nr_str(dict, "nr", buf->b_fnum, NULL); + dict_add_nr_str(dict, "name", 0L, + buf->b_ffname != NULL ? buf->b_ffname : (char_u *)""); + dict_add_nr_str(dict, "lnum", buflist_findlnum(buf), NULL); + dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL); + dict_add_nr_str(dict, "listed", buf->b_p_bl, NULL); + dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL); + dict_add_nr_str(dict, "changedtick", buf->b_changedtick, NULL); + dict_add_nr_str(dict, "hidden", + buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0, + NULL); + + // Copy buffer variables + dict_T *vars = dict_copy(NULL, buf->b_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + // Copy buffer options + dict_T *opts = get_winbuf_options(true); + if (opts != NULL) { + dict_add_dict(dict, "options", opts); + } + + // List of windows displaying this buffer + list_T *windows = list_alloc(); + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf) { + list_append_number(windows, (varnumber_T)wp->handle); + } + } + dict_add_list(dict, "windows", windows); + + if (buf->b_signlist != NULL) { + // List of signs placed in this buffer + list_T *signs = list_alloc(); + get_buffer_signs(buf, signs); + dict_add_list(dict, "signs", signs); + } + + return dict; +} + +/// "getbufinfo()" function +static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + buf_T *argbuf = NULL; + bool filtered = false; + bool sel_buflisted = false; + bool sel_bufloaded = false; + + rettv_list_alloc(rettv); + + // 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 = dict_find(sel_d, (char_u *)"buflisted", -1); + if (di != NULL && get_tv_number(&di->di_tv)) { + sel_buflisted = true; + } + + di = dict_find(sel_d, (char_u *)"bufloaded", -1); + if (di != NULL && get_tv_number(&di->di_tv)) { + sel_bufloaded = true; + } + } + } else if (argvars[0].v_type != VAR_UNKNOWN) { + // Information about one buffer. Argument specifies the buffer + (void)get_tv_number(&argvars[0]); // issue errmsg if type error + emsg_off++; + argbuf = get_buf_tv(&argvars[0], false); + emsg_off--; + 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))) { + continue; + } + + dict_T *d = get_buffer_info(buf); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (argbuf != NULL) { + return; + } + } +} /* * Get line or list of lines from buffer "buf" into "rettv". @@ -10654,6 +10792,60 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = (char_u *)xstrdup(buf); } +/// Returns 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 *dict = dict_alloc(); + + dict_add_nr_str(dict, "nr", tp_idx, NULL); + + list_T *l = list_alloc(); + FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + list_append_number(l, (varnumber_T)wp->handle); + } + dict_add_list(dict, "windows", l); + + // Copy tabpage variables + dict_T *vars = dict_copy(NULL, tp->tp_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + return dict; +} + +/// "gettabinfo()" function +static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tabpage_T *tparg = NULL; + + rettv_list_alloc(rettv); + + if (argvars[0].v_type != VAR_UNKNOWN) { + // Information about one tab page + tparg = find_tabpage((int)get_tv_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 *d = get_tabpage_info(tp, tpnr); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (tparg != NULL) { + return; + } + } +} + /* * "gettabvar()" function */ @@ -10701,6 +10893,70 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) getwinvar(argvars, rettv, 1); } +/// Returns information about a window as a dictionary. +static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) +{ + dict_T *dict = dict_alloc(); + + dict_add_nr_str(dict, "tpnr", tpnr, NULL); + dict_add_nr_str(dict, "nr", winnr, NULL); + dict_add_nr_str(dict, "winid", wp->handle, NULL); + dict_add_nr_str(dict, "height", wp->w_height, NULL); + dict_add_nr_str(dict, "width", wp->w_width, NULL); + dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL); + + // Copy window variables + dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); + if (vars != NULL) { + dict_add_dict(dict, "variables", vars); + } + + // Copy window options + dict_T *opts = get_winbuf_options(false); + if (opts != NULL) { + dict_add_dict(dict, "options", opts); + } + + return dict; +} + +/// "getwininfo()" function +static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + win_T *wparg = NULL; + + rettv_list_alloc(rettv); + + if (argvars[0].v_type != VAR_UNKNOWN) { + wparg = win_id2wp(argvars); + if (wparg == NULL) { + return; + } + } + + // Collect information about either all the windows across all the tab + // pages or one particular window. + short tabnr = 0; + FOR_ALL_TABS(tp) { + tabnr++; + short winnr = 0; + FOR_ALL_WINDOWS_IN_TAB(wp, tp) { + if (wparg != NULL && wp != wparg) { + continue; + } + winnr++; + dict_T *d = get_win_info(wp, tabnr, winnr); + if (d != NULL) { + list_append_dict(rettv->vval.v_list, d); + } + if (wparg != NULL) { + // found information about a specific window + return; + } + } + } +} + /* * "getwinposx()" function */ diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index a0671cac1f..980a8d2326 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -106,6 +106,7 @@ return { ['function']={args={1, 3}}, garbagecollect={args={0, 1}}, get={args={2, 3}}, + getbufinfo={args={0, 1}}, getbufline={args={2, 3}}, getbufvar={args={2, 3}}, getchar={args={0, 1}}, @@ -131,8 +132,10 @@ return { getqflist={}, getreg={args={0, 3}}, getregtype={args={0, 1}}, + gettabinfo={args={0, 1}}, gettabvar={args={2, 3}}, gettabwinvar={args={3, 4}}, + getwininfo={args={0, 1}}, getwinposx={}, getwinposy={}, getwinvar={args={2, 3}}, diff --git a/src/nvim/option.c b/src/nvim/option.c index 2249ef6e95..817e35d550 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -6923,3 +6923,28 @@ bool signcolumn_on(win_T *wp) } return wp->w_buffer->b_signlist != NULL; } + +/// Get window or buffer local options. +dict_T * get_winbuf_options(int bufopt) +{ + dict_T *d = dict_alloc(); + + for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { + struct vimoption *opt = &options[opt_idx]; + + if ((bufopt && (opt->indir & PV_BUF)) + || (!bufopt && (opt->indir & PV_WIN))) { + char_u *varp = get_varp(opt); + + if (varp != NULL) { + if (opt->flags & P_STRING) { + dict_add_nr_str(d, opt->fullname, 0L, *(char_u **)varp); + } else { + dict_add_nr_str(d, opt->fullname, *varp, NULL); + } + } + } + } + + return d; +} diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index e27be54fc9..84a0c0b889 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -30,6 +30,7 @@ SCRIPTS := \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ + test_bufwintabinfo.res \ test_cmdline.res \ test_cscope.res \ test_diffmode.res \ diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim new file mode 100644 index 0000000000..236ca30f99 --- /dev/null +++ b/src/nvim/testdir/test_bufwintabinfo.vim @@ -0,0 +1,38 @@ +" Tests for the getbufinfo(), getwininfo() and gettabinfo() functions + +function Test_getbufwintabinfo() + 1,$bwipeout + edit Xtestfile1 + edit Xtestfile2 + let buflist = getbufinfo() + call assert_equal(2, len(buflist)) + call assert_match('Xtestfile1', buflist[0].name) + call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name) + call assert_equal([], getbufinfo(2016)) + edit Xtestfile1 + hide edit Xtestfile2 + hide enew + call assert_equal(3, len(getbufinfo({'bufloaded':1}))) + + only + let w1_id = win_getid() + new + let w2_id = win_getid() + tabnew | let w3_id = win_getid() + new | let w4_id = win_getid() + new | let w5_id = win_getid() + tabfirst + let winlist = getwininfo() + call assert_equal(5, len(winlist)) + call assert_equal(2, winlist[3].tpnr) + let winfo = getwininfo(w5_id)[0] + call assert_equal(2, winfo.tpnr) + call assert_equal([], getwininfo(3)) + + let tablist = gettabinfo() + call assert_equal(2, len(tablist)) + call assert_equal(3, len(tablist[1].windows)) + call assert_equal([], gettabinfo(3)) + + tabonly | only +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index e89bc49210..b1bb9f02f4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -236,7 +236,7 @@ static int included_patches[] = { // 2207 NA // 2206 NA 2205, - // 2204, + 2204, // 2203 NA // 2202 NA 2201, diff --git a/src/nvim/window.c b/src/nvim/window.c index 3e7aed7867..00229ccca9 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5797,6 +5797,19 @@ void win_id2tabwin(typval_T *argvars, list_T *list) list_append_number(list, winnr); } +win_T * win_id2wp(typval_T *argvars) +{ + int id = get_tv_number(&argvars[0]); + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->handle == id) { + return wp; + } + } + + return NULL; +} + int win_id2win(typval_T *argvars) { win_T *wp; |