From 00466410701802214aba5c95f1cbb2e5086a37f5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 12:06:10 -0500 Subject: 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 --- src/nvim/eval.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) (limited to 'src/nvim/eval.c') 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 */ -- cgit From 4453aa0d29d7a4e488a4c1799c9d33bcbde432eb Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 13:41:01 -0500 Subject: vim-patch:7.4.2215 Problem: It's not easy to find out if a window is a quickfix or location list window. Solution: Add "loclist" and "quickfix" entries to the dict returnec by getwininfo(). (Yegappan Lakshmanan) https://github.com/vim/vim/commit/386600f0cbcb8add099c723cf84634f46df2f788 --- src/nvim/eval.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 91f7233a21..a59bfca2a5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10905,6 +10905,11 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) dict_add_nr_str(dict, "width", wp->w_width, NULL); dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL); + dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL); + dict_add_nr_str(dict, "loclist", + (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), + NULL); + // Copy window variables dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); if (vars != NULL) { -- cgit From c4c894b2fada371c424e55d26174110b9069b5f8 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:46:11 -0500 Subject: vim-patch:7.4.2226 Problem: The field names used by getbufinfo(), gettabinfo() and getwininfo() are not consistent. Solution: Use bufnr, winnr and tabnr. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/339288377072f66ec88e21903e75a82d23ffbf4f --- src/nvim/eval.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a59bfca2a5..6dee5ed336 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9868,7 +9868,7 @@ 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, "bufnr", 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); @@ -10798,7 +10798,7 @@ 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); + dict_add_nr_str(dict, "tabnr", tp_idx, NULL); list_T *l = list_alloc(); FOR_ALL_WINDOWS_IN_TAB(wp, tp) { @@ -10898,12 +10898,12 @@ 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, "tabnr", tpnr, NULL); + dict_add_nr_str(dict, "winnr", 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); + dict_add_nr_str(dict, "bufnr", wp->w_buffer->b_fnum, NULL); dict_add_nr_str(dict, "quickfix", bt_quickfix(wp->w_buffer), NULL); dict_add_nr_str(dict, "loclist", -- cgit From 03ed7e1ebaf7f0934b176c71949a77a3fe2291fb Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 15 Nov 2016 16:53:07 -0500 Subject: vim-patch:7.4.2272 Problem: getbufinfo(), getwininfo() and gettabinfo() are inefficient. Solution: Instead of making a copy of the variables dictionary, use a reference. https://github.com/vim/vim/commit/9f8187c335b4fb07be9095dfdd0fc52670ba3c3f --- src/nvim/eval.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6dee5ed336..59d1132c79 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9880,11 +9880,8 @@ static dict_T *get_buffer_info(buf_T *buf) 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); - } + // Get a reference to buffer variables + dict_add_dict(dict, "variables", buf->b_vars); // Copy buffer options dict_T *opts = get_winbuf_options(true); @@ -10806,11 +10803,8 @@ static dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) } 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); - } + // Make a reference to tabpage variables + dict_add_dict(dict, "variables", tp->tp_vars); return dict; } @@ -10910,11 +10904,8 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL); - // Copy window variables - dict_T *vars = dict_copy(NULL, wp->w_vars, true, 0); - if (vars != NULL) { - dict_add_dict(dict, "variables", vars); - } + // Make a reference to window variables + dict_add_dict(dict, "variables", wp->w_vars); // Copy window options dict_T *opts = get_winbuf_options(false); -- cgit From fe03ce23bfc5c45545b53d4959aeeb27d82753ed Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 23:01:53 -0500 Subject: vim-patch:7.4.2273 Problem: getwininfo() and getbufinfo() are inefficient. Solution: Do not make a copy of all window/buffer-local options. Make it possible to get them with gettabwinvar() or getbufvar(). https://github.com/vim/vim/commit/3056735ae8a366aa7fcb51872520895251858637 --- src/nvim/eval.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 59d1132c79..2b325bbf20 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9883,12 +9883,6 @@ static dict_T *get_buffer_info(buf_T *buf) // Get a reference to buffer variables dict_add_dict(dict, "variables", buf->b_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) { @@ -10056,8 +10050,20 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) curbuf = buf; if (*varname == '&') { /* buffer-local-option */ - if (get_option_tv(&varname, rettv, TRUE) == OK) + if (varname[1] == NUL) { + // get all buffer-local options in a dict + dict_T *opts = get_winbuf_options(true); + + if (opts != NULL) { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = opts; + opts->dv_refcount++; + done = true; + } + } else if (get_option_tv(&varname, rettv, true) == OK) { + // buffer-local-option done = TRUE; + } } else if (STRCMP(varname, "changedtick") == 0) { rettv->v_type = VAR_NUMBER; rettv->vval.v_number = curbuf->b_changedtick; @@ -10904,15 +10910,9 @@ static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL), NULL); - // Make a reference to window variables + // Add a reference to window variables dict_add_dict(dict, "variables", wp->w_vars); - // Copy window options - dict_T *opts = get_winbuf_options(false); - if (opts != NULL) { - dict_add_dict(dict, "options", opts); - } - return dict; } @@ -11072,8 +11072,19 @@ getwinvar ( bool need_switch_win = tp != curtab || win != curwin; if (!need_switch_win || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) { - if (*varname == '&') { // window-local-option - if (get_option_tv(&varname, rettv, 1) == OK) { + if (*varname == '&') { + if (varname[1] == NUL) { + // get all window-local options in a dict + dict_T *opts = get_winbuf_options(false); + + if (opts != NULL) { + rettv->v_type = VAR_DICT; + rettv->vval.v_dict = opts; + opts->dv_refcount++; + done = true; + } + } else if (get_option_tv(&varname, rettv, 1) == OK) { + // window-local-option done = true; } } else { -- cgit From de025d6dd05de41a1226721420ffa51018e07fed Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 23:22:50 -0500 Subject: vim-patch:7.4.2277 Problem: Memory leak in getbufinfo() when there is a sign. (Dominique Pelle) Solution: Remove extra vim_strsave(). https://github.com/vim/vim/commit/6a402edbeb693113f05d9319cd20ec382a0a1a20 --- src/nvim/eval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2b325bbf20..2016e0bb45 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9857,7 +9857,7 @@ static void get_buffer_signs(buf_T *buf, list_T *l) 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))); + dict_add_nr_str(d, "name", 0L, sign_typenr2name(sign->typenr)); list_append_dict(l, d); } -- cgit From 46235a30edc4ee09fdbd4f489865982bafde247d Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 27 Dec 2016 23:26:51 -0500 Subject: lint --- src/nvim/eval.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval.c') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 2016e0bb45..32e1991742 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10049,7 +10049,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) save_curbuf = curbuf; curbuf = buf; - if (*varname == '&') { /* buffer-local-option */ + if (*varname == '&') { // buffer-local-option if (varname[1] == NUL) { // get all buffer-local options in a dict dict_T *opts = get_winbuf_options(true); @@ -10062,7 +10062,7 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } else if (get_option_tv(&varname, rettv, true) == OK) { // buffer-local-option - done = TRUE; + done = true; } } else if (STRCMP(varname, "changedtick") == 0) { rettv->v_type = VAR_NUMBER; @@ -10825,8 +10825,9 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) 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) + if (tparg == NULL) { return; + } } // Get information about a specific tab page or all tab pages @@ -10894,7 +10895,7 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } /// Returns information about a window as a dictionary. -static dict_T *get_win_info(win_T *wp, short tpnr, short winnr) +static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) { dict_T *dict = dict_alloc(); @@ -10932,10 +10933,10 @@ static void f_getwininfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) // Collect information about either all the windows across all the tab // pages or one particular window. - short tabnr = 0; + int16_t tabnr = 0; FOR_ALL_TABS(tp) { tabnr++; - short winnr = 0; + int16_t winnr = 0; FOR_ALL_WINDOWS_IN_TAB(wp, tp) { if (wparg != NULL && wp != wparg) { continue; -- cgit