0
0
mirror of https://github.com/vim/vim.git synced 2025-07-24 10:45:12 -04:00

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)
This commit is contained in:
Bram Moolenaar 2016-08-12 22:23:25 +02:00
parent ebcccad573
commit b5ae48e9ff
13 changed files with 528 additions and 1 deletions

View File

@ -2081,6 +2081,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}])
@ -2110,10 +2111,12 @@ getqflist([{what}]) 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}])
@ -3976,6 +3979,55 @@ get({func}, {what})
'dict' The dictionary
'args' The list with arguments
*getbufinfo()*
getbufinfo([{expr}])
getbufinfo([{dict}])
Get information aobut 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}
@ -4461,6 +4513,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|
@ -4502,6 +4566,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: >

View File

@ -1,4 +1,4 @@
*usr_41.txt* For Vim version 7.4. Last change: 2016 Jul 24
*usr_41.txt* For Vim version 7.4. Last change: 2016 Aug 07
VIM USER MANUAL - by Bram Moolenaar
@ -803,6 +803,9 @@ Buffers, windows and the argument list:
win_gotoid() go to window with ID
win_id2tabwin() get tab and window nr from window ID
win_id2win() get window nr from window ID
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
@ -957,7 +960,10 @@ Jobs: *job-functions*
Timers: *timer-functions*
timer_start() create a timer
timer_pause() pause or unpause a timer
timer_stop() stop a timer
timer_stopall() stop all timers
timer_info() get information about timers
Various: *various-functions*
mode() get current editing mode

View File

@ -2056,6 +2056,7 @@ test_arglist \
test_autochdir \
test_autocmd \
test_backspace_opt \
test_bufwintabinfo \
test_cdo \
test_channel \
test_cmdline \

View File

@ -366,6 +366,30 @@ 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;
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.
*/

View File

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

View File

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

View File

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

View File

@ -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 : */

View File

@ -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 : */

View File

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

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

@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2204,
/**/
2203,
/**/

View File

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