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)

b5ae48e9ff
This commit is contained in:
James McCoy 2016-11-15 12:06:10 -05:00
parent 99a8cd3be0
commit 0046641070
No known key found for this signature in database
GPG Key ID: DFE691AE331BA3DB
9 changed files with 425 additions and 2 deletions

View File

@ -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({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def} get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
get({func}, {what}) any get property of funcref/partial {func} get({func}, {what}) any get property of funcref/partial {func}
getbufinfo( [{expr}]) List information about buffers
getbufline({expr}, {lnum} [, {end}]) getbufline({expr}, {lnum} [, {end}])
List lines {lnum} to {end} of buffer {expr} List lines {lnum} to {end} of buffer {expr}
getbufvar({expr}, {varname} [, {def}]) getbufvar({expr}, {varname} [, {def}])
@ -1986,10 +1987,12 @@ getqflist() List list of quickfix items
getreg([{regname} [, 1 [, {list}]]]) getreg([{regname} [, 1 [, {list}]]])
String or List contents of register String or List contents of register
getregtype([{regname}]) String type of register getregtype([{regname}]) String type of register
gettabinfo( [{expr}]) List list of tab pages
gettabvar({nr}, {varname} [, {def}]) gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def} any variable {varname} in tab {nr} or {def}
gettabwinvar({tabnr}, {winnr}, {name} [, {def}]) gettabwinvar({tabnr}, {winnr}, {name} [, {def}])
any {name} in {winnr} in tab page {tabnr} any {name} in {winnr} in tab page {tabnr}
getwininfo( [{winid}]) List list of windows
getwinposx() Number X coord in pixels of GUI Vim window getwinposx() Number X coord in pixels of GUI Vim window
getwinposy() Number Y coord in pixels of GUI Vim window getwinposy() Number Y coord in pixels of GUI Vim window
getwinvar({nr}, {varname} [, {def}]) getwinvar({nr}, {varname} [, {def}])
@ -3593,6 +3596,55 @@ get({func}, {what})
'dict' The dictionary 'dict' The dictionary
'args' The list with arguments '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()*
getbufline({expr}, {lnum} [, {end}]) getbufline({expr}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {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. <CTRL-V> is one character with value 0x16.
If {regname} is not specified, |v:register| is used. 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()* gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
Get the value of a tab-local variable {varname} in tab page Get the value of a tab-local variable {varname} in tab page
{tabnr}. |t:var| {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 the top of the GUI Vim window. The result will be -1 if the
information is not available. 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()* getwinvar({winnr}, {varname} [, {def}]) *getwinvar()*
Like |gettabwinvar()| for the current tabpage. Like |gettabwinvar()| for the current tabpage.
Examples: > Examples: >

View File

@ -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 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 bufwinnr() get the window number of a specific buffer
winbufnr() get the buffer number of a specific window winbufnr() get the buffer number of a specific window
getbufline() get a list of lines from the specified buffer 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* Command line: *command-line-functions*
getcmdline() get the current command line getcmdline() get the current command line

View File

@ -6611,6 +6611,23 @@ int dict_add_list(dict_T *d, char *key, list_T *list)
return OK; 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. /// Set all existing keys in "dict" as read-only.
/// ///
/// This does not protect against adding new keys to the Dictionary. /// 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); 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". * 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); 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 * "gettabvar()" function
*/ */
@ -10701,6 +10893,70 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
getwinvar(argvars, rettv, 1); 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 * "getwinposx()" function
*/ */

View File

@ -106,6 +106,7 @@ return {
['function']={args={1, 3}}, ['function']={args={1, 3}},
garbagecollect={args={0, 1}}, garbagecollect={args={0, 1}},
get={args={2, 3}}, get={args={2, 3}},
getbufinfo={args={0, 1}},
getbufline={args={2, 3}}, getbufline={args={2, 3}},
getbufvar={args={2, 3}}, getbufvar={args={2, 3}},
getchar={args={0, 1}}, getchar={args={0, 1}},
@ -131,8 +132,10 @@ return {
getqflist={}, getqflist={},
getreg={args={0, 3}}, getreg={args={0, 3}},
getregtype={args={0, 1}}, getregtype={args={0, 1}},
gettabinfo={args={0, 1}},
gettabvar={args={2, 3}}, gettabvar={args={2, 3}},
gettabwinvar={args={3, 4}}, gettabwinvar={args={3, 4}},
getwininfo={args={0, 1}},
getwinposx={}, getwinposx={},
getwinposy={}, getwinposy={},
getwinvar={args={2, 3}}, getwinvar={args={2, 3}},

View File

@ -6923,3 +6923,28 @@ bool signcolumn_on(win_T *wp)
} }
return wp->w_buffer->b_signlist != NULL; 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;
}

View File

@ -30,6 +30,7 @@ SCRIPTS := \
# Tests using runtest.vim.vim. # Tests using runtest.vim.vim.
# Keep test_alot*.res as the last one, sort the others. # Keep test_alot*.res as the last one, sort the others.
NEW_TESTS = \ NEW_TESTS = \
test_bufwintabinfo.res \
test_cmdline.res \ test_cmdline.res \
test_cscope.res \ test_cscope.res \
test_diffmode.res \ test_diffmode.res \

View File

@ -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

View File

@ -236,7 +236,7 @@ static int included_patches[] = {
// 2207 NA // 2207 NA
// 2206 NA // 2206 NA
2205, 2205,
// 2204, 2204,
// 2203 NA // 2203 NA
// 2202 NA // 2202 NA
2201, 2201,

View File

@ -5797,6 +5797,19 @@ void win_id2tabwin(typval_T *argvars, list_T *list)
list_append_number(list, winnr); 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) int win_id2win(typval_T *argvars)
{ {
win_T *wp; win_T *wp;