# HG changeset patch # User Bram Moolenaar # Date 1547210706 -3600 # Node ID 51b3c36b052384819a4b1e2a51fa964e2158ec7b # Parent 50a5ad0008456cf47dbc1da93c2fd8bae880d2ee patch 8.1.0717: there is no function for the ":sign jump" command commit https://github.com/vim/vim/commit/6b7b7190aa9e5c4f51bceaebf9275aa5097cfea1 Author: Bram Moolenaar Date: Fri Jan 11 13:42:41 2019 +0100 patch 8.1.0717: there is no function for the ":sign jump" command Problem: There is no function for the ":sign jump" command. Solution: Add the sign_jump() function. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/3780) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2412,6 +2412,8 @@ sign_define({name} [, {dict}]) Number de sign_getdefined([{name}]) List get a list of defined signs sign_getplaced([{expr} [, {dict}]]) List get a list of placed signs +sign_jump({id}, {group}, {expr}) + Number jump to a sign sign_place({id}, {group}, {name}, {expr} [, {dict}]) Number place a sign sign_undefine([{name}]) Number undefine a sign @@ -7998,6 +8000,21 @@ sign_getplaced([{expr} [, {dict}]]) *s " Get a List of all the placed signs echo sign_getplaced() < + *sign_jump()* +sign_jump({id}, {group}, {expr}) + Open the buffer {expr} or jump to the window that contains + {expr} and position the cursor at sign {id} in group {group}. + This is similar to the |:sign-jump| command. + + For the use of {expr}, see |bufname()|. + + Returns the line number of the sign. Returns -1 if the + arguments are invalid. + + Example: > + " Jump to sign 10 in the current buffer + call sign_jump(10, '', '') +< *sign_place()* sign_place({id}, {group}, {name}, {expr} [, {dict}]) Place the sign defined as {name} at line {lnum} in file {expr} diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -263,13 +263,13 @@ See |sign_unplace()| for the equivalent all the files it appears in. :sign unplace * - Remove placed signs in the global group from all the files. + Remove all placed signs in the global group from all the files. :sign unplace * group={group} - Remove placed signs in group {group} from all the files. + Remove all placed signs in group {group} from all the files. :sign unplace * group=* - Remove placed signs in all the groups from all the files. + Remove all placed signs in all the groups from all the files. :sign unplace Remove a placed sign at the cursor position. If multiple signs @@ -317,6 +317,8 @@ See |sign_getplaced()| for the equivalen JUMPING TO A SIGN *:sign-jump* *E157* +See |sign_jump()| for the equivalent Vim script function. + :sign jump {id} file={fname} Open the file {fname} or jump to the window that contains {fname} and position the cursor at sign {id}. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -987,6 +987,7 @@ Signs: *sign-functions* sign_define() define or update a sign sign_getdefined() get a list of defined signs sign_getplaced() get a list of placed signs + sign_jump() jump to a sign sign_place() place a sign sign_undefine() undefine a sign sign_unplace() unplace a sign diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -371,6 +371,7 @@ static void f_shiftwidth(typval_T *argva static void f_sign_define(typval_T *argvars, typval_T *rettv); static void f_sign_getdefined(typval_T *argvars, typval_T *rettv); static void f_sign_getplaced(typval_T *argvars, typval_T *rettv); +static void f_sign_jump(typval_T *argvars, typval_T *rettv); static void f_sign_place(typval_T *argvars, typval_T *rettv); static void f_sign_undefine(typval_T *argvars, typval_T *rettv); static void f_sign_unplace(typval_T *argvars, typval_T *rettv); @@ -858,6 +859,7 @@ static struct fst {"sign_define", 1, 2, f_sign_define}, {"sign_getdefined", 0, 1, f_sign_getdefined}, {"sign_getplaced", 0, 2, f_sign_getplaced}, + {"sign_jump", 3, 3, f_sign_jump}, {"sign_place", 4, 5, f_sign_place}, {"sign_undefine", 0, 1, f_sign_undefine}, {"sign_unplace", 1, 2, f_sign_unplace}, @@ -1918,6 +1920,23 @@ tv_get_buf(typval_T *tv, int curtab_only } /* + * Get the buffer from "arg" and give an error and return NULL if it is not + * valid. + */ + static buf_T * +get_buf_arg(typval_T *arg) +{ + buf_T *buf; + + ++emsg_off; + buf = tv_get_buf(arg, FALSE); + --emsg_off; + if (buf == NULL) + EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(arg)); + return buf; +} + +/* * "bufname(expr)" function */ static void @@ -11366,14 +11385,10 @@ f_sign_getplaced(typval_T *argvars, typv if (argvars[0].v_type != VAR_UNKNOWN) { - // get signs placed in this buffer - buf = tv_get_buf(&argvars[0], FALSE); + // get signs placed in the specified buffer + buf = get_buf_arg(&argvars[0]); if (buf == NULL) - { - EMSG2(_("E158: Invalid buffer name: %s"), - tv_get_string(&argvars[0])); return; - } if (argvars[1].v_type != VAR_UNKNOWN) { @@ -11413,6 +11428,53 @@ f_sign_getplaced(typval_T *argvars, typv } /* + * "sign_jump()" function + */ + static void +f_sign_jump(typval_T *argvars, typval_T *rettv) +{ + int sign_id; + char_u *sign_group = NULL; + buf_T *buf; + int notanum = FALSE; + + rettv->vval.v_number = -1; + + // Sign identifer + sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); + if (notanum) + return; + if (sign_id <= 0) + { + EMSG(_(e_invarg)); + return; + } + + // Sign group + sign_group = tv_get_string_chk(&argvars[1]); + if (sign_group == NULL) + return; + if (sign_group[0] == '\0') + sign_group = NULL; // global sign group + else + { + sign_group = vim_strsave(sign_group); + if (sign_group == NULL) + return; + } + + // Buffer to place the sign + buf = get_buf_arg(&argvars[2]); + if (buf == NULL) + goto cleanup; + + rettv->vval.v_number = sign_jump(sign_id, sign_group, buf); + +cleanup: + vim_free(sign_group); +} + +/* * "sign_place()" function */ static void @@ -11459,12 +11521,9 @@ f_sign_place(typval_T *argvars, typval_T goto cleanup; // Buffer to place the sign - buf = tv_get_buf(&argvars[3], FALSE); + buf = get_buf_arg(&argvars[3]); if (buf == NULL) - { - EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(&argvars[3])); goto cleanup; - } if (argvars[4].v_type != VAR_UNKNOWN) { @@ -11568,13 +11627,9 @@ f_sign_unplace(typval_T *argvars, typval if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL) { - buf = tv_get_buf(&di->di_tv, FALSE); + buf = get_buf_arg(&di->di_tv); if (buf == NULL) - { - EMSG2(_("E158: Invalid buffer name: %s"), - tv_get_string(&di->di_tv)); goto cleanup; - } } if (dict_find(dict, (char_u *)"id", -1) != NULL) sign_id = dict_get_number(dict, (char_u *)"id"); diff --git a/src/proto/sign.pro b/src/proto/sign.pro --- a/src/proto/sign.pro +++ b/src/proto/sign.pro @@ -11,6 +11,7 @@ void sign_mark_adjust(linenr_T line1, li int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl); int sign_undefine_by_name(char_u *name); int sign_place(int *sign_id, char_u *sign_group, char_u *sign_name, buf_T *buf, linenr_T lnum, int prio); +linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf); int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum); void ex_sign(exarg_T *eap); void sign_getlist(char_u *name, list_T *retlist); diff --git a/src/sign.c b/src/sign.c --- a/src/sign.c +++ b/src/sign.c @@ -22,16 +22,16 @@ typedef struct sign sign_T; struct sign { - sign_T *sn_next; /* next sign in list */ - int sn_typenr; /* type number of sign */ - char_u *sn_name; /* name of sign */ - char_u *sn_icon; /* name of pixmap */ + sign_T *sn_next; // next sign in list + int sn_typenr; // type number of sign + char_u *sn_name; // name of sign + char_u *sn_icon; // name of pixmap # ifdef FEAT_SIGN_ICONS - void *sn_image; /* icon image */ + void *sn_image; // icon image # endif - char_u *sn_text; /* text used instead of pixmap */ - int sn_line_hl; /* highlight ID for line */ - int sn_text_hl; /* highlight ID for text */ + char_u *sn_text; // text used instead of pixmap + int sn_line_hl; // highlight ID for line + int sn_text_hl; // highlight ID for text }; static sign_T *first_sign = NULL; @@ -381,9 +381,9 @@ buf_change_sign_type( buf_getsigntype( buf_T *buf, linenr_T lnum, - int type) /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */ + int type) // SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL { - signlist_T *sign; /* a sign in a b_signlist */ + signlist_T *sign; // a sign in a b_signlist FOR_ALL_SIGNS_IN_BUF(buf, sign) if (sign->lnum == lnum @@ -526,11 +526,11 @@ buf_findsign_id( */ int buf_findsigntype_id( - buf_T *buf, /* buffer whose sign we are searching for */ - linenr_T lnum, /* line number of sign */ - int typenr) /* sign type number */ + buf_T *buf, // buffer whose sign we are searching for + linenr_T lnum, // line number of sign + int typenr) // sign type number { - signlist_T *sign; /* a sign in the signlist */ + signlist_T *sign; // a sign in the signlist FOR_ALL_SIGNS_IN_BUF(buf, sign) if (sign->lnum == lnum && sign->typenr == typenr) @@ -656,7 +656,7 @@ sign_mark_adjust( long amount, long amount_after) { - signlist_T *sign; /* a sign in a b_signlist */ + signlist_T *sign; // a sign in a b_signlist FOR_ALL_SIGNS_IN_BUF(curbuf, sign) { @@ -678,8 +678,8 @@ sign_mark_adjust( */ static int sign_cmd_idx( - char_u *begin_cmd, /* begin of sign subcmd */ - char_u *end_cmd) /* just after sign subcmd */ + char_u *begin_cmd, // begin of sign subcmd + char_u *end_cmd) // just after sign subcmd { int idx; char save = *end_cmd; @@ -984,8 +984,51 @@ sign_unplace_at_cursor(char_u *groupname } /* - * sign define command - * ":sign define {name} ..." + * Jump to a sign. + */ + linenr_T +sign_jump(int sign_id, char_u *sign_group, buf_T *buf) +{ + linenr_T lnum; + + if ((lnum = buf_findsign(buf, sign_id, sign_group)) <= 0) + { + EMSGN(_("E157: Invalid sign ID: %ld"), sign_id); + return -1; + } + + // 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_u *cmd; + + if (buf->b_fname == NULL) + { + EMSG(_("E934: Cannot jump to a buffer that does not have a name")); + return -1; + } + cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25); + if (cmd == NULL) + return -1; + sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname); + do_cmdline_cmd(cmd); + vim_free(cmd); + } +# ifdef FEAT_FOLDING + foldOpenCursor(); +# endif + + return lnum; +} + +/* + * ":sign define {name} ..." command */ static void sign_define_cmd(char_u *sign_name, char_u *cmdline) @@ -1043,7 +1086,7 @@ sign_define_cmd(char_u *sign_name, char_ } /* - * :sign place command + * ":sign place" command */ static void sign_place_cmd( @@ -1087,7 +1130,7 @@ sign_place_cmd( } /* - * :sign unplace command + * ":sign unplace" command */ static void sign_unplace_cmd( @@ -1152,7 +1195,7 @@ sign_unplace_cmd( } /* - * Jump to a placed sign + * Jump to a placed sign commands: * :sign jump {id} file={fname} * :sign jump {id} buffer={nr} * :sign jump {id} group={group} file={fname} @@ -1180,39 +1223,7 @@ sign_jump_cmd( EMSG(_(e_invarg)); return; } - - if ((lnum = buf_findsign(buf, id, group)) <= 0) - { - EMSGN(_("E157: Invalid sign ID: %ld"), id); - return; - } - - // 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_u *cmd; - - if (buf->b_fname == NULL) - { - EMSG(_("E934: Cannot jump to a buffer that does not have a name")); - return; - } - cmd = alloc((unsigned)STRLEN(buf->b_fname) + 25); - if (cmd == NULL) - return; - sprintf((char *)cmd, "e +%ld %s", (long)lnum, buf->b_fname); - do_cmdline_cmd(cmd); - vim_free(cmd); - } -# ifdef FEAT_FOLDING - foldOpenCursor(); -# endif + (void)sign_jump(id, group, buf); } /* @@ -1685,7 +1696,7 @@ sign_get_text(int typenr) # if defined(FEAT_SIGN_ICONS) || defined(PROTO) void * sign_get_image( - int typenr) /* the attribute which may have a sign */ + int typenr) // the attribute which may have a sign { sign_T *sp; @@ -1709,11 +1720,11 @@ free_signs(void) # if defined(FEAT_CMDL_COMPL) || defined(PROTO) static enum { - EXP_SUBCMD, /* expand :sign sub-commands */ - EXP_DEFINE, /* expand :sign define {name} args */ - EXP_PLACE, /* expand :sign place {id} args */ - EXP_UNPLACE, /* expand :sign unplace" */ - EXP_SIGN_NAMES /* expand with name of placed signs */ + EXP_SUBCMD, // expand :sign sub-commands + EXP_DEFINE, // expand :sign define {name} args + EXP_PLACE, // expand :sign place {id} args + EXP_UNPLACE, // expand :sign unplace" + EXP_SIGN_NAMES // expand with name of placed signs } expand_what; /* @@ -1753,7 +1764,7 @@ get_sign_name(expand_T *xp UNUSED, int i return (char_u *)unplace_arg[idx]; } case EXP_SIGN_NAMES: - /* Complete with name of signs already defined */ + // Complete with name of signs already defined current_idx = 0; for (sp = first_sign; sp != NULL; sp = sp->sn_next) if (current_idx++ == idx) @@ -1776,38 +1787,38 @@ set_context_in_sign_cmd(expand_T *xp, ch int cmd_idx; char_u *begin_subcmd_args; - /* Default: expand subcommands. */ + // Default: expand subcommands. xp->xp_context = EXPAND_SIGN; expand_what = EXP_SUBCMD; xp->xp_pattern = arg; end_subcmd = skiptowhite(arg); if (*end_subcmd == NUL) - /* expand subcmd name - * :sign {subcmd}*/ + // expand subcmd name + // :sign {subcmd} return; cmd_idx = sign_cmd_idx(arg, end_subcmd); - /* :sign {subcmd} {subcmd_args} - * | - * begin_subcmd_args */ + // :sign {subcmd} {subcmd_args} + // | + // begin_subcmd_args begin_subcmd_args = skipwhite(end_subcmd); p = skiptowhite(begin_subcmd_args); if (*p == NUL) { - /* - * Expand first argument of subcmd when possible. - * For ":jump {id}" and ":unplace {id}", we could - * possibly expand the ids of all signs already placed. - */ + // + // Expand first argument of subcmd when possible. + // For ":jump {id}" and ":unplace {id}", we could + // possibly expand the ids of all signs already placed. + // xp->xp_pattern = begin_subcmd_args; switch (cmd_idx) { case SIGNCMD_LIST: case SIGNCMD_UNDEFINE: - /* :sign list - * :sign undefine */ + // :sign list + // :sign undefine expand_what = EXP_SIGN_NAMES; break; default: @@ -1816,13 +1827,13 @@ set_context_in_sign_cmd(expand_T *xp, ch return; } - /* expand last argument of subcmd */ + // expand last argument of subcmd - /* :sign define {name} {args}... - * | - * p */ + // :sign define {name} {args}... + // | + // p - /* Loop until reaching last argument. */ + // Loop until reaching last argument. do { p = skipwhite(p); @@ -1832,12 +1843,12 @@ set_context_in_sign_cmd(expand_T *xp, ch p = vim_strchr(last, '='); - /* :sign define {name} {args}... {last}= - * | | - * last p */ + // :sign define {name} {args}... {last}= + // | | + // last p if (p == NULL) { - /* Expand last argument name (before equal sign). */ + // Expand last argument name (before equal sign). xp->xp_pattern = last; switch (cmd_idx) { @@ -1857,7 +1868,7 @@ set_context_in_sign_cmd(expand_T *xp, ch } else { - /* Expand last argument value (after equal sign). */ + // Expand last argument value (after equal sign). xp->xp_pattern = p + 1; switch (cmd_idx) { diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -1255,3 +1255,48 @@ func Test_sign_change_type() sign undefine sign2 enew! endfunc + +" Test for the sign_jump() function +func Test_sign_jump_func() + enew! | only! + + sign define sign1 text=#> linehl=Comment + + edit foo + set buftype=nofile + call setline(1, ['A', 'B', 'C', 'D', 'E']) + call sign_place(5, '', 'sign1', '', {'lnum' : 2}) + call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3}) + call sign_place(6, '', 'sign1', '', {'lnum' : 4}) + call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5}) + split bar + set buftype=nofile + call setline(1, ['P', 'Q', 'R', 'S', 'T']) + call sign_place(5, '', 'sign1', '', {'lnum' : 2}) + call sign_place(5, 'g1', 'sign1', '', {'lnum' : 3}) + call sign_place(6, '', 'sign1', '', {'lnum' : 4}) + call sign_place(6, 'g1', 'sign1', '', {'lnum' : 5}) + + let r = sign_jump(5, '', 'foo') + call assert_equal(2, r) + call assert_equal(2, line('.')) + let r = sign_jump(6, 'g1', 'foo') + call assert_equal(5, r) + call assert_equal(5, line('.')) + let r = sign_jump(5, '', 'bar') + call assert_equal(2, r) + call assert_equal(2, line('.')) + + " Error cases + call assert_fails("call sign_jump(99, '', 'bar')", 'E157:') + call assert_fails("call sign_jump(0, '', 'foo')", 'E474:') + call assert_fails("call sign_jump(5, 'g5', 'foo')", 'E157:') + call assert_fails('call sign_jump([], "", "foo")', 'E745:') + call assert_fails('call sign_jump(2, [], "foo")', 'E730:') + call assert_fails('call sign_jump(2, "", {})', 'E158:') + call assert_fails('call sign_jump(2, "", "baz")', 'E158:') + + sign unplace * group=* + sign undefine sign1 + enew! | only! +endfunc diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -800,6 +800,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 717, +/**/ 716, /**/ 715,