# HG changeset patch # User Bram Moolenaar # Date 1550412006 -3600 # Node ID 9e0154efac3a3f9b55c6d966f4b8bc88640c233c # Parent 7c92dfb1bdd7928cb7861622173a640c5a8c0f87 patch 8.1.0939: no completion for sign group names commit https://github.com/vim/vim/commit/3678f65d43d10b36dc62738aab2f341fa1e18a32 Author: Bram Moolenaar Date: Sun Feb 17 14:50:25 2019 +0100 patch 8.1.0939: no completion for sign group names Problem: No completion for sign group names. Solution: Add completion for sign group names and buffer names. (Yegappan Lakshmanan, closes #3980) diff --git a/src/sign.c b/src/sign.c --- a/src/sign.c +++ b/src/sign.c @@ -1767,20 +1767,65 @@ static enum EXP_SUBCMD, // expand :sign sub-commands EXP_DEFINE, // expand :sign define {name} args EXP_PLACE, // expand :sign place {id} args + EXP_LIST, // expand :sign place args EXP_UNPLACE, // expand :sign unplace" - EXP_SIGN_NAMES // expand with name of placed signs + EXP_SIGN_NAMES, // expand with name of placed signs + EXP_SIGN_GROUPS // expand with name of placed sign groups } expand_what; /* + * Return the n'th sign name (used for command line completion) + */ + static char_u * +get_nth_sign_name(int idx) +{ + int current_idx; + sign_T *sp; + + // Complete with name of signs already defined + current_idx = 0; + for (sp = first_sign; sp != NULL; sp = sp->sn_next) + if (current_idx++ == idx) + return sp->sn_name; + return NULL; +} + +/* + * Return the n'th sign group name (used for command line completion) + */ + static char_u * +get_nth_sign_group_name(int idx) +{ + int current_idx; + int todo; + hashitem_T *hi; + signgroup_T *group; + + // Complete with name of sign groups already defined + current_idx = 0; + todo = (int)sg_table.ht_used; + for (hi = sg_table.ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + if (current_idx++ == idx) + { + group = HI2SG(hi); + return group->sg_name; + } + } + } + return NULL; +} + +/* * Function given to ExpandGeneric() to obtain the sign command * expansion. */ char_u * get_sign_name(expand_T *xp UNUSED, int idx) { - sign_T *sp; - int current_idx; - switch (expand_what) { case EXP_SUBCMD: @@ -1802,18 +1847,23 @@ get_sign_name(expand_T *xp UNUSED, int i }; return (char_u *)place_arg[idx]; } + case EXP_LIST: + { + char *list_arg[] = + { + "group=", "file=", "buffer=", NULL + }; + return (char_u *)list_arg[idx]; + } case EXP_UNPLACE: { char *unplace_arg[] = { "group=", "file=", "buffer=", NULL }; return (char_u *)unplace_arg[idx]; } case EXP_SIGN_NAMES: - // Complete with name of signs already defined - current_idx = 0; - for (sp = first_sign; sp != NULL; sp = sp->sn_next) - if (current_idx++ == idx) - return sp->sn_name; - return NULL; + return get_nth_sign_name(idx); + case EXP_SIGN_GROUPS: + return get_nth_sign_group_name(idx); default: return NULL; } @@ -1848,28 +1898,6 @@ set_context_in_sign_cmd(expand_T *xp, ch // | // 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. - // - xp->xp_pattern = begin_subcmd_args; - switch (cmd_idx) - { - case SIGNCMD_LIST: - case SIGNCMD_UNDEFINE: - // :sign list - // :sign undefine - expand_what = EXP_SIGN_NAMES; - break; - default: - xp->xp_context = EXPAND_NOTHING; - } - return; - } // expand last argument of subcmd @@ -1878,6 +1906,7 @@ set_context_in_sign_cmd(expand_T *xp, ch // p // Loop until reaching last argument. + p = begin_subcmd_args; do { p = skipwhite(p); @@ -1900,7 +1929,19 @@ set_context_in_sign_cmd(expand_T *xp, ch expand_what = EXP_DEFINE; break; case SIGNCMD_PLACE: - expand_what = EXP_PLACE; + // List placed signs + if (VIM_ISDIGIT(*begin_subcmd_args)) + // :sign place {id} {args}... + expand_what = EXP_PLACE; + else + // :sign place {args}... + expand_what = EXP_LIST; + break; + case SIGNCMD_LIST: + case SIGNCMD_UNDEFINE: + // :sign list + // :sign undefine + expand_what = EXP_SIGN_NAMES; break; case SIGNCMD_JUMP: case SIGNCMD_UNPLACE: @@ -1917,17 +1958,30 @@ set_context_in_sign_cmd(expand_T *xp, ch switch (cmd_idx) { case SIGNCMD_DEFINE: - if (STRNCMP(last, "texthl", p - last) == 0 - || STRNCMP(last, "linehl", p - last) == 0) + if (STRNCMP(last, "texthl", 6) == 0 + || STRNCMP(last, "linehl", 6) == 0) xp->xp_context = EXPAND_HIGHLIGHT; - else if (STRNCMP(last, "icon", p - last) == 0) + else if (STRNCMP(last, "icon", 4) == 0) xp->xp_context = EXPAND_FILES; else xp->xp_context = EXPAND_NOTHING; break; case SIGNCMD_PLACE: - if (STRNCMP(last, "name", p - last) == 0) + if (STRNCMP(last, "name", 4) == 0) expand_what = EXP_SIGN_NAMES; + else if (STRNCMP(last, "group", 5) == 0) + expand_what = EXP_SIGN_GROUPS; + else if (STRNCMP(last, "file", 4) == 0) + xp->xp_context = EXPAND_BUFFERS; + else + xp->xp_context = EXPAND_NOTHING; + break; + case SIGNCMD_UNPLACE: + case SIGNCMD_JUMP: + if (STRNCMP(last, "group", 5) == 0) + expand_what = EXP_SIGN_GROUPS; + else if (STRNCMP(last, "file", 4) == 0) + xp->xp_context = EXPAND_BUFFERS; else xp->xp_context = EXPAND_NOTHING; break; 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 @@ -210,13 +210,16 @@ func Test_sign_completion() call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' . \ 'SpellLocal SpellRare', @:) - call writefile(['foo'], 'XsignOne') - call writefile(['bar'], 'XsignTwo') + call feedkeys(":sign define Sign texthl=Spell\\\"\", 'tx') + call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' . + \ 'SpellLocal SpellRare', @:) + + call writefile(repeat(["Sun is shining"], 30), "XsignOne") + call writefile(repeat(["Sky is blue"], 30), "XsignTwo") call feedkeys(":sign define Sign icon=Xsig\\\"\", 'tx') call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:) - call delete('XsignOne') - call delete('XsignTwo') + " Test for completion of arguments to ':sign undefine' call feedkeys(":sign undefine \\\"\", 'tx') call assert_equal('"sign undefine Sign1 Sign2', @:) @@ -227,17 +230,70 @@ func Test_sign_completion() call feedkeys(":sign place 1 name=\\\"\", 'tx') call assert_equal('"sign place 1 name=Sign1 Sign2', @:) + edit XsignOne + sign place 1 name=Sign1 line=5 + sign place 1 name=Sign1 group=g1 line=10 + edit XsignTwo + sign place 1 name=Sign2 group=g2 line=15 + + " Test for completion of group= and file= arguments to ':sign place' + call feedkeys(":sign place 1 name=Sign1 file=Xsign\\\"\", 'tx') + call assert_equal('"sign place 1 name=Sign1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign place 1 name=Sign1 group=\\\"\", 'tx') + call assert_equal('"sign place 1 name=Sign1 group=g1 g2', @:) + + " Test for completion of arguments to 'sign place' without sign identifier + call feedkeys(":sign place \\\"\", 'tx') + call assert_equal('"sign place buffer= file= group=', @:) + call feedkeys(":sign place file=Xsign\\\"\", 'tx') + call assert_equal('"sign place file=XsignOne XsignTwo', @:) + call feedkeys(":sign place group=\\\"\", 'tx') + call assert_equal('"sign place group=g1 g2', @:) + call feedkeys(":sign place group=g1 file=\\\"\", 'tx') + call assert_equal('"sign place group=g1 file=XsignOne XsignTwo', @:) + + " Test for completion of arguments to ':sign unplace' call feedkeys(":sign unplace 1 \\\"\", 'tx') call assert_equal('"sign unplace 1 buffer= file= group=', @:) + call feedkeys(":sign unplace 1 file=Xsign\\\"\", 'tx') + call assert_equal('"sign unplace 1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign unplace 1 group=\\\"\", 'tx') + call assert_equal('"sign unplace 1 group=g1 g2', @:) + call feedkeys(":sign unplace 1 group=g2 file=Xsign\\\"\", 'tx') + call assert_equal('"sign unplace 1 group=g2 file=XsignOne XsignTwo', @:) + " Test for completion of arguments to ':sign list' call feedkeys(":sign list \\\"\", 'tx') call assert_equal('"sign list Sign1 Sign2', @:) + " Test for completion of arguments to ':sign jump' call feedkeys(":sign jump 1 \\\"\", 'tx') call assert_equal('"sign jump 1 buffer= file= group=', @:) + call feedkeys(":sign jump 1 file=Xsign\\\"\", 'tx') + call assert_equal('"sign jump 1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign jump 1 group=\\\"\", 'tx') + call assert_equal('"sign jump 1 group=g1 g2', @:) + " Error cases + call feedkeys(":sign here\\\"\", 'tx') + call assert_equal('"sign here', @:) + call feedkeys(":sign define Sign here=\\\"\", 'tx') + call assert_equal("\"sign define Sign here=\", @:) + call feedkeys(":sign place 1 here=\\\"\", 'tx') + call assert_equal("\"sign place 1 here=\", @:) + call feedkeys(":sign jump 1 here=\\\"\", 'tx') + call assert_equal("\"sign jump 1 here=\", @:) + call feedkeys(":sign here there\\\"\", 'tx') + call assert_equal("\"sign here there\", @:) + call feedkeys(":sign here there=\\\"\", 'tx') + call assert_equal("\"sign here there=\", @:) + + sign unplace * group=* sign undefine Sign1 sign undefine Sign2 + enew + call delete('XsignOne') + call delete('XsignTwo') endfunc func Test_sign_invalid_commands() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -780,6 +780,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 939, +/**/ 938, /**/ 937,