]> granicus.if.org Git - vim/commitdiff
patch 8.2.4565: no command line completion for :breakadd and :breakdel v8.2.4565
authorBram Moolenaar <Bram@vim.org>
Mon, 14 Mar 2022 19:24:46 +0000 (19:24 +0000)
committerBram Moolenaar <Bram@vim.org>
Mon, 14 Mar 2022 19:24:46 +0000 (19:24 +0000)
Problem:    No command line completion for :breakadd and :breakdel.
Solution:   Add completion for :breakadd and :breakdel. (Yegappan Lakshmanan,
            closes #9950)

runtime/doc/builtin.txt
src/cmdexpand.c
src/spellsuggest.c
src/testdir/test_cmdline.vim
src/testdir/test_writefile.vim
src/usercmd.c
src/version.c
src/vim.h

index 922a2da3bac0674d172da6e3512576f874627ef2..9e5b6f2f0087d83c5089c9ded69b010139743450 100644 (file)
@@ -3230,7 +3230,8 @@ getcompletion({pat}, {type} [, {filtered}])               *getcompletion()*
                arglist         file names in argument list
                augroup         autocmd groups
                buffer          buffer names
-               behave          :behave suboptions
+               behave          |:behave| suboptions
+               breakpoint      |:breakadd| and |:breakdel| suboptions
                color           color schemes
                command         Ex command
                cmdline         |cmdline-completion| result
@@ -3247,7 +3248,7 @@ getcompletion({pat}, {type} [, {filtered}])               *getcompletion()*
                function        function name
                help            help subjects
                highlight       highlight groups
-               history         :history suboptions
+               history         |:history| suboptions
                locale          locale names (as output of locale -a)
                mapclear        buffer argument
                mapping         mapping name
index b261415e85556535475c21968d375e5775dcd3c8..7ab1bba31bf9038d49351ec2c52051c750af4796 100644 (file)
@@ -1602,6 +1602,71 @@ set_context_in_lang_cmd(expand_T *xp, char_u *arg)
 }
 #endif
 
+#ifdef FEAT_EVAL
+static enum
+{
+    EXP_BREAKPT_ADD,   // expand ":breakadd" sub-commands
+    EXP_BREAKPT_DEL    // expand ":breakdel" sub-commands
+} breakpt_expand_what;
+
+/*
+ * Set the completion context for the :breakadd command. Always returns NULL.
+ */
+    static char_u *
+set_context_in_breakadd_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
+{
+    char_u *p;
+    char_u *subcmd_start;
+
+    xp->xp_context = EXPAND_BREAKPOINT;
+    xp->xp_pattern = arg;
+
+    if (cmdidx == CMD_breakadd)
+       breakpt_expand_what = EXP_BREAKPT_ADD;
+    else
+       breakpt_expand_what = EXP_BREAKPT_DEL;
+
+    p = skipwhite(arg);
+    if (*p == NUL)
+       return NULL;
+    subcmd_start = p;
+
+    if (STRNCMP("file ", p, 5) == 0 ||
+           STRNCMP("func ", p, 5) == 0)
+    {
+       // :breakadd file [lnum] <filename>
+       // :breakadd func [lnum] <funcname>
+       p += 4;
+       p = skipwhite(p);
+
+       // skip line number (if specified)
+       if (VIM_ISDIGIT(*p))
+       {
+           p = skipdigits(p);
+           if (*p != ' ')
+           {
+               xp->xp_context = EXPAND_NOTHING;
+               return NULL;
+           }
+           p = skipwhite(p);
+       }
+       if (STRNCMP("file", subcmd_start, 4) == 0)
+           xp->xp_context = EXPAND_FILES;
+       else
+           xp->xp_context = EXPAND_USER_FUNC;
+       xp->xp_pattern = p;
+    }
+    else if (STRNCMP("expr ", p, 5) == 0)
+    {
+       // :breakadd expr <expression>
+       xp->xp_context = EXPAND_EXPRESSION;
+       xp->xp_pattern = skipwhite(p + 5);
+    }
+
+    return NULL;
+}
+#endif
+
 /*
  * Set the completion context in 'xp' for command 'cmd' with index 'cmdidx'.
  * The argument to the command is 'arg' and the argument flags is 'argt'.
@@ -1958,6 +2023,12 @@ set_context_by_cmdname(
            xp->xp_pattern = arg;
            break;
 
+#ifdef FEAT_EVAL
+       case CMD_breakadd:
+       case CMD_breakdel:
+           return set_context_in_breakadd_cmd(xp, arg, cmdidx);
+#endif
+
        default:
            break;
     }
@@ -2348,6 +2419,31 @@ get_behave_arg(expand_T *xp UNUSED, int idx)
     return NULL;
 }
 
+# ifdef FEAT_EVAL
+/*
+ * Function given to ExpandGeneric() to obtain the possible arguments of the
+ * ":breakadd {expr, file, func, here}" command.
+ * ":breakdel {func, file, here}" command.
+ */
+    static char_u *
+get_breakadd_arg(expand_T *xp UNUSED, int idx)
+{
+    char *opts[] = {"expr", "file", "func", "here"};
+
+    if (idx >=0 && idx <= 3)
+    {
+       if (breakpt_expand_what == EXP_BREAKPT_ADD)
+           return (char_u *)opts[idx];
+       else
+       {
+           if (idx <= 2)
+               return (char_u *)opts[idx + 1];
+       }
+    }
+    return NULL;
+}
+#endif
+
 /*
  * Function given to ExpandGeneric() to obtain the possible arguments of the
  * ":messages {clear}" command.
@@ -2397,42 +2493,45 @@ ExpandOther(
        {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
        {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
        {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
-# ifdef FEAT_EVAL
+#ifdef FEAT_EVAL
        {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE},
        {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE},
        {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE},
        {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE},
        {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE},
-# endif
-# ifdef FEAT_MENU
+#endif
+#ifdef FEAT_MENU
        {EXPAND_MENUS, get_menu_name, FALSE, TRUE},
        {EXPAND_MENUNAMES, get_menu_names, FALSE, TRUE},
-# endif
-# ifdef FEAT_SYN_HL
+#endif
+#ifdef FEAT_SYN_HL
        {EXPAND_SYNTAX, get_syntax_name, TRUE, TRUE},
-# endif
-# ifdef FEAT_PROFILE
+#endif
+#ifdef FEAT_PROFILE
        {EXPAND_SYNTIME, get_syntime_arg, TRUE, TRUE},
-# endif
+#endif
        {EXPAND_HIGHLIGHT, get_highlight_name, TRUE, TRUE},
        {EXPAND_EVENTS, get_event_name, TRUE, FALSE},
        {EXPAND_AUGROUP, get_augroup_name, TRUE, FALSE},
-# ifdef FEAT_CSCOPE
+#ifdef FEAT_CSCOPE
        {EXPAND_CSCOPE, get_cscope_name, TRUE, TRUE},
-# endif
-# ifdef FEAT_SIGNS
+#endif
+#ifdef FEAT_SIGNS
        {EXPAND_SIGN, get_sign_name, TRUE, TRUE},
-# endif
-# ifdef FEAT_PROFILE
+#endif
+#ifdef FEAT_PROFILE
        {EXPAND_PROFILE, get_profile_name, TRUE, TRUE},
-# endif
-# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
+#endif
+#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
        {EXPAND_LANGUAGE, get_lang_arg, TRUE, FALSE},
        {EXPAND_LOCALES, get_locales, TRUE, FALSE},
-# endif
+#endif
        {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
        {EXPAND_USER, get_users, TRUE, FALSE},
        {EXPAND_ARGLIST, get_arglist_name, TRUE, FALSE},
+#ifdef FEAT_EVAL
+       {EXPAND_BREAKPOINT, get_breakadd_arg, TRUE, TRUE},
+#endif
     };
     int        i;
     int ret = FAIL;
index 3be917f868a01eebfd23789b577c2b125fca4bef..1e389663ce90d7fc675a9dd414f1d368799ee361 100644 (file)
@@ -508,7 +508,7 @@ spell_suggest(int count)
        end_visual_mode();
        // make sure we don't include the NUL at the end of the line
        line = ml_get_curline();
-       if (badlen > STRLEN(line) - curwin->w_cursor.col)
+       if (badlen > (int)STRLEN(line) - (int)curwin->w_cursor.col)
            badlen = STRLEN(line) - curwin->w_cursor.col;
     }
     // Find the start of the badly spelled word.
index c354fa1023174b85594162e4cb20f972285d3ef5..528668e550cbba8ef524f2c97703ec3d6bbb3668 100644 (file)
@@ -3007,4 +3007,158 @@ func Test_fuzzy_completion_custom_func()
   set wildoptions&
 endfunc
 
+" Test for :breakadd argument completion
+func Test_cmdline_complete_breakadd()
+  call feedkeys(":breakadd \<C-A>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd expr file func here", @:)
+  call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd expr", @:)
+  call feedkeys(":breakadd    \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd    expr", @:)
+  call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd here", @:)
+  call feedkeys(":breakadd    he\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd    here", @:)
+  call feedkeys(":breakadd abc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd abc", @:)
+  call assert_equal(['expr', 'file', 'func', 'here'], getcompletion('', 'breakpoint'))
+  let l = getcompletion('not', 'breakpoint')
+  call assert_equal([], l)
+
+  " Test for :breakadd file [lnum] <file>
+  call writefile([], 'Xscript')
+  call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file Xscript", @:)
+  call feedkeys(":breakadd   file   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd   file   Xscript", @:)
+  call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file 20 Xscript", @:)
+  call feedkeys(":breakadd   file   20   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd   file   20   Xscript", @:)
+  call feedkeys(":breakadd file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file 20x Xsc\t", @:)
+  call feedkeys(":breakadd file 20\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file 20\t", @:)
+  call feedkeys(":breakadd file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file 20x\t", @:)
+  call feedkeys(":breakadd file Xscript  \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file Xscript  ", @:)
+  call feedkeys(":breakadd file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd file X1B2C3", @:)
+  call delete('Xscript')
+
+  " Test for :breakadd func [lnum] <function>
+  func Xbreak_func()
+  endfunc
+  call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func Xbreak_func", @:)
+  call feedkeys(":breakadd    func    Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd    func    Xbreak_func", @:)
+  call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func 20 Xbreak_func", @:)
+  call feedkeys(":breakadd   func   20   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd   func   20   Xbreak_func", @:)
+  call feedkeys(":breakadd func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func 20x Xbr\t", @:)
+  call feedkeys(":breakadd func 20\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func 20\t", @:)
+  call feedkeys(":breakadd func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func 20x\t", @:)
+  call feedkeys(":breakadd func Xbreak_func  \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func Xbreak_func  ", @:)
+  call feedkeys(":breakadd func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd func X1B2C3", @:)
+  delfunc Xbreak_func
+
+  " Test for :breakadd expr <expression>
+  let g:Xtest_var = 10
+  call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd expr Xtest_var", @:)
+  call feedkeys(":breakadd    expr    Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd    expr    Xtest_var", @:)
+  call feedkeys(":breakadd expr Xtest_var  \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd expr Xtest_var  ", @:)
+  call feedkeys(":breakadd expr X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd expr X1B2C3", @:)
+  unlet g:Xtest_var
+
+  " Test for :breakadd here
+  call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd here Xtest", @:)
+  call feedkeys(":breakadd   here   Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd   here   Xtest", @:)
+  call feedkeys(":breakadd here \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakadd here ", @:)
+endfunc
+
+" Test for :breakdel argument completion
+func Test_cmdline_complete_breakdel()
+  call feedkeys(":breakdel \<C-A>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file func here", @:)
+  call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file", @:)
+  call feedkeys(":breakdel    \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel    file", @:)
+  call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel here", @:)
+  call feedkeys(":breakdel    he\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel    here", @:)
+  call feedkeys(":breakdel abc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel abc", @:)
+
+  " Test for :breakdel file [lnum] <file>
+  call writefile([], 'Xscript')
+  call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file Xscript", @:)
+  call feedkeys(":breakdel   file   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel   file   Xscript", @:)
+  call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file 20 Xscript", @:)
+  call feedkeys(":breakdel   file   20   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel   file   20   Xscript", @:)
+  call feedkeys(":breakdel file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file 20x Xsc\t", @:)
+  call feedkeys(":breakdel file 20\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file 20\t", @:)
+  call feedkeys(":breakdel file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file 20x\t", @:)
+  call feedkeys(":breakdel file Xscript  \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file Xscript  ", @:)
+  call feedkeys(":breakdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel file X1B2C3", @:)
+  call delete('Xscript')
+
+  " Test for :breakdel func [lnum] <function>
+  func Xbreak_func()
+  endfunc
+  call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func Xbreak_func", @:)
+  call feedkeys(":breakdel   func   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel   func   Xbreak_func", @:)
+  call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func 20 Xbreak_func", @:)
+  call feedkeys(":breakdel   func   20   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel   func   20   Xbreak_func", @:)
+  call feedkeys(":breakdel func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func 20x Xbr\t", @:)
+  call feedkeys(":breakdel func 20\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func 20\t", @:)
+  call feedkeys(":breakdel func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func 20x\t", @:)
+  call feedkeys(":breakdel func Xbreak_func  \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func Xbreak_func  ", @:)
+  call feedkeys(":breakdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel func X1B2C3", @:)
+  delfunc Xbreak_func
+
+  " Test for :breakdel here
+  call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel here Xtest", @:)
+  call feedkeys(":breakdel   here   Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel   here   Xtest", @:)
+  call feedkeys(":breakdel here \<Tab>\<C-B>\"\<CR>", 'tx')
+  call assert_equal("\"breakdel here ", @:)
+
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index a8204ef02d12e1271f1cabc93bca59651a7d46b4..592ab88708816881b80cda287672f5d7beef22dd 100644 (file)
@@ -890,6 +890,9 @@ endfunc
 " link to the original file. The backup file should not be modified.
 func Test_write_backup_symlink()
   CheckUnix
+  call mkdir('Xbackup')
+  let save_backupdir = &backupdir
+  set backupdir=.,./Xbackup
   call writefile(['1111'], 'Xfile')
   silent !ln -s Xfile Xfile.bak
 
@@ -898,11 +901,18 @@ func Test_write_backup_symlink()
   write
   call assert_equal('link', getftype('Xfile.bak'))
   call assert_equal('Xfile', resolve('Xfile.bak'))
+  " backup file should be created in the 'backup' directory
+  if !has('bsd')
+    " This check fails on FreeBSD
+    call assert_true(filereadable('./Xbackup/Xfile.bak'))
+  endif
   set backup& backupcopy& backupext&
-  close
+  %bw
 
   call delete('Xfile')
   call delete('Xfile.bak')
+  call delete('Xbackup', 'rf')
+  let &backupdir = save_backupdir
 endfunc
 
 " Test for ':write ++bin' and ':write ++nobin'
index 1ff4d0d49221cc337b526ac69e7fbe0e62ed8017..70dbbb03badcf56af8299d7cef054c3c196b2bd6 100644 (file)
@@ -90,6 +90,9 @@ static struct
     {EXPAND_TAGS_LISTFILES, "tag_listfiles"},
     {EXPAND_USER, "user"},
     {EXPAND_USER_VARS, "var"},
+#if defined(FEAT_EVAL)
+    {EXPAND_BREAKPOINT, "breakpoint"},
+#endif
     {0, NULL}
 };
 
index bf3116ec9f143e07b9caa843633c2670df7fd911..2ea5965cdc31bcde29ff7658b51be91e632f9a2b 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4565,
 /**/
     4564,
 /**/
index 816cfe89de98f49c783bc60952de420ff710f621..4f80a09264077187aa2e4cb1504444bffa3d8560 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -801,6 +801,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 #define EXPAND_ARGLIST         48
 #define EXPAND_DIFF_BUFFERS    49
 #define EXPAND_DISASSEMBLE     50
+#define EXPAND_BREAKPOINT      51
 
 // Values for exmode_active (0 is no exmode)
 #define EXMODE_NORMAL          1