]> granicus.if.org Git - vim/commitdiff
patch 8.1.2341: not so easy to interrupt a script programatically v8.1.2341
authorBram Moolenaar <Bram@vim.org>
Sun, 24 Nov 2019 23:05:32 +0000 (00:05 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 24 Nov 2019 23:05:32 +0000 (00:05 +0100)
Problem:    Not so easy to interrupt a script programatically.
Solution:   Add the interrupt() function. (Yasuhiro Matsumoto, closes #2834)

runtime/doc/eval.txt
src/evalfunc.c
src/ex_eval.c
src/testdir/Make_all.mak
src/testdir/test_interrupt.vim [new file with mode: 0644]
src/version.c

index 7c8c8d30f48301af3b0ab69d631cf7ee13a6d501..a6f56eb916285125e551ac5604a93974241e1213 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 8.1.  Last change: 2019 Nov 21
+*eval.txt*     For Vim version 8.1.  Last change: 2019 Nov 24
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -2531,6 +2531,7 @@ inputrestore()                    Number  restore typeahead
 inputsave()                    Number  save and clear typeahead
 inputsecret({prompt} [, {text}]) String        like input() but hiding the text
 insert({object}, {item} [, {idx}]) List        insert {item} in {object} [before {idx}]
+interrupt()                    none    interrupt script execution
 invert({expr})                 Number  bitwise invert
 isdirectory({directory})       Number  |TRUE| if {directory} is a directory
 isinf({expr})                  Number  determine if {expr} is infinity value
@@ -6181,6 +6182,19 @@ insert({object}, {item} [, {idx}])                       *insert()*
                Can also be used as a |method|: >
                        mylist->insert(item)
 
+interrupt()                                            *interrupt()*
+               Interrupt script execution.  It works more or less like the
+               user typing CTRL-C, most commands won't execute and control
+               returns to the user.  This is useful to abort execution
+               from lower down, e.g. in an autocommand.  Example: >
+               :function s:check_typoname(file)
+               :   if fnamemodify(a:file, ':t') == '['
+               :       echomsg 'Maybe typo'
+               :       call interrupt()
+               :   endif
+               :endfunction
+               :au BufWritePre * call s:check_typoname(expand('<amatch>'))
+
 invert({expr})                                         *invert()*
                Bitwise invert.  The argument is converted to a number.  A
                List, Dict or Float argument causes an error.  Example: >
index 6a9f9d6370da4f4116c63be24f909785cca7e60b..075ef1bf1b2533ec6f4bd544d37cfc15e8c1a71f 100644 (file)
@@ -114,6 +114,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv);
 static void f_inputrestore(typval_T *argvars, typval_T *rettv);
 static void f_inputsave(typval_T *argvars, typval_T *rettv);
 static void f_inputsecret(typval_T *argvars, typval_T *rettv);
+static void f_interrupt(typval_T *argvars, typval_T *rettv);
 static void f_invert(typval_T *argvars, typval_T *rettv);
 static void f_islocked(typval_T *argvars, typval_T *rettv);
 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
@@ -509,6 +510,7 @@ static funcentry_T global_functions[] =
     {"inputsave",      0, 0, 0,          f_inputsave},
     {"inputsecret",    1, 2, FEARG_1,    f_inputsecret},
     {"insert",         2, 3, FEARG_1,    f_insert},
+    {"interrupt",      0, 0, 0,          f_interrupt},
     {"invert",         1, 1, FEARG_1,    f_invert},
     {"isdirectory",    1, 1, FEARG_1,    f_isdirectory},
 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
@@ -4151,6 +4153,15 @@ f_inputsecret(typval_T *argvars, typval_T *rettv)
     --inputsecret_flag;
 }
 
+/*
+ * "interrupt()" function
+ */
+    static void
+f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+    got_int = TRUE;
+}
+
 /*
  * "invert(expr)" function
  */
index f1a8b97fcc021e7f6f036fba5266c3b76d7c3876..097280a671b3e07a5d74bb9bb990296a4f3a948e 100644 (file)
@@ -85,6 +85,7 @@ static int cause_abort = FALSE;
  * until the throw point for error messages has been reached.  That is, during
  * cancellation of an expression evaluation after an aborting function call or
  * due to a parsing error, aborting() always returns the same value.
+ * "got_int" is also set by calling interrupt().
  */
     int
 aborting(void)
index 6b86b37ec1e1280ddf6611bb8643cfac980b8c46..ac254202a8e2505e9ab08feaf466d7783a68dd99 100644 (file)
@@ -154,6 +154,7 @@ NEW_TESTS = \
        test_increment \
        test_increment_dbcs \
        test_ins_complete \
+       test_interrupt \
        test_job_fails \
        test_join \
        test_json \
@@ -361,6 +362,7 @@ NEW_TESTS_RES = \
        test_increment.res \
        test_increment_dbcs.res \
        test_ins_complete.res \
+       test_interrupt.res \
        test_job_fails.res \
        test_json.res \
        test_jumplist.res \
diff --git a/src/testdir/test_interrupt.vim b/src/testdir/test_interrupt.vim
new file mode 100644 (file)
index 0000000..111752d
--- /dev/null
@@ -0,0 +1,27 @@
+" Test behavior of interrupt()
+
+let s:bufwritepre_called = 0
+let s:bufwritepost_called = 0
+
+func s:bufwritepre()
+  let s:bufwritepre_called = 1
+  call interrupt()
+endfunction
+
+func s:bufwritepost()
+  let s:bufwritepost_called = 1
+endfunction
+
+func Test_interrupt()
+  new Xfile
+  let n = 0
+  try
+    au BufWritePre Xfile call s:bufwritepre()
+    au BufWritePost Xfile call s:bufwritepost()
+    w!
+  catch /^Vim:Interrupt$/
+  endtry
+  call assert_equal(1, s:bufwritepre_called)
+  call assert_equal(0, s:bufwritepost_called)
+  call assert_equal(0, filereadable('Xfile'))
+endfunc
index bebf220031c504543d6c19ab427df063e24dfd10..bbc71be6e884294b207c2fa2d263d0c8a17f42fd 100644 (file)
@@ -737,6 +737,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2341,
 /**/
     2340,
 /**/