Patch 8.2.3735
Problem: Cannot use a lambda for 'imactivatefunc'.
Solution: Add lambda support for 'imactivatefunc' and 'imstatusfunc'.
(Yegappan Lakshmanan, closes #9275)
Files: runtime/doc/options.txt, src/alloc.c, src/gui_xim.c,
src/optionstr.c, src/proto/gui_xim.pro,
src/testdir/test_iminsert.vim, src/testdir/test_ins_complete.vim
*** ../vim-8.2.3734/runtime/doc/options.txt 2021-12-03 11:08:34.256842709
+0000
--- runtime/doc/options.txt 2021-12-04 13:58:20.200881316 +0000
***************
*** 4228,4234 ****
'imactivatefunc' 'imaf' string (default "")
global
This option specifies a function that will be called to
! activate or deactivate the Input Method.
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|.
--- 4247,4255 ----
'imactivatefunc' 'imaf' string (default "")
global
This option specifies a function that will be called to
! 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|.
***************
*** 4338,4343 ****
--- 4359,4366 ----
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: >
*** ../vim-8.2.3734/src/alloc.c 2021-11-29 20:39:06.666101630 +0000
--- src/alloc.c 2021-12-04 13:58:20.200881316 +0000
***************
*** 440,445 ****
--- 440,446 ----
free_prev_shellcmd();
free_regexp_stuff();
free_tag_stuff();
+ free_xim_stuff();
free_cd_dir();
# ifdef FEAT_SIGNS
free_signs();
*** ../vim-8.2.3734/src/gui_xim.c 2021-08-02 17:07:15.186473836 +0100
--- src/gui_xim.c 2021-12-04 13:58:20.200881316 +0000
***************
*** 67,74 ****
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
#endif
! #if defined(FEAT_EVAL) && \
! (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
static void
call_imactivatefunc(int active)
{
--- 67,90 ----
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
#endif
! #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,83 ****
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);
}
static int
--- 93,99 ----
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = active ? 1 : 0;
argv[1].v_type = VAR_UNKNOWN;
! (void)call_callback_retnr(&imaf_cb, 1, argv);
}
static int
***************
*** 91,102 ****
// FIXME: :py print 'xxx' is shown duplicate result.
// Use silent to avoid it.
++msg_silent;
! is_active = call_func_retnr(p_imsf, 0, NULL);
--msg_silent;
return (is_active > 0);
}
#endif
#if defined(FEAT_XIM) || defined(PROTO)
# if defined(FEAT_GUI_GTK) || defined(PROTO)
--- 107,131 ----
// FIXME: :py print 'xxx' is shown duplicate result.
// Use silent to avoid it.
++msg_silent;
! 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)
*** ../vim-8.2.3734/src/optionstr.c 2021-12-03 11:08:34.256842709 +0000
--- src/optionstr.c 2021-12-04 13:58:20.200881316 +0000
***************
*** 2330,2335 ****
--- 2330,2352 ----
}
#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)
{
*** ../vim-8.2.3734/src/proto/gui_xim.pro 2020-06-01 13:34:22.027462262
+0100
--- src/proto/gui_xim.pro 2021-12-04 13:58:20.200881316 +0000
***************
*** 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);
*** ../vim-8.2.3734/src/testdir/test_iminsert.vim 2020-08-13
20:05:31.789361598 +0100
--- src/testdir/test_iminsert.vim 2021-12-04 13:58:20.200881316 +0000
***************
*** 2,7 ****
--- 2,8 ----
source view_util.vim
source check.vim
+ source vim9.vim
let s:imactivatefunc_called = 0
let s:imstatusfunc_called = 0
***************
*** 107,110 ****
--- 108,250 ----
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
*** ../vim-8.2.3734/src/testdir/test_ins_complete.vim 2021-12-03
11:08:34.260842706 +0000
--- src/testdir/test_ins_complete.vim 2021-12-04 13:58:20.200881316 +0000
***************
*** 923,929 ****
call add(g:MycompleteFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set completefunc={a,\ b,\ ->\ MycompleteFunc3(a,\ b,)}
new | only
call setline(1, 'five')
let g:MycompleteFunc3_args = []
--- 923,929 ----
call add(g:MycompleteFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set completefunc={a,\ b\ ->\ MycompleteFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MycompleteFunc3_args = []
***************
*** 986,1011 ****
bw!
# Test for using a lambda
! def MycompleteFunc2(findstart: number, base: string): any
! add(g:MycompleteFunc2_args, [findstart, base])
return findstart ? 0 : []
enddef
! &completefunc = '(a, b) => MycompleteFunc2(a, b)'
new | only
setline(1, 'two')
! g:MycompleteFunc2_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
! assert_equal([[1, ''], [0, 'two']], g:MycompleteFunc2_args)
bw!
# Test for using a variable with a lambda expression
! var Fn: func = (a, b) => MycompleteFunc2(a, b)
&completefunc = string(Fn)
new | only
setline(1, 'three')
! g:MycompleteFunc2_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
! assert_equal([[1, ''], [0, 'three']], g:MycompleteFunc2_args)
bw!
END
call CheckScriptSuccess(lines)
--- 986,1014 ----
bw!
# Test for using a lambda
! def LambdaComplete1(findstart: number, base: string): any
! add(g:LambdaComplete1_args, [findstart, base])
return findstart ? 0 : []
enddef
! &completefunc = '(a, b) => LambdaComplete1(a, b)'
new | only
setline(1, 'two')
! g:LambdaComplete1_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
! assert_equal([[1, ''], [0, 'two']], g:LambdaComplete1_args)
bw!
# Test for using a variable with a lambda expression
! var Fn: func = (findstart, base) => {
! add(g:LambdaComplete2_args, [findstart, base])
! return findstart ? 0 : []
! }
&completefunc = string(Fn)
new | only
setline(1, 'three')
! g:LambdaComplete2_args = []
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
! assert_equal([[1, ''], [0, 'three']], g:LambdaComplete2_args)
bw!
END
call CheckScriptSuccess(lines)
***************
*** 1080,1086 ****
call add(g:MyomniFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set omnifunc={a,\ b,\ ->\ MyomniFunc3(a,\ b,)}
new | only
call setline(1, 'five')
let g:MyomniFunc3_args = []
--- 1083,1089 ----
call add(g:MyomniFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set omnifunc={a,\ b\ ->\ MyomniFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MyomniFunc3_args = []
***************
*** 1237,1243 ****
call add(g:MytsrFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set thesaurusfunc={a,\ b,\ ->\ MytsrFunc3(a,\ b,)}
new | only
call setline(1, 'five')
let g:MytsrFunc3_args = []
--- 1240,1246 ----
call add(g:MytsrFunc3_args, [a:findstart, a:base])
return a:findstart ? 0 : []
endfunc
! set thesaurusfunc={a,\ b\ ->\ MytsrFunc3(a,\ b)}
new | only
call setline(1, 'five')
let g:MytsrFunc3_args = []
*** ../vim-8.2.3734/src/version.c 2021-12-04 13:15:07.336273914 +0000
--- src/version.c 2021-12-04 13:59:46.328943183 +0000
***************
*** 755,756 ****
--- 755,758 ----
{ /* Add new patch number below this line */
+ /**/
+ 3735,
/**/
--
If the Universe is constantly expanding, why can't I ever find a parking space?
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/20211204140302.64C4E1C0BCC%40moolenaar.net.