changeset 18699:1febd1aa9930 v8.1.2341

patch 8.1.2341: not so easy to interrupt a script programatically Commit: https://github.com/vim/vim/commit/67a2deb9cb4ac2224cb1e4d240a5d0659f036264 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Nov 25 00:05:32 2019 +0100 patch 8.1.2341: not so easy to interrupt a script programatically Problem: Not so easy to interrupt a script programatically. Solution: Add the interrupt() function. (Yasuhiro Matsumoto, closes https://github.com/vim/vim/issues/2834)
author Bram Moolenaar <Bram@vim.org>
date Mon, 25 Nov 2019 00:15:06 +0100
parents 13e7c756367c
children 975583db60c0
files runtime/doc/eval.txt src/evalfunc.c src/ex_eval.c src/testdir/Make_all.mak src/testdir/test_interrupt.vim src/version.c
diffstat 6 files changed, 58 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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 typeahea
 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}])			*in
 		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: >
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -114,6 +114,7 @@ static void f_inputlist(typval_T *argvar
 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)
@@ -4152,6 +4154,15 @@ f_inputsecret(typval_T *argvars, typval_
 }
 
 /*
+ * "interrupt()" function
+ */
+    static void
+f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+    got_int = TRUE;
+}
+
+/*
  * "invert(expr)" function
  */
     static void
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -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)
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -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 \
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_interrupt.vim
@@ -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
--- a/src/version.c
+++ b/src/version.c
@@ -738,6 +738,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2341,
+/**/
     2340,
 /**/
     2339,