summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-08-12 22:23:25 +0200
committerBram Moolenaar <Bram@vim.org>2016-08-12 22:23:25 +0200
commitb5ae48e9ffd3b8eb6ca4057de11f1bddcde8ce6f (patch)
tree4102b935644caa2544138f3abb1d038523568d94 /src
parentebcccad573a7722e16cf2dd435cc62b61f61d9cc (diff)
patch 7.4.2204v7.4.2204
Problem: It is not easy to get information about buffers, windows and tabpages. Solution: Add getbufinfo(), getwininfo() and gettabinfo(). (Yegappan Lakshmanan)
Diffstat (limited to 'src')
-rw-r--r--src/Makefile1
-rw-r--r--src/dict.c24
-rw-r--r--src/evalfunc.c317
-rw-r--r--src/option.c37
-rw-r--r--src/proto/dict.pro1
-rw-r--r--src/proto/option.pro1
-rw-r--r--src/proto/window.pro1
-rw-r--r--src/testdir/Make_all.mak1
-rw-r--r--src/testdir/test_bufwintabinfo.vim38
-rw-r--r--src/version.c2
-rw-r--r--src/window.c14
11 files changed, 437 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
index e15df1bc54..dbfa90b5d3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2056,6 +2056,7 @@ test_arglist \
test_autochdir \
test_autocmd \
test_backspace_opt \
+ test_bufwintabinfo \
test_cdo \
test_channel \
test_cmdline \
diff --git a/src/dict.c b/src/dict.c
index 30a15a6f07..d78d42d521 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -367,6 +367,30 @@ dict_add_list(dict_T *d, char *key, list_T *list)
}
/*
+ * 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;
+
+ item = dictitem_alloc((char_u *)key);
+ if (item == NULL)
+ return FAIL;
+ 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;
+}
+
+/*
* Get the number of items in a Dictionary.
*/
long
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 8bb002adbf..ab4f9fd15f 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -152,6 +152,7 @@ static void f_funcref(typval_T *argvars, typval_T *rettv);
static void f_function(typval_T *argvars, typval_T *rettv);
static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
static void f_get(typval_T *argvars, typval_T *rettv);
+static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
static void f_getbufline(typval_T *argvars, typval_T *rettv);
static void f_getbufvar(typval_T *argvars, typval_T *rettv);
static void f_getchar(typval_T *argvars, typval_T *rettv);
@@ -179,8 +180,10 @@ static void f_getpos(typval_T *argvars, typval_T *rettv);
static void f_getqflist(typval_T *argvars, typval_T *rettv);
static void f_getreg(typval_T *argvars, typval_T *rettv);
static void f_getregtype(typval_T *argvars, typval_T *rettv);
+static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
static void f_gettabvar(typval_T *argvars, typval_T *rettv);
static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
+static void f_getwininfo(typval_T *argvars, typval_T *rettv);
static void f_getwinposx(typval_T *argvars, typval_T *rettv);
static void f_getwinposy(typval_T *argvars, typval_T *rettv);
static void f_getwinvar(typval_T *argvars, typval_T *rettv);
@@ -572,6 +575,7 @@ static struct fst
{"function", 1, 3, f_function},
{"garbagecollect", 0, 1, f_garbagecollect},
{"get", 2, 3, f_get},
+ {"getbufinfo", 0, 1, f_getbufinfo},
{"getbufline", 2, 3, f_getbufline},
{"getbufvar", 2, 3, f_getbufvar},
{"getchar", 0, 1, f_getchar},
@@ -599,8 +603,10 @@ static struct fst
{"getqflist", 0, 1, f_getqflist},
{"getreg", 0, 3, f_getreg},
{"getregtype", 0, 1, f_getregtype},
+ {"gettabinfo", 0, 1, f_gettabinfo},
{"gettabvar", 2, 3, f_gettabvar},
{"gettabwinvar", 3, 4, f_gettabwinvar},
+ {"getwininfo", 0, 1, f_getwininfo},
{"getwinposx", 0, 0, f_getwinposx},
{"getwinposy", 0, 0, f_getwinposy},
{"getwinvar", 2, 3, f_getwinvar},
@@ -3882,6 +3888,161 @@ f_get(typval_T *argvars, typval_T *rettv)
copy_tv(tv, rettv);
}
+#ifdef FEAT_SIGNS
+/*
+ * Returns information about signs placed in a buffer as list of dicts.
+ */
+ static void
+get_buffer_signs(buf_T *buf, list_T *l)
+{
+ signlist_T *sign;
+
+ for (sign = buf->b_signlist; sign; sign = sign->next)
+ {
+ dict_T *d = dict_alloc();
+
+ if (d != NULL)
+ {
+ 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);
+ }
+ }
+}
+#endif
+
+/*
+ * Returns buffer options, variables and other attributes in a dictionary.
+ */
+ static dict_T *
+get_buffer_info(buf_T *buf)
+{
+ dict_T *dict;
+ dict_T *opts;
+ dict_T *vars;
+ tabpage_T *tp;
+ win_T *wp;
+ list_T *windows;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ 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 */
+ vars = dict_copy(buf->b_vars, TRUE, 0);
+ if (vars != NULL)
+ dict_add_dict(dict, "variables", vars);
+
+ /* Copy buffer options */
+ opts = get_winbuf_options(TRUE);
+ if (opts != NULL)
+ dict_add_dict(dict, "options", opts);
+
+ /* List of windows displaying this buffer */
+ windows = list_alloc();
+ if (windows != NULL)
+ {
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_buffer == buf)
+ list_append_number(windows, (varnumber_T)wp->w_id);
+ dict_add_list(dict, "windows", windows);
+ }
+
+#ifdef FEAT_SIGNS
+ if (buf->b_signlist != NULL)
+ {
+ /* List of signs placed in this buffer */
+ list_T *signs = list_alloc();
+ if (signs != NULL)
+ {
+ get_buffer_signs(buf, signs);
+ dict_add_list(dict, "signs", signs);
+ }
+ }
+#endif
+
+ return dict;
+}
+
+/*
+ * "getbufinfo()" function
+ */
+ static void
+f_getbufinfo(typval_T *argvars, typval_T *rettv)
+{
+ buf_T *buf = NULL;
+ buf_T *argbuf = NULL;
+ dict_T *d;
+ int filtered = FALSE;
+ int sel_buflisted = FALSE;
+ int sel_bufloaded = FALSE;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ /* 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 (buf = firstbuf; buf != NULL; buf = buf->b_next)
+ {
+ if (argbuf != NULL && argbuf != buf)
+ continue;
+ if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
+ || (sel_buflisted && !buf->b_p_bl)))
+ continue;
+
+ d = get_buffer_info(buf);
+ if (d != NULL)
+ list_append_dict(rettv->vval.v_list, d);
+ if (argbuf != NULL)
+ return;
+ }
+}
+
static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
/*
@@ -4817,6 +4978,79 @@ f_getregtype(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = vim_strsave(buf);
}
+#ifdef FEAT_WINDOWS
+/*
+ * Returns information (variables, options, etc.) about a tab page
+ * as a dictionary.
+ */
+ static dict_T *
+get_tabpage_info(tabpage_T *tp, int tp_idx)
+{
+ win_T *wp;
+ dict_T *dict;
+ dict_T *vars;
+ list_T *l;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_nr_str(dict, "nr", tp_idx, NULL);
+
+ l = list_alloc();
+ if (l != NULL)
+ {
+ for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ wp; wp = wp->w_next)
+ list_append_number(l, (varnumber_T)wp->w_id);
+ dict_add_list(dict, "windows", l);
+ }
+
+ /* Copy tabpage variables */
+ vars = dict_copy(tp->tp_vars, TRUE, 0);
+ if (vars != NULL)
+ dict_add_dict(dict, "variables", vars);
+
+ return dict;
+}
+#endif
+
+/*
+ * "gettabinfo()" function
+ */
+ static void
+f_gettabinfo(typval_T *argvars, typval_T *rettv)
+{
+#ifdef FEAT_WINDOWS
+ tabpage_T *tp, *tparg = NULL;
+ dict_T *d;
+ int tpnr = 1;
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+ 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 */
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, tpnr++)
+ {
+ if (tparg != NULL && tp != tparg)
+ continue;
+ d = get_tabpage_info(tp, tpnr);
+ if (d != NULL)
+ list_append_dict(rettv->vval.v_list, d);
+ if (tparg != NULL)
+ return;
+ }
+#endif
+}
+
/*
* "gettabvar()" function
*/
@@ -4869,6 +5103,89 @@ f_gettabwinvar(typval_T *argvars, typval_T *rettv)
getwinvar(argvars, rettv, 1);
}
+#ifdef FEAT_WINDOWS
+/*
+ * 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_T *vars;
+ dict_T *opts;
+
+ dict = dict_alloc();
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_nr_str(dict, "tpnr", tpnr, NULL);
+ dict_add_nr_str(dict, "nr", winnr, NULL);
+ dict_add_nr_str(dict, "winid", wp->w_id, 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 */
+ vars = dict_copy(wp->w_vars, TRUE, 0);
+ if (vars != NULL)
+ dict_add_dict(dict, "variables", vars);
+
+ /* Copy window options */
+ opts = get_winbuf_options(FALSE);
+ if (opts != NULL)
+ dict_add_dict(dict, "options", opts);
+
+ return dict;
+}
+#endif
+
+/*
+ * "getwininfo()" function
+ */
+ static void
+f_getwininfo(typval_T *argvars, typval_T *rettv)
+{
+#ifdef FEAT_WINDOWS
+ tabpage_T *tp;
+ win_T *wp = NULL, *wparg = NULL;
+ dict_T *d;
+ short tabnr, winnr;
+#endif
+
+ if (rettv_list_alloc(rettv) != OK)
+ return;
+
+#ifdef FEAT_WINDOWS
+ 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.
+ */
+ tabnr = 1;
+ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, tabnr++)
+ {
+ wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ winnr = 1;
+ for (; wp; wp = wp->w_next, winnr++)
+ {
+ if (wparg != NULL && wp != wparg)
+ continue;
+ 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;
+ }
+ }
+#endif
+}
+
/*
* "getwinposx()" function
*/
diff --git a/src/option.c b/src/option.c
index ba07482429..d1a25339be 100644
--- a/src/option.c
+++ b/src/option.c
@@ -12329,3 +12329,40 @@ signcolumn_on(win_T *wp)
);
}
#endif
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Get window or buffer local options.
+ */
+ dict_T *
+get_winbuf_options(int bufopt)
+{
+ dict_T *d;
+ int opt_idx;
+
+ d = dict_alloc();
+ if (d == NULL)
+ return NULL;
+
+ for (opt_idx = 0; !istermoption(&options[opt_idx]); 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;
+}
+#endif
diff --git a/src/proto/dict.pro b/src/proto/dict.pro
index 10a5b6bf1d..61f4dfa5b2 100644
--- a/src/proto/dict.pro
+++ b/src/proto/dict.pro
@@ -11,6 +11,7 @@ dict_T *dict_copy(dict_T *orig, int deep, int copyID);
int dict_add(dict_T *d, dictitem_T *item);
int dict_add_nr_str(dict_T *d, char *key, varnumber_T nr, char_u *str);
int dict_add_list(dict_T *d, char *key, list_T *list);
+int dict_add_dict(dict_T *d, char *key, dict_T *dict);
long dict_len(dict_T *d);
dictitem_T *dict_find(dict_T *d, char_u *key, int len);
char_u *get_dict_string(dict_T *d, char_u *key, int save);
diff --git a/src/proto/option.pro b/src/proto/option.pro
index 3da0e945e0..8c9bde583a 100644
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -64,4 +64,5 @@ long get_sts_value(void);
void find_mps_values(int *initc, int *findc, int *backwards, int switchit);
unsigned int get_bkc_value(buf_T *buf);
int signcolumn_on(win_T *wp);
+dict_T *get_winbuf_options(int bufopt);
/* vim: set ft=c : */
diff --git a/src/proto/window.pro b/src/proto/window.pro
index e091e34ad8..ebd71ed951 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -86,6 +86,7 @@ int get_tab_number(tabpage_T *tp);
int win_getid(typval_T *argvars);
int win_gotoid(typval_T *argvars);
void win_id2tabwin(typval_T *argvars, list_T *list);
+win_T *win_id2wp(typval_T *argvars);
int win_id2win(typval_T *argvars);
void win_findbuf(typval_T *argvars, list_T *list);
/* vim: set ft=c : */
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 0a5ee927b0..2692b72250 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -160,6 +160,7 @@ NEW_TESTS = test_arglist.res \
test_assert.res \
test_autochdir \
test_backspace_opt.res \
+ test_bufwintabinfo.res \
test_cdo.res \
test_channel.res \
test_cmdline.res \
diff --git a/src/testdir/test_bufwintabinfo.vim b/src/testdir/test_bufwintabinfo.vim
new file mode 100644
index 0000000000..236ca30f99
--- /dev/null
+++ b/src/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/version.c b/src/version.c
index 3e34e0a00b..11ab8f6f10 100644
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2204,
+/**/
2203,
/**/
2202,
diff --git a/src/window.c b/src/window.c
index 925a147130..c6409e1e03 100644
--- a/src/window.c
+++ b/src/window.c
@@ -7147,6 +7147,20 @@ win_id2tabwin(typval_T *argvars, list_T *list)
list_append_number(list, 0);
}
+ win_T *
+win_id2wp(typval_T *argvars)
+{
+ win_T *wp;
+ tabpage_T *tp;
+ int id = get_tv_number(&argvars[0]);
+
+ FOR_ALL_TAB_WINDOWS(tp, wp)
+ if (wp->w_id == id)
+ return wp;
+
+ return NULL;
+}
+
int
win_id2win(typval_T *argvars)
{