mirror of
https://github.com/neovim/neovim.git
synced 2025-10-01 07:28:34 +00:00
Merge pull request #5613 from jamessan/vim-7.4.2183
vim-patch:7.4.2183,7.4.2194,7.4.2201,7.4.2204,0952131,7.4.2215,7.4.2225,7.4.2226,7.4.2272,7.4.2273,7.4.2277,7.4.2294
This commit is contained in:
@@ -237,6 +237,8 @@ typedef struct {
|
||||
# define w_p_crb w_onebuf_opt.wo_crb /* 'cursorbind' */
|
||||
int wo_crb_save; /* 'cursorbind' state saved for diff mode*/
|
||||
# define w_p_crb_save w_onebuf_opt.wo_crb_save
|
||||
char_u *wo_scl;
|
||||
# define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn'
|
||||
|
||||
int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */
|
||||
# define w_p_scriptID w_onebuf_opt.wo_scriptID
|
||||
|
@@ -5708,7 +5708,7 @@ comp_textwidth (
|
||||
textwidth -= 1;
|
||||
textwidth -= curwin->w_p_fdc;
|
||||
|
||||
if (curwin->w_buffer->b_signlist != NULL) {
|
||||
if (signcolumn_on(curwin)) {
|
||||
textwidth -= 1;
|
||||
}
|
||||
|
||||
|
274
src/nvim/eval.c
274
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,118 @@ 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, 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, "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);
|
||||
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);
|
||||
|
||||
// Get a reference to buffer variables
|
||||
dict_add_dict(dict, "variables", buf->b_vars);
|
||||
|
||||
// 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".
|
||||
@@ -9920,9 +10049,21 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
save_curbuf = curbuf;
|
||||
curbuf = buf;
|
||||
|
||||
if (*varname == '&') { /* buffer-local-option */
|
||||
if (get_option_tv(&varname, rettv, TRUE) == OK)
|
||||
done = TRUE;
|
||||
if (*varname == '&') { // buffer-local-option
|
||||
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;
|
||||
@@ -10654,6 +10795,58 @@ 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, "tabnr", 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);
|
||||
|
||||
// Make a reference to tabpage variables
|
||||
dict_add_dict(dict, "variables", tp->tp_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 +10894,66 @@ 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, int16_t tpnr, int16_t winnr)
|
||||
{
|
||||
dict_T *dict = dict_alloc();
|
||||
|
||||
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, "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",
|
||||
(bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL),
|
||||
NULL);
|
||||
|
||||
// Add a reference to window variables
|
||||
dict_add_dict(dict, "variables", wp->w_vars);
|
||||
|
||||
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.
|
||||
int16_t tabnr = 0;
|
||||
FOR_ALL_TABS(tp) {
|
||||
tabnr++;
|
||||
int16_t 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
|
||||
*/
|
||||
@@ -10820,8 +11073,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 {
|
||||
|
@@ -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}},
|
||||
|
@@ -5351,385 +5351,330 @@ static int sign_cmd_idx(
|
||||
*/
|
||||
void ex_sign(exarg_T *eap)
|
||||
{
|
||||
char_u *arg = eap->arg;
|
||||
char_u *p;
|
||||
int idx;
|
||||
sign_T *sp;
|
||||
sign_T *sp_prev;
|
||||
char_u *arg = eap->arg;
|
||||
char_u *p;
|
||||
int idx;
|
||||
sign_T *sp;
|
||||
sign_T *sp_prev;
|
||||
|
||||
/* Parse the subcommand. */
|
||||
p = skiptowhite(arg);
|
||||
idx = sign_cmd_idx(arg, p);
|
||||
if (idx == SIGNCMD_LAST)
|
||||
{
|
||||
EMSG2(_("E160: Unknown sign command: %s"), arg);
|
||||
return;
|
||||
// Parse the subcommand.
|
||||
p = skiptowhite(arg);
|
||||
idx = sign_cmd_idx(arg, p);
|
||||
if (idx == SIGNCMD_LAST) {
|
||||
EMSG2(_("E160: Unknown sign command: %s"), arg);
|
||||
return;
|
||||
}
|
||||
arg = skipwhite(p);
|
||||
|
||||
if (idx <= SIGNCMD_LIST) {
|
||||
// Define, undefine or list signs.
|
||||
if (idx == SIGNCMD_LIST && *arg == NUL) {
|
||||
// ":sign list": list all defined signs
|
||||
for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next) {
|
||||
sign_list_defined(sp);
|
||||
}
|
||||
} else if (*arg == NUL) {
|
||||
EMSG(_("E156: Missing sign name"));
|
||||
} else {
|
||||
// Isolate the sign name. If it's a number skip leading zeroes,
|
||||
// so that "099" and "99" are the same sign. But keep "0".
|
||||
p = skiptowhite(arg);
|
||||
if (*p != NUL) {
|
||||
*p++ = NUL;
|
||||
}
|
||||
while (arg[0] == '0' && arg[1] != NUL) {
|
||||
arg++;
|
||||
}
|
||||
|
||||
sp_prev = NULL;
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
|
||||
if (STRCMP(sp->sn_name, arg) == 0) {
|
||||
break;
|
||||
}
|
||||
sp_prev = sp;
|
||||
}
|
||||
if (idx == SIGNCMD_DEFINE) {
|
||||
// ":sign define {name} ...": define a sign
|
||||
if (sp == NULL) {
|
||||
sign_T *lp;
|
||||
int start = next_sign_typenr;
|
||||
|
||||
// Allocate a new sign.
|
||||
sp = xcalloc(1, sizeof(sign_T));
|
||||
|
||||
// Check that next_sign_typenr is not already being used.
|
||||
// This only happens after wrapping around. Hopefully
|
||||
// another one got deleted and we can use its number.
|
||||
for (lp = first_sign; lp != NULL; ) {
|
||||
if (lp->sn_typenr == next_sign_typenr) {
|
||||
next_sign_typenr++;
|
||||
if (next_sign_typenr == MAX_TYPENR) {
|
||||
next_sign_typenr = 1;
|
||||
}
|
||||
if (next_sign_typenr == start) {
|
||||
xfree(sp);
|
||||
EMSG(_("E612: Too many signs defined"));
|
||||
return;
|
||||
}
|
||||
lp = first_sign; // start all over
|
||||
continue;
|
||||
}
|
||||
lp = lp->sn_next;
|
||||
}
|
||||
|
||||
sp->sn_typenr = next_sign_typenr;
|
||||
if (++next_sign_typenr == MAX_TYPENR) {
|
||||
next_sign_typenr = 1; // wrap around
|
||||
}
|
||||
|
||||
sp->sn_name = vim_strsave(arg);
|
||||
|
||||
// add the new sign to the list of signs
|
||||
if (sp_prev == NULL) {
|
||||
first_sign = sp;
|
||||
} else {
|
||||
sp_prev->sn_next = sp;
|
||||
}
|
||||
}
|
||||
|
||||
// set values for a defined sign.
|
||||
for (;;) {
|
||||
arg = skipwhite(p);
|
||||
if (*arg == NUL) {
|
||||
break;
|
||||
}
|
||||
p = skiptowhite_esc(arg);
|
||||
if (STRNCMP(arg, "icon=", 5) == 0) {
|
||||
arg += 5;
|
||||
xfree(sp->sn_icon);
|
||||
sp->sn_icon = vim_strnsave(arg, (int)(p - arg));
|
||||
backslash_halve(sp->sn_icon);
|
||||
} else if (STRNCMP(arg, "text=", 5) == 0) {
|
||||
char_u *s;
|
||||
int cells;
|
||||
int len;
|
||||
|
||||
arg += 5;
|
||||
|
||||
// Count cells and check for non-printable chars
|
||||
cells = 0;
|
||||
for (s = arg; s < p; s += (*mb_ptr2len)(s)) {
|
||||
if (!vim_isprintc((*mb_ptr2char)(s))) {
|
||||
break;
|
||||
}
|
||||
cells += (*mb_ptr2cells)(s);
|
||||
}
|
||||
// Currently must be one or two display cells
|
||||
if (s != p || cells < 1 || cells > 2) {
|
||||
*p = NUL;
|
||||
EMSG2(_("E239: Invalid sign text: %s"), arg);
|
||||
return;
|
||||
}
|
||||
|
||||
xfree(sp->sn_text);
|
||||
// Allocate one byte more if we need to pad up
|
||||
// with a space.
|
||||
len = (int)(p - arg + ((cells == 1) ? 1 : 0));
|
||||
sp->sn_text = vim_strnsave(arg, len);
|
||||
|
||||
if (cells == 1) {
|
||||
STRCPY(sp->sn_text + len - 1, " ");
|
||||
}
|
||||
} else if (STRNCMP(arg, "linehl=", 7) == 0) {
|
||||
arg += 7;
|
||||
sp->sn_line_hl = syn_check_group(arg, (int)(p - arg));
|
||||
} else if (STRNCMP(arg, "texthl=", 7) == 0) {
|
||||
arg += 7;
|
||||
sp->sn_text_hl = syn_check_group(arg, (int)(p - arg));
|
||||
} else {
|
||||
EMSG2(_(e_invarg2), arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (sp == NULL) {
|
||||
EMSG2(_("E155: Unknown sign: %s"), arg);
|
||||
} else if (idx == SIGNCMD_LIST) {
|
||||
// ":sign list {name}"
|
||||
sign_list_defined(sp);
|
||||
} else {
|
||||
// ":sign undefine {name}"
|
||||
sign_undefine(sp, sp_prev);
|
||||
}
|
||||
}
|
||||
arg = skipwhite(p);
|
||||
} else {
|
||||
int id = -1;
|
||||
linenr_T lnum = -1;
|
||||
char_u *sign_name = NULL;
|
||||
char_u *arg1;
|
||||
|
||||
if (idx <= SIGNCMD_LIST)
|
||||
{
|
||||
/*
|
||||
* Define, undefine or list signs.
|
||||
*/
|
||||
if (idx == SIGNCMD_LIST && *arg == NUL)
|
||||
{
|
||||
/* ":sign list": list all defined signs */
|
||||
for (sp = first_sign; sp != NULL && !got_int; sp = sp->sn_next)
|
||||
sign_list_defined(sp);
|
||||
}
|
||||
else if (*arg == NUL)
|
||||
EMSG(_("E156: Missing sign name"));
|
||||
else
|
||||
{
|
||||
/* Isolate the sign name. If it's a number skip leading zeroes,
|
||||
* so that "099" and "99" are the same sign. But keep "0". */
|
||||
p = skiptowhite(arg);
|
||||
if (*p != NUL)
|
||||
*p++ = NUL;
|
||||
while (arg[0] == '0' && arg[1] != NUL)
|
||||
++arg;
|
||||
|
||||
sp_prev = NULL;
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next)
|
||||
{
|
||||
if (STRCMP(sp->sn_name, arg) == 0)
|
||||
break;
|
||||
sp_prev = sp;
|
||||
}
|
||||
if (idx == SIGNCMD_DEFINE)
|
||||
{
|
||||
/* ":sign define {name} ...": define a sign */
|
||||
if (sp == NULL)
|
||||
{
|
||||
sign_T *lp;
|
||||
int start = next_sign_typenr;
|
||||
|
||||
/* Allocate a new sign. */
|
||||
sp = xcalloc(1, sizeof(sign_T));
|
||||
|
||||
/* Check that next_sign_typenr is not already being used.
|
||||
* This only happens after wrapping around. Hopefully
|
||||
* another one got deleted and we can use its number. */
|
||||
for (lp = first_sign; lp != NULL; )
|
||||
{
|
||||
if (lp->sn_typenr == next_sign_typenr)
|
||||
{
|
||||
++next_sign_typenr;
|
||||
if (next_sign_typenr == MAX_TYPENR)
|
||||
next_sign_typenr = 1;
|
||||
if (next_sign_typenr == start)
|
||||
{
|
||||
xfree(sp);
|
||||
EMSG(_("E612: Too many signs defined"));
|
||||
return;
|
||||
}
|
||||
lp = first_sign; /* start all over */
|
||||
continue;
|
||||
}
|
||||
lp = lp->sn_next;
|
||||
}
|
||||
|
||||
sp->sn_typenr = next_sign_typenr;
|
||||
if (++next_sign_typenr == MAX_TYPENR)
|
||||
next_sign_typenr = 1; /* wrap around */
|
||||
|
||||
sp->sn_name = vim_strsave(arg);
|
||||
|
||||
/* add the new sign to the list of signs */
|
||||
if (sp_prev == NULL)
|
||||
first_sign = sp;
|
||||
else
|
||||
sp_prev->sn_next = sp;
|
||||
}
|
||||
|
||||
/* set values for a defined sign. */
|
||||
for (;;)
|
||||
{
|
||||
arg = skipwhite(p);
|
||||
if (*arg == NUL)
|
||||
break;
|
||||
p = skiptowhite_esc(arg);
|
||||
if (STRNCMP(arg, "icon=", 5) == 0)
|
||||
{
|
||||
arg += 5;
|
||||
xfree(sp->sn_icon);
|
||||
sp->sn_icon = vim_strnsave(arg, (int)(p - arg));
|
||||
backslash_halve(sp->sn_icon);
|
||||
}
|
||||
else if (STRNCMP(arg, "text=", 5) == 0)
|
||||
{
|
||||
char_u *s;
|
||||
int cells;
|
||||
int len;
|
||||
|
||||
arg += 5;
|
||||
|
||||
/* Count cells and check for non-printable chars */
|
||||
if (has_mbyte)
|
||||
{
|
||||
cells = 0;
|
||||
for (s = arg; s < p; s += (*mb_ptr2len)(s))
|
||||
{
|
||||
if (!vim_isprintc((*mb_ptr2char)(s)))
|
||||
break;
|
||||
cells += (*mb_ptr2cells)(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
for (s = arg; s < p; ++s)
|
||||
if (!vim_isprintc(*s))
|
||||
break;
|
||||
cells = (int)(s - arg);
|
||||
}
|
||||
/* Currently must be one or two display cells */
|
||||
if (s != p || cells < 1 || cells > 2)
|
||||
{
|
||||
*p = NUL;
|
||||
EMSG2(_("E239: Invalid sign text: %s"), arg);
|
||||
return;
|
||||
}
|
||||
|
||||
xfree(sp->sn_text);
|
||||
/* Allocate one byte more if we need to pad up
|
||||
* with a space. */
|
||||
len = (int)(p - arg + ((cells == 1) ? 1 : 0));
|
||||
sp->sn_text = vim_strnsave(arg, len);
|
||||
|
||||
if (cells == 1)
|
||||
STRCPY(sp->sn_text + len - 1, " ");
|
||||
}
|
||||
else if (STRNCMP(arg, "linehl=", 7) == 0)
|
||||
{
|
||||
arg += 7;
|
||||
sp->sn_line_hl = syn_check_group(arg, (int)(p - arg));
|
||||
}
|
||||
else if (STRNCMP(arg, "texthl=", 7) == 0)
|
||||
{
|
||||
arg += 7;
|
||||
sp->sn_text_hl = syn_check_group(arg, (int)(p - arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
EMSG2(_(e_invarg2), arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sp == NULL)
|
||||
EMSG2(_("E155: Unknown sign: %s"), arg);
|
||||
else if (idx == SIGNCMD_LIST)
|
||||
/* ":sign list {name}" */
|
||||
sign_list_defined(sp);
|
||||
else
|
||||
/* ":sign undefine {name}" */
|
||||
sign_undefine(sp, sp_prev);
|
||||
}
|
||||
if (*arg == NUL) {
|
||||
if (idx == SIGNCMD_PLACE) {
|
||||
// ":sign place": list placed signs in all buffers
|
||||
sign_list_placed(NULL);
|
||||
} else if (idx == SIGNCMD_UNPLACE) {
|
||||
// ":sign unplace": remove placed sign at cursor
|
||||
id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum);
|
||||
if (id > 0) {
|
||||
buf_delsign(curwin->w_buffer, id);
|
||||
update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum);
|
||||
} else {
|
||||
EMSG(_("E159: Missing sign number"));
|
||||
}
|
||||
} else {
|
||||
EMSG(_(e_argreq));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int id = -1;
|
||||
linenr_T lnum = -1;
|
||||
char_u *sign_name = NULL;
|
||||
char_u *arg1;
|
||||
|
||||
if (*arg == NUL)
|
||||
{
|
||||
if (idx == SIGNCMD_PLACE)
|
||||
{
|
||||
/* ":sign place": list placed signs in all buffers */
|
||||
sign_list_placed(NULL);
|
||||
}
|
||||
else if (idx == SIGNCMD_UNPLACE)
|
||||
{
|
||||
/* ":sign unplace": remove placed sign at cursor */
|
||||
id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum);
|
||||
if (id > 0)
|
||||
{
|
||||
buf_delsign(curwin->w_buffer, id);
|
||||
update_debug_sign(curwin->w_buffer, curwin->w_cursor.lnum);
|
||||
}
|
||||
else
|
||||
EMSG(_("E159: Missing sign number"));
|
||||
}
|
||||
else
|
||||
EMSG(_(e_argreq));
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL)
|
||||
{
|
||||
/* ":sign unplace *": remove all placed signs */
|
||||
buf_delete_all_signs();
|
||||
return;
|
||||
}
|
||||
|
||||
/* first arg could be placed sign id */
|
||||
arg1 = arg;
|
||||
if (ascii_isdigit(*arg))
|
||||
{
|
||||
id = getdigits_int(&arg);
|
||||
if (!ascii_iswhite(*arg) && *arg != NUL)
|
||||
{
|
||||
id = -1;
|
||||
arg = arg1;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg = skipwhite(arg);
|
||||
if (idx == SIGNCMD_UNPLACE && *arg == NUL)
|
||||
{
|
||||
// ":sign unplace {id}": remove placed sign by number
|
||||
FOR_ALL_BUFFERS(buf) {
|
||||
if ((lnum = buf_delsign(buf, id)) != 0) {
|
||||
update_debug_sign(buf, lnum);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for line={lnum} name={name} and file={fname} or buffer={nr}.
|
||||
* Leave "arg" pointing to {fname}.
|
||||
*/
|
||||
|
||||
buf_T *buf = NULL;
|
||||
for (;;)
|
||||
{
|
||||
if (STRNCMP(arg, "line=", 5) == 0)
|
||||
{
|
||||
arg += 5;
|
||||
lnum = atoi((char *)arg);
|
||||
arg = skiptowhite(arg);
|
||||
}
|
||||
else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE)
|
||||
{
|
||||
if (id != -1)
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
id = -2;
|
||||
arg = skiptowhite(arg + 1);
|
||||
}
|
||||
else if (STRNCMP(arg, "name=", 5) == 0)
|
||||
{
|
||||
arg += 5;
|
||||
sign_name = arg;
|
||||
arg = skiptowhite(arg);
|
||||
if (*arg != NUL)
|
||||
*arg++ = NUL;
|
||||
while (sign_name[0] == '0' && sign_name[1] != NUL)
|
||||
++sign_name;
|
||||
}
|
||||
else if (STRNCMP(arg, "file=", 5) == 0)
|
||||
{
|
||||
arg += 5;
|
||||
buf = buflist_findname(arg);
|
||||
break;
|
||||
}
|
||||
else if (STRNCMP(arg, "buffer=", 7) == 0)
|
||||
{
|
||||
arg += 7;
|
||||
buf = buflist_findnr(getdigits_int(&arg));
|
||||
if (*skipwhite(arg) != NUL)
|
||||
EMSG(_(e_trailing));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
arg = skipwhite(arg);
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
{
|
||||
EMSG2(_("E158: Invalid buffer name: %s"), arg);
|
||||
}
|
||||
else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2))
|
||||
{
|
||||
if (lnum >= 0 || sign_name != NULL)
|
||||
EMSG(_(e_invarg));
|
||||
else
|
||||
/* ":sign place file={fname}": list placed signs in one file */
|
||||
sign_list_placed(buf);
|
||||
}
|
||||
else if (idx == SIGNCMD_JUMP)
|
||||
{
|
||||
/* ":sign jump {id} file={fname}" */
|
||||
if (lnum >= 0 || sign_name != NULL)
|
||||
EMSG(_(e_invarg));
|
||||
else if ((lnum = buf_findsign(buf, id)) > 0)
|
||||
{ /* goto a sign ... */
|
||||
if (buf_jump_open_win(buf) != NULL)
|
||||
{ /* ... in a current window */
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
check_cursor_lnum();
|
||||
beginline(BL_WHITE);
|
||||
}
|
||||
else
|
||||
{ // ... not currently in a window
|
||||
char *cmd = xmalloc(STRLEN(buf->b_fname) + 25);
|
||||
sprintf(cmd, "e +%" PRId64 " %s",
|
||||
(int64_t)lnum, buf->b_fname);
|
||||
do_cmdline_cmd(cmd);
|
||||
xfree(cmd);
|
||||
}
|
||||
|
||||
foldOpenCursor();
|
||||
}
|
||||
else
|
||||
EMSGN(_("E157: Invalid sign ID: %" PRId64), id);
|
||||
}
|
||||
else if (idx == SIGNCMD_UNPLACE)
|
||||
{
|
||||
if (lnum >= 0 || sign_name != NULL)
|
||||
EMSG(_(e_invarg));
|
||||
else if (id == -2)
|
||||
{
|
||||
/* ":sign unplace * file={fname}" */
|
||||
redraw_buf_later(buf, NOT_VALID);
|
||||
buf_delete_signs(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ":sign unplace {id} file={fname}" */
|
||||
lnum = buf_delsign(buf, id);
|
||||
update_debug_sign(buf, lnum);
|
||||
}
|
||||
}
|
||||
/* idx == SIGNCMD_PLACE */
|
||||
else if (sign_name != NULL)
|
||||
{
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next)
|
||||
if (STRCMP(sp->sn_name, sign_name) == 0)
|
||||
break;
|
||||
if (sp == NULL)
|
||||
{
|
||||
EMSG2(_("E155: Unknown sign: %s"), sign_name);
|
||||
return;
|
||||
}
|
||||
if (lnum > 0)
|
||||
/* ":sign place {id} line={lnum} name={name} file={fname}":
|
||||
* place a sign */
|
||||
buf_addsign(buf, id, lnum, sp->sn_typenr);
|
||||
else
|
||||
/* ":sign place {id} file={fname}": change sign type */
|
||||
lnum = buf_change_sign_type(buf, id, sp->sn_typenr);
|
||||
if (lnum > 0)
|
||||
update_debug_sign(buf, lnum);
|
||||
else
|
||||
EMSG2(_("E885: Not possible to change sign %s"), sign_name);
|
||||
}
|
||||
else
|
||||
EMSG(_(e_invarg));
|
||||
if (idx == SIGNCMD_UNPLACE && arg[0] == '*' && arg[1] == NUL) {
|
||||
// ":sign unplace *": remove all placed signs
|
||||
buf_delete_all_signs();
|
||||
return;
|
||||
}
|
||||
|
||||
// first arg could be placed sign id
|
||||
arg1 = arg;
|
||||
if (ascii_isdigit(*arg)) {
|
||||
id = getdigits_int(&arg);
|
||||
if (!ascii_iswhite(*arg) && *arg != NUL) {
|
||||
id = -1;
|
||||
arg = arg1;
|
||||
} else {
|
||||
arg = skipwhite(arg);
|
||||
if (idx == SIGNCMD_UNPLACE && *arg == NUL) {
|
||||
// ":sign unplace {id}": remove placed sign by number
|
||||
FOR_ALL_BUFFERS(buf) {
|
||||
if ((lnum = buf_delsign(buf, id)) != 0) {
|
||||
update_debug_sign(buf, lnum);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for line={lnum} name={name} and file={fname} or buffer={nr}.
|
||||
// Leave "arg" pointing to {fname}.
|
||||
|
||||
buf_T *buf = NULL;
|
||||
for (;;) {
|
||||
if (STRNCMP(arg, "line=", 5) == 0) {
|
||||
arg += 5;
|
||||
lnum = atoi((char *)arg);
|
||||
arg = skiptowhite(arg);
|
||||
} else if (STRNCMP(arg, "*", 1) == 0 && idx == SIGNCMD_UNPLACE) {
|
||||
if (id != -1) {
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
id = -2;
|
||||
arg = skiptowhite(arg + 1);
|
||||
} else if (STRNCMP(arg, "name=", 5) == 0) {
|
||||
arg += 5;
|
||||
sign_name = arg;
|
||||
arg = skiptowhite(arg);
|
||||
if (*arg != NUL) {
|
||||
*arg++ = NUL;
|
||||
}
|
||||
while (sign_name[0] == '0' && sign_name[1] != NUL) {
|
||||
sign_name++;
|
||||
}
|
||||
} else if (STRNCMP(arg, "file=", 5) == 0) {
|
||||
arg += 5;
|
||||
buf = buflist_findname(arg);
|
||||
break;
|
||||
} else if (STRNCMP(arg, "buffer=", 7) == 0) {
|
||||
arg += 7;
|
||||
buf = buflist_findnr(getdigits_int(&arg));
|
||||
if (*skipwhite(arg) != NUL) {
|
||||
EMSG(_(e_trailing));
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
arg = skipwhite(arg);
|
||||
}
|
||||
|
||||
if (buf == NULL) {
|
||||
EMSG2(_("E158: Invalid buffer name: %s"), arg);
|
||||
} else if (id <= 0 && !(idx == SIGNCMD_UNPLACE && id == -2)) {
|
||||
if (lnum >= 0 || sign_name != NULL) {
|
||||
EMSG(_(e_invarg));
|
||||
} else {
|
||||
// ":sign place file={fname}": list placed signs in one file
|
||||
sign_list_placed(buf);
|
||||
}
|
||||
} else if (idx == SIGNCMD_JUMP) {
|
||||
// ":sign jump {id} file={fname}"
|
||||
if (lnum >= 0 || sign_name != NULL) {
|
||||
EMSG(_(e_invarg));
|
||||
} else if ((lnum = buf_findsign(buf, id)) > 0) {
|
||||
// goto a sign ...
|
||||
if (buf_jump_open_win(buf) != NULL) {
|
||||
// ... in a current window
|
||||
curwin->w_cursor.lnum = lnum;
|
||||
check_cursor_lnum();
|
||||
beginline(BL_WHITE);
|
||||
} else {
|
||||
// ... not currently in a window
|
||||
if (buf->b_fname == NULL) {
|
||||
EMSG(_("E934: Cannot jump to a buffer that does not have a name"));
|
||||
return;
|
||||
}
|
||||
size_t cmdlen = STRLEN(buf->b_fname) + 24;
|
||||
char *cmd = xmallocz(cmdlen);
|
||||
snprintf(cmd, cmdlen, "e +%" PRId64 " %s",
|
||||
(int64_t)lnum, buf->b_fname);
|
||||
do_cmdline_cmd(cmd);
|
||||
xfree(cmd);
|
||||
}
|
||||
|
||||
foldOpenCursor();
|
||||
} else {
|
||||
EMSGN(_("E157: Invalid sign ID: %" PRId64), id);
|
||||
}
|
||||
} else if (idx == SIGNCMD_UNPLACE) {
|
||||
if (lnum >= 0 || sign_name != NULL) {
|
||||
EMSG(_(e_invarg));
|
||||
} else if (id == -2) {
|
||||
// ":sign unplace * file={fname}"
|
||||
redraw_buf_later(buf, NOT_VALID);
|
||||
buf_delete_signs(buf);
|
||||
} else {
|
||||
// ":sign unplace {id} file={fname}"
|
||||
lnum = buf_delsign(buf, id);
|
||||
update_debug_sign(buf, lnum);
|
||||
}
|
||||
} else if (sign_name != NULL) {
|
||||
// idx == SIGNCMD_PLACE
|
||||
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
|
||||
if (STRCMP(sp->sn_name, sign_name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sp == NULL) {
|
||||
EMSG2(_("E155: Unknown sign: %s"), sign_name);
|
||||
return;
|
||||
}
|
||||
if (lnum > 0) {
|
||||
// ":sign place {id} line={lnum} name={name} file={fname}":
|
||||
// place a sign
|
||||
buf_addsign(buf, id, lnum, sp->sn_typenr);
|
||||
} else {
|
||||
// ":sign place {id} file={fname}": change sign type
|
||||
lnum = buf_change_sign_type(buf, id, sp->sn_typenr);
|
||||
}
|
||||
if (lnum > 0) {
|
||||
update_debug_sign(buf, lnum);
|
||||
} else {
|
||||
EMSG2(_("E885: Not possible to change sign %s"), sign_name);
|
||||
}
|
||||
} else {
|
||||
EMSG(_(e_invarg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/memline.h"
|
||||
#include "nvim/misc1.h"
|
||||
#include "nvim/option.h"
|
||||
#include "nvim/popupmnu.h"
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/strings.h"
|
||||
@@ -669,8 +670,7 @@ int win_col_off(win_T *wp)
|
||||
return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
|
||||
+ (cmdwin_type == 0 || wp != curwin ? 0 : 1)
|
||||
+ (int)wp->w_p_fdc
|
||||
+ (wp->w_buffer->b_signlist != NULL ? 2 : 0)
|
||||
;
|
||||
+ (signcolumn_on(wp) ? 2 : 0);
|
||||
}
|
||||
|
||||
int curwin_col_off(void)
|
||||
|
@@ -289,6 +289,7 @@ static char *(p_fcl_values[]) = { "all", NULL };
|
||||
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
|
||||
"noinsert", "noselect", NULL };
|
||||
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
|
||||
static char *(p_scl_values[]) = { "yes", "no", "auto", NULL };
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "option.c.generated.h"
|
||||
@@ -3007,6 +3008,11 @@ did_set_string_option (
|
||||
} else {
|
||||
completeopt_was_set();
|
||||
}
|
||||
} else if (varp == &curwin->w_p_scl) {
|
||||
// 'signcolumn'
|
||||
if (check_opt_strings(*varp, p_scl_values, false) != OK) {
|
||||
errmsg = e_invarg;
|
||||
}
|
||||
}
|
||||
/* 'pastetoggle': translate key codes like in a mapping */
|
||||
else if (varp == &p_pt) {
|
||||
@@ -4782,7 +4788,6 @@ static int find_key_option(const char_u *arg)
|
||||
return find_key_option_len(arg, STRLEN(arg));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if 'all' == 0: show changed options
|
||||
* if 'all' == 1: show all normal options
|
||||
@@ -5428,6 +5433,7 @@ static char_u *get_varp(vimoption_T *p)
|
||||
case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
|
||||
case PV_WM: return (char_u *)&(curbuf->b_p_wm);
|
||||
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
|
||||
case PV_SCL: return (char_u *)&(curwin->w_p_scl);
|
||||
default: EMSG(_("E356: get_varp ERROR"));
|
||||
}
|
||||
/* always return a valid pointer to avoid a crash! */
|
||||
@@ -5505,7 +5511,8 @@ void copy_winopt(winopt_T *from, winopt_T *to)
|
||||
to->wo_fde = vim_strsave(from->wo_fde);
|
||||
to->wo_fdt = vim_strsave(from->wo_fdt);
|
||||
to->wo_fmr = vim_strsave(from->wo_fmr);
|
||||
check_winopt(to); /* don't want NULL pointers */
|
||||
to->wo_scl = vim_strsave(from->wo_scl);
|
||||
check_winopt(to); // don't want NULL pointers
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5528,6 +5535,7 @@ static void check_winopt(winopt_T *wop)
|
||||
check_string_option(&wop->wo_fde);
|
||||
check_string_option(&wop->wo_fdt);
|
||||
check_string_option(&wop->wo_fmr);
|
||||
check_string_option(&wop->wo_scl);
|
||||
check_string_option(&wop->wo_rlc);
|
||||
check_string_option(&wop->wo_stl);
|
||||
check_string_option(&wop->wo_cc);
|
||||
@@ -5546,6 +5554,7 @@ void clear_winopt(winopt_T *wop)
|
||||
clear_string_option(&wop->wo_fde);
|
||||
clear_string_option(&wop->wo_fdt);
|
||||
clear_string_option(&wop->wo_fmr);
|
||||
clear_string_option(&wop->wo_scl);
|
||||
clear_string_option(&wop->wo_rlc);
|
||||
clear_string_option(&wop->wo_stl);
|
||||
clear_string_option(&wop->wo_cc);
|
||||
@@ -6902,3 +6911,39 @@ int csh_like_shell(void)
|
||||
return strstr((char *)path_tail(p_sh), "csh") != NULL;
|
||||
}
|
||||
|
||||
/// Return true when window "wp" has a column to draw signs in.
|
||||
bool signcolumn_on(win_T *wp)
|
||||
{
|
||||
if (*wp->w_p_scl == 'n') {
|
||||
return false;
|
||||
}
|
||||
if (*wp->w_p_scl == 'y') {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@@ -799,7 +799,8 @@ enum {
|
||||
, WV_WFH
|
||||
, WV_WFW
|
||||
, WV_WRAP
|
||||
, WV_COUNT /* must be the last one */
|
||||
, WV_SCL
|
||||
, WV_COUNT // must be the last one
|
||||
};
|
||||
|
||||
/* Value for b_p_ul indicating the global value must be used. */
|
||||
|
@@ -2169,6 +2169,14 @@ return {
|
||||
varname='p_siso',
|
||||
defaults={if_true={vi=0}}
|
||||
},
|
||||
{
|
||||
full_name='signcolumn', abbreviation='scl',
|
||||
type='string', scope={'window'},
|
||||
vi_def=true,
|
||||
alloced=true,
|
||||
redraw={'current_window'},
|
||||
defaults={if_true={vi="auto"}}
|
||||
},
|
||||
{
|
||||
full_name='smartcase', abbreviation='scs',
|
||||
type='bool', scope={'global'},
|
||||
|
@@ -580,15 +580,6 @@ void update_debug_sign(buf_T *buf, linenr_T lnum)
|
||||
update_finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE when window "wp" has a column to draw signs in.
|
||||
*/
|
||||
static int draw_signcolumn(win_T *wp)
|
||||
{
|
||||
return (wp->w_buffer->b_signlist != NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Update a single window.
|
||||
*
|
||||
@@ -1603,7 +1594,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
|
||||
' ', ' ', hl_attr(HLF_FC));
|
||||
}
|
||||
|
||||
if (draw_signcolumn(wp)) {
|
||||
if (signcolumn_on(wp)) {
|
||||
int nn = n + 2;
|
||||
|
||||
/* draw the sign column left of the fold column */
|
||||
@@ -1644,8 +1635,7 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
|
||||
n = nn;
|
||||
}
|
||||
|
||||
if (draw_signcolumn(wp))
|
||||
{
|
||||
if (signcolumn_on(wp)) {
|
||||
int nn = n + 2;
|
||||
|
||||
/* draw the sign column after the fold column */
|
||||
@@ -1757,8 +1747,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
|
||||
* text */
|
||||
RL_MEMSET(col, hl_attr(HLF_FL), wp->w_width - col);
|
||||
|
||||
/* If signs are being displayed, add two spaces. */
|
||||
if (draw_signcolumn(wp)) {
|
||||
// If signs are being displayed, add two spaces.
|
||||
if (signcolumn_on(wp)) {
|
||||
len = wp->w_width - col;
|
||||
if (len > 0) {
|
||||
if (len > 2) {
|
||||
@@ -2706,7 +2696,7 @@ win_line (
|
||||
draw_state = WL_SIGN;
|
||||
/* Show the sign column when there are any signs in this
|
||||
* buffer or when using Netbeans. */
|
||||
if (draw_signcolumn(wp)) {
|
||||
if (signcolumn_on(wp)) {
|
||||
int text_sign;
|
||||
/* Draw two cells with the sign value or blank. */
|
||||
c_extra = ' ';
|
||||
|
@@ -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 \
|
||||
@@ -40,6 +41,7 @@ NEW_TESTS = \
|
||||
test_match.res \
|
||||
test_matchadd_conceal.res \
|
||||
test_quickfix.res \
|
||||
test_signs.res \
|
||||
test_syntax.res \
|
||||
test_usercommands.res \
|
||||
test_timers.res \
|
||||
|
@@ -86,6 +86,12 @@ function RunTheTest(test)
|
||||
if exists("*TearDown")
|
||||
call TearDown()
|
||||
endif
|
||||
|
||||
" Close any extra windows and make the current one not modified.
|
||||
while winnr('$') > 1
|
||||
bwipe!
|
||||
endwhile
|
||||
set nomodified
|
||||
endfunc
|
||||
|
||||
" Source the test script. First grab the file name, in case the script
|
||||
|
103
src/nvim/testdir/test_bufwintabinfo.vim
Normal file
103
src/nvim/testdir/test_bufwintabinfo.vim
Normal file
@@ -0,0 +1,103 @@
|
||||
" 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})))
|
||||
|
||||
set tabstop&vim
|
||||
let b:editor = 'vim'
|
||||
let l = getbufinfo('%')
|
||||
call assert_equal(bufnr('%'), l[0].bufnr)
|
||||
call assert_equal('vim', l[0].variables.editor)
|
||||
call assert_notequal(-1, index(l[0].windows, bufwinid('%')))
|
||||
|
||||
if has('signs')
|
||||
call append(0, ['Linux', 'Windows', 'Mac'])
|
||||
sign define Mark text=>> texthl=Search
|
||||
exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%')
|
||||
let l = getbufinfo('%')
|
||||
call assert_equal(2, l[0].signs[0].id)
|
||||
call assert_equal(3, l[0].signs[0].lnum)
|
||||
call assert_equal('Mark', l[0].signs[0].name)
|
||||
sign unplace *
|
||||
sign undefine Mark
|
||||
enew!
|
||||
endif
|
||||
|
||||
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()
|
||||
call setwinvar(0, 'signal', 'green')
|
||||
tabfirst
|
||||
let winlist = getwininfo()
|
||||
call assert_equal(5, len(winlist))
|
||||
call assert_equal(winbufnr(2), winlist[1].bufnr)
|
||||
call assert_equal(winheight(2), winlist[1].height)
|
||||
call assert_equal(1, winlist[2].winnr)
|
||||
call assert_equal(2, winlist[3].tabnr)
|
||||
call assert_equal('green', winlist[2].variables.signal)
|
||||
call assert_equal(winwidth(1), winlist[0].width)
|
||||
call assert_equal(w4_id, winlist[3].winid)
|
||||
let winfo = getwininfo(w5_id)[0]
|
||||
call assert_equal(2, winfo.tabnr)
|
||||
call assert_equal([], getwininfo(3))
|
||||
|
||||
call settabvar(1, 'space', 'build')
|
||||
let tablist = gettabinfo()
|
||||
call assert_equal(2, len(tablist))
|
||||
call assert_equal(3, len(tablist[1].windows))
|
||||
call assert_equal(2, tablist[1].tabnr)
|
||||
call assert_equal('build', tablist[0].variables.space)
|
||||
call assert_equal(w2_id, tablist[0].windows[0])
|
||||
call assert_equal([], gettabinfo(3))
|
||||
|
||||
tabonly | only
|
||||
|
||||
lexpr ''
|
||||
lopen
|
||||
copen
|
||||
let winlist = getwininfo()
|
||||
call assert_false(winlist[0].quickfix)
|
||||
call assert_false(winlist[0].loclist)
|
||||
call assert_true(winlist[1].quickfix)
|
||||
call assert_true(winlist[1].loclist)
|
||||
call assert_true(winlist[2].quickfix)
|
||||
call assert_false(winlist[2].loclist)
|
||||
wincmd t | only
|
||||
endfunction
|
||||
|
||||
function Test_get_buf_options()
|
||||
let opts = getbufvar(bufnr('%'), '&')
|
||||
call assert_equal(v:t_dict, type(opts))
|
||||
call assert_equal(8, opts.tabstop)
|
||||
endfunc
|
||||
|
||||
function Test_get_win_options()
|
||||
let opts = getwinvar(1, '&')
|
||||
call assert_equal(v:t_dict, type(opts))
|
||||
call assert_equal(0, opts.linebreak)
|
||||
if has('signs')
|
||||
call assert_equal('auto', opts.signcolumn)
|
||||
endif
|
||||
|
||||
let opts = gettabwinvar(1, 1, '&')
|
||||
call assert_equal(v:t_dict, type(opts))
|
||||
call assert_equal(0, opts.linebreak)
|
||||
if has('signs')
|
||||
call assert_equal('auto', opts.signcolumn)
|
||||
endif
|
||||
endfunc
|
199
src/nvim/testdir/test_signs.vim
Normal file
199
src/nvim/testdir/test_signs.vim
Normal file
@@ -0,0 +1,199 @@
|
||||
" Test for signs
|
||||
|
||||
if !has('signs')
|
||||
finish
|
||||
endif
|
||||
|
||||
func Test_sign()
|
||||
new
|
||||
call setline(1, ['a', 'b', 'c', 'd'])
|
||||
|
||||
" Define some signs.
|
||||
" We can specify icons even if not all versions of vim support icons as
|
||||
" icon is ignored when not supported. "(not supported)" is shown after
|
||||
" the icon name when listing signs.
|
||||
sign define Sign1 text=x
|
||||
try
|
||||
sign define Sign2 text=xy texthl=Title linehl=Error icon=../../pixmaps/stock_vim_find_help.png
|
||||
catch /E255:/
|
||||
" ignore error: E255: Couldn't read in sign data!
|
||||
" This error can happen when running in gui.
|
||||
" Some gui like Motif do not support the png icon format.
|
||||
endtry
|
||||
|
||||
" Test listing signs.
|
||||
let a=execute('sign list')
|
||||
call assert_match("^\nsign Sign1 text=x \nsign Sign2 icon=../../pixmaps/stock_vim_find_help.png .*text=xy linehl=Error texthl=Title$", a)
|
||||
|
||||
let a=execute('sign list Sign1')
|
||||
call assert_equal("\nsign Sign1 text=x ", a)
|
||||
|
||||
" Split the window to the bottom to verify sign jump will stay in the current window
|
||||
" if the buffer is displayed there.
|
||||
let bn = bufnr('%')
|
||||
let wn = winnr()
|
||||
exe 'sign place 41 line=3 name=Sign1 buffer=' . bn
|
||||
1
|
||||
bot split
|
||||
exe 'sign jump 41 buffer=' . bufnr('%')
|
||||
call assert_equal('c', getline('.'))
|
||||
call assert_equal(3, winnr())
|
||||
call assert_equal(bn, bufnr('%'))
|
||||
call assert_notequal(wn, winnr())
|
||||
|
||||
" Create a new buffer and check that ":sign jump" switches to the old buffer.
|
||||
1
|
||||
new foo
|
||||
call assert_notequal(bn, bufnr('%'))
|
||||
exe 'sign jump 41 buffer=' . bn
|
||||
call assert_equal(bn, bufnr('%'))
|
||||
call assert_equal('c', getline('.'))
|
||||
|
||||
" Redraw to make sure that screen redraw with sign gets exercised,
|
||||
" with and without 'rightleft'.
|
||||
if has('rightleft')
|
||||
set rightleft
|
||||
redraw
|
||||
set norightleft
|
||||
endif
|
||||
redraw
|
||||
|
||||
" Check that we can't change sign.
|
||||
call assert_fails("exe 'sign place 40 name=Sign1 buffer=' . bufnr('%')", 'E885:')
|
||||
|
||||
" Check placed signs
|
||||
let a=execute('sign place')
|
||||
call assert_equal("\n--- Signs ---\nSigns for [NULL]:\n line=3 id=41 name=Sign1\n", a)
|
||||
|
||||
" Unplace the sign and try jumping to it again should fail.
|
||||
sign unplace 41
|
||||
1
|
||||
call assert_fails("exe 'sign jump 41 buffer=' . bufnr('%')", 'E157:')
|
||||
call assert_equal('a', getline('.'))
|
||||
|
||||
" Unplace sign on current line.
|
||||
exe 'sign place 42 line=4 name=Sign2 buffer=' . bufnr('%')
|
||||
4
|
||||
sign unplace
|
||||
let a=execute('sign place')
|
||||
call assert_equal("\n--- Signs ---\n", a)
|
||||
|
||||
" Try again to unplace sign on current line, it should fail this time.
|
||||
call assert_fails('sign unplace', 'E159:')
|
||||
|
||||
" Unplace all signs.
|
||||
exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%')
|
||||
sign unplace *
|
||||
let a=execute('sign place')
|
||||
call assert_equal("\n--- Signs ---\n", a)
|
||||
|
||||
" Check :jump with file=...
|
||||
edit foo
|
||||
call setline(1, ['A', 'B', 'C', 'D'])
|
||||
|
||||
try
|
||||
sign define Sign3 text=y texthl=DoesNotExist linehl=DoesNotExist icon=doesnotexist.xpm
|
||||
catch /E255:/
|
||||
" ignore error: E255: it can happens for guis.
|
||||
endtry
|
||||
|
||||
let fn = expand('%:p')
|
||||
exe 'sign place 43 line=2 name=Sign3 file=' . fn
|
||||
edit bar
|
||||
call assert_notequal(fn, expand('%:p'))
|
||||
exe 'sign jump 43 file=' . fn
|
||||
call assert_equal('B', getline('.'))
|
||||
|
||||
" After undefining the sign, we should no longer be able to place it.
|
||||
sign undefine Sign1
|
||||
sign undefine Sign2
|
||||
sign undefine Sign3
|
||||
call assert_fails("exe 'sign place 41 line=3 name=Sign1 buffer=' . bufnr('%')", 'E155:')
|
||||
endfunc
|
||||
|
||||
" Undefining placed sign is not recommended.
|
||||
" Quoting :help sign
|
||||
"
|
||||
" :sign undefine {name}
|
||||
" Deletes a previously defined sign. If signs with this {name}
|
||||
" are still placed this will cause trouble.
|
||||
func Test_sign_undefine_still_placed()
|
||||
new foobar
|
||||
sign define Sign text=x
|
||||
exe 'sign place 41 line=1 name=Sign buffer=' . bufnr('%')
|
||||
sign undefine Sign
|
||||
|
||||
" Listing placed sign should show that sign is deleted.
|
||||
let a=execute('sign place')
|
||||
call assert_equal("\n--- Signs ---\nSigns for foobar:\n line=1 id=41 name=[Deleted]\n", a)
|
||||
|
||||
sign unplace 41
|
||||
let a=execute('sign place')
|
||||
call assert_equal("\n--- Signs ---\n", a)
|
||||
endfunc
|
||||
|
||||
func Test_sign_completion()
|
||||
sign define Sign1 text=x
|
||||
sign define Sign2 text=y
|
||||
|
||||
call feedkeys(":sign \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign define jump list place undefine unplace', @:)
|
||||
|
||||
call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign define Sign icon= linehl= text= texthl=', @:)
|
||||
|
||||
call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign define Sign linehl=SpellBad SpellCap SpellLocal SpellRare', @:)
|
||||
|
||||
call writefile(['foo'], 'XsignOne')
|
||||
call writefile(['bar'], 'XsignTwo')
|
||||
call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:)
|
||||
call delete('XsignOne')
|
||||
call delete('XsignTwo')
|
||||
|
||||
call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign undefine Sign1 Sign2', @:)
|
||||
|
||||
call feedkeys(":sign place 1 \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign place 1 buffer= file= line= name=', @:)
|
||||
|
||||
call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign place 1 name=Sign1 Sign2', @:)
|
||||
|
||||
call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign unplace 1 buffer= file=', @:)
|
||||
|
||||
call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign list Sign1 Sign2', @:)
|
||||
|
||||
call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"sign jump 1 buffer= file=', @:)
|
||||
|
||||
sign undefine Sign1
|
||||
sign undefine Sign2
|
||||
endfunc
|
||||
|
||||
func Test_sign_invalid_commands()
|
||||
call assert_fails('sign', 'E471:')
|
||||
call assert_fails('sign jump', 'E471:')
|
||||
call assert_fails('sign xxx', 'E160:')
|
||||
call assert_fails('sign define', 'E156:')
|
||||
call assert_fails('sign define Sign1 xxx', 'E475:')
|
||||
call assert_fails('sign undefine', 'E156:')
|
||||
call assert_fails('sign list xxx', 'E155:')
|
||||
call assert_fails('sign place 1 buffer=', 'E158:')
|
||||
call assert_fails('sign define Sign2 text=', 'E239:')
|
||||
endfunc
|
||||
|
||||
func Test_sign_delete_buffer()
|
||||
new
|
||||
sign define Sign text=x
|
||||
let bufnr = bufnr('%')
|
||||
new
|
||||
exe 'bd ' . bufnr
|
||||
exe 'sign place 61 line=3 name=Sign buffer=' . bufnr
|
||||
call assert_fails('sign jump 61 buffer=' . bufnr, 'E934:')
|
||||
sign unplace 61
|
||||
sign undefine Sign
|
||||
endfunc
|
@@ -146,7 +146,7 @@ static int included_patches[] = {
|
||||
// 2297 NA
|
||||
// 2296,
|
||||
// 2295,
|
||||
// 2294,
|
||||
2294,
|
||||
// 2293,
|
||||
// 2292,
|
||||
// 2291,
|
||||
@@ -163,12 +163,12 @@ static int included_patches[] = {
|
||||
// 2280,
|
||||
// 2279,
|
||||
// 2278 NA
|
||||
// 2277,
|
||||
2277,
|
||||
// 2276,
|
||||
// 2275,
|
||||
2274,
|
||||
// 2273,
|
||||
// 2272,
|
||||
2273,
|
||||
2272,
|
||||
// 2271 NA
|
||||
// 2270 NA
|
||||
// 2269,
|
||||
@@ -214,8 +214,8 @@ static int included_patches[] = {
|
||||
// 2229,
|
||||
// 2228,
|
||||
2227,
|
||||
// 2226,
|
||||
// 2225,
|
||||
2226,
|
||||
2225,
|
||||
// 2224,
|
||||
// 2223,
|
||||
// 2222,
|
||||
@@ -225,7 +225,7 @@ static int included_patches[] = {
|
||||
// 2218 NA
|
||||
2217,
|
||||
// 2216 NA
|
||||
// 2215,
|
||||
2215,
|
||||
// 2214 NA
|
||||
2213,
|
||||
2212,
|
||||
@@ -236,17 +236,17 @@ static int included_patches[] = {
|
||||
// 2207 NA
|
||||
// 2206 NA
|
||||
2205,
|
||||
// 2204,
|
||||
2204,
|
||||
// 2203 NA
|
||||
// 2202 NA
|
||||
// 2201,
|
||||
2201,
|
||||
// 2200,
|
||||
// 2199 NA
|
||||
// 2198,
|
||||
// 2197,
|
||||
// 2196,
|
||||
// 2195 NA
|
||||
// 2194,
|
||||
2194,
|
||||
// 2193 NA
|
||||
// 2192 NA
|
||||
// 2191 NA
|
||||
@@ -257,7 +257,7 @@ static int included_patches[] = {
|
||||
// 2186 NA
|
||||
// 2185,
|
||||
// 2184,
|
||||
// 2183,
|
||||
2183,
|
||||
// 2182 NA
|
||||
// 2181,
|
||||
// 2180,
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user