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
9 changed files with 425 additions and 2 deletions

View File

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

View File

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

View File

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

View File

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

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
// 2206 NA
2205,
// 2204,
2204,
// 2203 NA
// 2202 NA
2201,

View File

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