aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames McCoy <jamessan@jamessan.com>2016-11-15 12:06:10 -0500
committerJames McCoy <jamessan@jamessan.com>2016-12-28 14:57:38 -0500
commit00466410701802214aba5c95f1cbb2e5086a37f5 (patch)
tree475ac94ef210e89b2a36deb9bbcfc0dbf212c7f0
parent99a8cd3be0509e97b649edc1599bfb74bf2b4802 (diff)
downloadrneovim-00466410701802214aba5c95f1cbb2e5086a37f5.tar.gz
rneovim-00466410701802214aba5c95f1cbb2e5086a37f5.tar.bz2
rneovim-00466410701802214aba5c95f1cbb2e5086a37f5.zip
vim-patch:7.4.2204
Problem: It is not easy to get information about buffers, windows and tabpages. Solution: Add getbufinfo(), getwininfo() and gettabinfo(). (Yegappan Lakshmanan) https://github.com/vim/vim/commit/b5ae48e9ffd3b8eb6ca4057de11f1bddcde8ce6f
-rw-r--r--runtime/doc/eval.txt84
-rw-r--r--runtime/doc/usr_41.txt5
-rw-r--r--src/nvim/eval.c256
-rw-r--r--src/nvim/eval.lua3
-rw-r--r--src/nvim/option.c25
-rw-r--r--src/nvim/testdir/Makefile1
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim38
-rw-r--r--src/nvim/version.c2
-rw-r--r--src/nvim/window.c13
9 files changed, 425 insertions, 2 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 367f64df9b..9e08c64de9 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1956,6 +1956,7 @@ garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
get({func}, {what}) any get property of funcref/partial {func}
+getbufinfo( [{expr}]) List information about buffers
getbufline({expr}, {lnum} [, {end}])
List lines {lnum} to {end} of buffer {expr}
getbufvar({expr}, {varname} [, {def}])
@@ -1986,10 +1987,12 @@ getqflist() List list of quickfix items
getreg([{regname} [, 1 [, {list}]]])
String or List contents of register
getregtype([{regname}]) String type of register
+gettabinfo( [{expr}]) List list of tab pages
gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def}
gettabwinvar({tabnr}, {winnr}, {name} [, {def}])
any {name} in {winnr} in tab page {tabnr}
+getwininfo( [{winid}]) List list of windows
getwinposx() Number X coord in pixels of GUI Vim window
getwinposy() Number Y coord in pixels of GUI Vim window
getwinvar({nr}, {varname} [, {def}])
@@ -3593,6 +3596,55 @@ get({func}, {what})
'dict' The dictionary
'args' The list with arguments
+ *getbufinfo()*
+getbufinfo([{expr}])
+getbufinfo([{dict}])
+ Get information about buffers as a List of Dictionaries.
+
+ Without an argument information about all the buffers is
+ returned.
+
+ When the argument is a Dictionary only the buffers matching
+ the specified criteria are returned. The following keys can
+ be specified in {dict}:
+ buflisted include only listed buffers.
+ bufloaded include only loaded buffers.
+
+ Otherwise, {expr} specifies a particular buffer to return
+ information for. For the use of {expr}, see |bufname()|
+ above. If the buffer is found the returned List has one item.
+ Otherwise the result is an empty list.
+
+ Each returned List item is a dictionary with the following
+ entries:
+ changed TRUE if the buffer is modified.
+ changedtick number of changes made to the buffer.
+ hidden TRUE if the buffer is hidden.
+ listed TRUE if the buffer is listed.
+ lnum current line number in buffer.
+ loaded TRUE if the buffer is loaded.
+ name full path to the file in the buffer.
+ nr buffer number.
+ options dictionary of buffer local options.
+ signs list of signs placed in the buffer.
+ Each list item is a dictionary with
+ the following fields:
+ id sign identifier
+ lnum line number
+ name sign name
+ variables dictionary of buffer local variables.
+ windows list of window IDs with this buffer
+
+ Examples: >
+ for buf in getbufinfo()
+ echo buf.name
+ endfor
+ for buf in getbufinfo({'buflisted':1})
+ if buf.options.filetype == 'java'
+ ....
+ endif
+ endfor
+<
*getbufline()*
getbufline({expr}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {end}
@@ -4050,6 +4102,18 @@ getregtype([{regname}]) *getregtype()*
<CTRL-V> is one character with value 0x16.
If {regname} is not specified, |v:register| is used.
+gettabinfo([{arg}]) *gettabinfo()*
+ If {arg} is not specified, then information about all the tab
+ pages is returned as a List. Each List item is a Dictionary.
+ Otherwise, {arg} specifies the tab page number and information
+ about that one is returned. If the tab page does not exist an
+ empty List is returned.
+
+ Each List item is a Dictionary with the following entries:
+ nr tab page number.
+ windows List of window IDs in the tag page.
+ variables dictionary of tabpage local variables.
+
gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
Get the value of a tab-local variable {varname} in tab page
{tabnr}. |t:var|
@@ -4091,6 +4155,26 @@ getwinposy() The result is a Number, which is the Y coordinate in pixels of
the top of the GUI Vim window. The result will be -1 if the
information is not available.
+getwininfo([{winid}]) *getwininfo()*
+ Returns information about windows as a List with Dictionaries.
+
+ If {winid} is given Information about the window with that ID
+ is returned. If the window does not exist the result is an
+ empty list.
+
+ Without an information about all the windows in all the tab
+ pages is returned.
+
+ Each List item is a Dictionary with the following entries:
+ nr window number.
+ tpnr tab page number.
+ winid window ID.
+ height window height.
+ width window width.
+ bufnum number of buffer in the window.
+ options dictionary of window local options.
+ variables dictionary of window local variables.
+
getwinvar({winnr}, {varname} [, {def}]) *getwinvar()*
Like |gettabwinvar()| for the current tabpage.
Examples: >
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 2896611274..49fcdf0bb7 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt* For Vim version 7.4. Last change: 2016 Apr 12
+*usr_41.txt* For Vim version 7.4. Last change: 2016 Aug 07
VIM USER MANUAL - by Bram Moolenaar
@@ -789,6 +789,9 @@ Buffers, windows and the argument list:
bufwinnr() get the window number of a specific buffer
winbufnr() get the buffer number of a specific window
getbufline() get a list of lines from the specified buffer
+ getbufinfo() get a list with buffer information
+ gettabinfo() get a list with tab page information
+ getwininfo() get a list with window information
Command line: *command-line-functions*
getcmdline() get the current command line
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;