summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2021-12-04 14:02:30 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-04 14:02:30 +0000
commit7645da568c5e3b4ee339a2e99c3b3af790619787 (patch)
treee922a56be3ad038a67e54ca04a1469d6e1115329
parent01a4dcbceefa99696bd1ef8631c3f7ce9f6e0cc2 (diff)
downloadvim-git-7645da568c5e3b4ee339a2e99c3b3af790619787.tar.gz
patch 8.2.3735: cannot use a lambda for 'imactivatefunc'v8.2.3735
Problem: Cannot use a lambda for 'imactivatefunc'. Solution: Add lambda support for 'imactivatefunc' and 'imstatusfunc'. (Yegappan Lakshmanan, closes #9275)
-rw-r--r--runtime/doc/options.txt6
-rw-r--r--src/alloc.c1
-rw-r--r--src/gui_xim.c37
-rw-r--r--src/optionstr.c17
-rw-r--r--src/proto/gui_xim.pro3
-rw-r--r--src/testdir/test_iminsert.vim140
-rw-r--r--src/testdir/test_ins_complete.vim25
-rw-r--r--src/version.c2
8 files changed, 215 insertions, 16 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e352ed8f2..73c92122f 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4242,7 +4242,9 @@ A jump table for the options with a short description can be found at |Q_op|.
'imactivatefunc' 'imaf' string (default "")
global
This option specifies a function that will be called to
- activate or deactivate the Input Method.
+ activate or deactivate the Input Method. The value can be the name of
+ a function, a |lambda| or a |Funcref|. See |option-value-function| for
+ more information.
It is not used in the MS-Windows GUI version.
The expression will be evaluated in the |sandbox| when set from a
modeline, see |sandbox-option|.
@@ -4352,6 +4354,8 @@ A jump table for the options with a short description can be found at |Q_op|.
global
This option specifies a function that is called to obtain the status
of Input Method. It must return a positive number when IME is active.
+ The value can be the name of a function, a |lambda| or a |Funcref|.
+ See |option-value-function| for more information.
It is not used in the MS-Windows GUI version.
Example: >
diff --git a/src/alloc.c b/src/alloc.c
index 42caa4180..38b452cbe 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -440,6 +440,7 @@ free_all_mem(void)
free_prev_shellcmd();
free_regexp_stuff();
free_tag_stuff();
+ free_xim_stuff();
free_cd_dir();
# ifdef FEAT_SIGNS
free_signs();
diff --git a/src/gui_xim.c b/src/gui_xim.c
index 2a12412da..6d72ef1d6 100644
--- a/src/gui_xim.c
+++ b/src/gui_xim.c
@@ -67,8 +67,24 @@ xim_log(char *s, ...)
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
#endif
-#if defined(FEAT_EVAL) && \
- (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
+#if (defined(FEAT_EVAL) && \
+ (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))) || \
+ defined(PROTO)
+static callback_T imaf_cb; // 'imactivatefunc' callback function
+static callback_T imsf_cb; // 'imstatusfunc' callback function
+
+ int
+set_imactivatefunc_option(void)
+{
+ return option_set_callback_func(p_imaf, &imaf_cb);
+}
+
+ int
+set_imstatusfunc_option(void)
+{
+ return option_set_callback_func(p_imsf, &imsf_cb);
+}
+
static void
call_imactivatefunc(int active)
{
@@ -77,7 +93,7 @@ call_imactivatefunc(int active)
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = active ? 1 : 0;
argv[1].v_type = VAR_UNKNOWN;
- (void)call_func_retnr(p_imaf, 1, argv);
+ (void)call_callback_retnr(&imaf_cb, 1, argv);
}
static int
@@ -91,12 +107,25 @@ call_imstatusfunc(void)
// FIXME: :py print 'xxx' is shown duplicate result.
// Use silent to avoid it.
++msg_silent;
- is_active = call_func_retnr(p_imsf, 0, NULL);
+ is_active = call_callback_retnr(&imsf_cb, 0, NULL);
--msg_silent;
return (is_active > 0);
}
#endif
+#if defined(EXITFREE) || defined(PROTO)
+ void
+free_xim_stuff(void)
+{
+#if defined(FEAT_EVAL) && \
+ (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
+ free_callback(&imaf_cb);
+ free_callback(&imsf_cb);
+# endif
+}
+#endif
+
+
#if defined(FEAT_XIM) || defined(PROTO)
# if defined(FEAT_GUI_GTK) || defined(PROTO)
diff --git a/src/optionstr.c b/src/optionstr.c
index fe62cb360..dbb93cdc9 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -2330,6 +2330,23 @@ ambw_end:
}
#endif
+#if defined(FEAT_EVAL) && \
+ (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
+ // 'imactivatefunc'
+ else if (gvarp == &p_imaf)
+ {
+ if (set_imactivatefunc_option() == FAIL)
+ errmsg = e_invarg;
+ }
+
+ // 'imstatusfunc'
+ else if (gvarp == &p_imsf)
+ {
+ if (set_imstatusfunc_option() == FAIL)
+ errmsg = e_invarg;
+ }
+#endif
+
// 'operatorfunc'
else if (varp == &p_opfunc)
{
diff --git a/src/proto/gui_xim.pro b/src/proto/gui_xim.pro
index 01fb56cda..60f30d758 100644
--- a/src/proto/gui_xim.pro
+++ b/src/proto/gui_xim.pro
@@ -1,4 +1,7 @@
/* gui_xim.c */
+int set_imactivatefunc_option(void);
+int set_imstatusfunc_option(void);
+void free_xim_stuff(void);
void im_set_active(int active);
void xim_set_focus(int focus);
void im_set_position(int row, int col);
diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim
index d0991c33d..14063f9d8 100644
--- a/src/testdir/test_iminsert.vim
+++ b/src/testdir/test_iminsert.vim
@@ -2,6 +2,7 @@
source view_util.vim
source check.vim
+source vim9.vim
let s:imactivatefunc_called = 0
let s:imstatusfunc_called = 0
@@ -107,4 +108,143 @@ func Test_iminsert_toggle()
close!
endfunc
+" Test for different ways of setting the 'imactivatefunc' and 'imstatusfunc'
+" options
+func Test_imactivatefunc_imstatusfunc_callback()
+ CheckNotMSWindows
+ func IMactivatefunc1(active)
+ let g:IMactivatefunc_called += 1
+ endfunc
+ func IMstatusfunc1()
+ let g:IMstatusfunc_called += 1
+ return 1
+ endfunc
+ let g:IMactivatefunc_called = 0
+ let g:IMstatusfunc_called = 0
+ set iminsert=2
+
+ " Test for using a function()
+ set imactivatefunc=function('IMactivatefunc1')
+ set imstatusfunc=function('IMstatusfunc1')
+ normal! i
+
+ " Using a funcref variable to set 'completefunc'
+ let Fn1 = function('IMactivatefunc1')
+ let &imactivatefunc = string(Fn1)
+ let Fn2 = function('IMstatusfunc1')
+ let &imstatusfunc = string(Fn2)
+ normal! i
+ call assert_fails('let &imactivatefunc = Fn1', 'E729:')
+ call assert_fails('let &imstatusfunc = Fn2', 'E729:')
+
+ " Test for using a funcref()
+ set imactivatefunc=funcref('IMactivatefunc1')
+ set imstatusfunc=funcref('IMstatusfunc1')
+ normal! i
+
+ " Using a funcref variable to set 'imactivatefunc'
+ let Fn1 = funcref('IMactivatefunc1')
+ let &imactivatefunc = string(Fn1)
+ let Fn2 = funcref('IMstatusfunc1')
+ let &imstatusfunc = string(Fn2)
+ normal! i
+ call assert_fails('let &imactivatefunc = Fn1', 'E729:')
+ call assert_fails('let &imstatusfunc = Fn2', 'E729:')
+
+ " Test for using a lambda function
+ set imactivatefunc={a\ ->\ IMactivatefunc1(a)}
+ set imstatusfunc={\ ->\ IMstatusfunc1()}
+ normal! i
+
+ " Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression
+ let &imactivatefunc = '{a -> IMactivatefunc1(a)}'
+ let &imstatusfunc = '{ -> IMstatusfunc1()}'
+ normal! i
+
+ " Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda expression
+ let Lambda1 = {a -> IMactivatefunc1(a)}
+ let Lambda2 = { -> IMstatusfunc1()}
+ let &imactivatefunc = string(Lambda1)
+ let &imstatusfunc = string(Lambda2)
+ normal! i
+ call assert_fails('let &imactivatefunc = Lambda1', 'E729:')
+ call assert_fails('let &imstatusfunc = Lambda2', 'E729:')
+
+ " Test for clearing the 'completefunc' option
+ set imactivatefunc='' imstatusfunc=''
+ set imactivatefunc& imstatusfunc&
+
+ call assert_fails("set imactivatefunc=function('abc')", "E700:")
+ call assert_fails("set imstatusfunc=function('abc')", "E700:")
+ call assert_fails("set imactivatefunc=funcref('abc')", "E700:")
+ call assert_fails("set imstatusfunc=funcref('abc')", "E700:")
+
+ call assert_equal(7, g:IMactivatefunc_called)
+ call assert_equal(14, g:IMstatusfunc_called)
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ # Test for using function()
+ def IMactivatefunc1(active: number): any
+ g:IMactivatefunc_called += 1
+ return 1
+ enddef
+ def IMstatusfunc1(): number
+ g:IMstatusfunc_called += 1
+ return 1
+ enddef
+ g:IMactivatefunc_called = 0
+ g:IMstatusfunc_called = 0
+ set iminsert=2
+ set imactivatefunc=function('IMactivatefunc1')
+ set imstatusfunc=function('IMstatusfunc1')
+ normal! i
+
+ # Test for using a lambda
+ &imactivatefunc = '(a) => IMactivatefunc1(a)'
+ &imstatusfunc = '() => IMstatusfunc1()'
+ normal! i
+
+ # Test for using a variable with a lambda expression
+ var Fn1: func = (active) => {
+ g:IMactivatefunc_called += 1
+ return 1
+ }
+ var Fn2: func = () => {
+ g:IMstatusfunc_called += 1
+ return 1
+ }
+ &imactivatefunc = string(Fn1)
+ &imstatusfunc = string(Fn2)
+ normal! i
+
+ assert_equal(3, g:IMactivatefunc_called)
+ assert_equal(6, g:IMstatusfunc_called)
+
+ set iminsert=0
+ set imactivatefunc=
+ set imstatusfunc=
+ END
+ call CheckScriptSuccess(lines)
+
+ " Using Vim9 lambda expression in legacy context should fail
+ set imactivatefunc=(a)\ =>\ IMactivatefunc1(a)
+ set imstatusfunc=IMstatusfunc1
+ call assert_fails('normal! i', 'E117:')
+ set imactivatefunc=IMactivatefunc1
+ set imstatusfunc=()\ =>\ IMstatusfunc1(a)
+ call assert_fails('normal! i', 'E117:')
+
+ " cleanup
+ delfunc IMactivatefunc1
+ delfunc IMstatusfunc1
+ set iminsert=0
+ set imactivatefunc=
+ set imstatusfunc=
+
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index 083fa68f7..d39acf427 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -923,7 +923,7 @@ func Test_completefunc_callback()
call add(g:MycompleteFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
- set completefunc={a,\ b,\ ->\ MycompleteFunc3(a,\ b,)}
+ set completefunc={a,\ b\ ->\ MycompleteFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MycompleteFunc3_args = []
@@ -986,26 +986,29 @@ func Test_completefunc_callback()
bw!
# Test for using a lambda
- def MycompleteFunc2(findstart: number, base: string): any
- add(g:MycompleteFunc2_args, [findstart, base])
+ def LambdaComplete1(findstart: number, base: string): any
+ add(g:LambdaComplete1_args, [findstart, base])
return findstart ? 0 : []
enddef
- &completefunc = '(a, b) => MycompleteFunc2(a, b)'
+ &completefunc = '(a, b) => LambdaComplete1(a, b)'
new | only
setline(1, 'two')
- g:MycompleteFunc2_args = []
+ g:LambdaComplete1_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
- assert_equal([[1, ''], [0, 'two']], g:MycompleteFunc2_args)
+ assert_equal([[1, ''], [0, 'two']], g:LambdaComplete1_args)
bw!
# Test for using a variable with a lambda expression
- var Fn: func = (a, b) => MycompleteFunc2(a, b)
+ var Fn: func = (findstart, base) => {
+ add(g:LambdaComplete2_args, [findstart, base])
+ return findstart ? 0 : []
+ }
&completefunc = string(Fn)
new | only
setline(1, 'three')
- g:MycompleteFunc2_args = []
+ g:LambdaComplete2_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
- assert_equal([[1, ''], [0, 'three']], g:MycompleteFunc2_args)
+ assert_equal([[1, ''], [0, 'three']], g:LambdaComplete2_args)
bw!
END
call CheckScriptSuccess(lines)
@@ -1080,7 +1083,7 @@ func Test_omnifunc_callback()
call add(g:MyomniFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
- set omnifunc={a,\ b,\ ->\ MyomniFunc3(a,\ b,)}
+ set omnifunc={a,\ b\ ->\ MyomniFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MyomniFunc3_args = []
@@ -1237,7 +1240,7 @@ func Test_thesaurusfunc_callback()
call add(g:MytsrFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
- set thesaurusfunc={a,\ b,\ ->\ MytsrFunc3(a,\ b,)}
+ set thesaurusfunc={a,\ b\ ->\ MytsrFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MytsrFunc3_args = []
diff --git a/src/version.c b/src/version.c
index 7948ecc2c..55d233170 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3735,
+/**/
3734,
/**/
3733,