forked from aniani/vim
patch 8.2.3735: cannot use a lambda for 'imactivatefunc'
Problem: Cannot use a lambda for 'imactivatefunc'. Solution: Add lambda support for 'imactivatefunc' and 'imstatusfunc'. (Yegappan Lakshmanan, closes #9275)
This commit is contained in:
committed by
Bram Moolenaar
parent
01a4dcbcee
commit
7645da568c
@@ -4242,7 +4242,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
'imactivatefunc' 'imaf' string (default "")
|
'imactivatefunc' 'imaf' string (default "")
|
||||||
global
|
global
|
||||||
This option specifies a function that will be called to
|
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.
|
It is not used in the MS-Windows GUI version.
|
||||||
The expression will be evaluated in the |sandbox| when set from a
|
The expression will be evaluated in the |sandbox| when set from a
|
||||||
modeline, see |sandbox-option|.
|
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
|
global
|
||||||
This option specifies a function that is called to obtain the status
|
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.
|
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.
|
It is not used in the MS-Windows GUI version.
|
||||||
|
|
||||||
Example: >
|
Example: >
|
||||||
|
@@ -440,6 +440,7 @@ free_all_mem(void)
|
|||||||
free_prev_shellcmd();
|
free_prev_shellcmd();
|
||||||
free_regexp_stuff();
|
free_regexp_stuff();
|
||||||
free_tag_stuff();
|
free_tag_stuff();
|
||||||
|
free_xim_stuff();
|
||||||
free_cd_dir();
|
free_cd_dir();
|
||||||
# ifdef FEAT_SIGNS
|
# ifdef FEAT_SIGNS
|
||||||
free_signs();
|
free_signs();
|
||||||
|
@@ -67,8 +67,24 @@ xim_log(char *s, ...)
|
|||||||
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
|
# define USE_IMSTATUSFUNC (*p_imsf != NUL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(FEAT_EVAL) && \
|
#if (defined(FEAT_EVAL) && \
|
||||||
(defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
|
(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
|
static void
|
||||||
call_imactivatefunc(int active)
|
call_imactivatefunc(int active)
|
||||||
{
|
{
|
||||||
@@ -77,7 +93,7 @@ call_imactivatefunc(int active)
|
|||||||
argv[0].v_type = VAR_NUMBER;
|
argv[0].v_type = VAR_NUMBER;
|
||||||
argv[0].vval.v_number = active ? 1 : 0;
|
argv[0].vval.v_number = active ? 1 : 0;
|
||||||
argv[1].v_type = VAR_UNKNOWN;
|
argv[1].v_type = VAR_UNKNOWN;
|
||||||
(void)call_func_retnr(p_imaf, 1, argv);
|
(void)call_callback_retnr(&imaf_cb, 1, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -91,12 +107,25 @@ call_imstatusfunc(void)
|
|||||||
// FIXME: :py print 'xxx' is shown duplicate result.
|
// FIXME: :py print 'xxx' is shown duplicate result.
|
||||||
// Use silent to avoid it.
|
// Use silent to avoid it.
|
||||||
++msg_silent;
|
++msg_silent;
|
||||||
is_active = call_func_retnr(p_imsf, 0, NULL);
|
is_active = call_callback_retnr(&imsf_cb, 0, NULL);
|
||||||
--msg_silent;
|
--msg_silent;
|
||||||
return (is_active > 0);
|
return (is_active > 0);
|
||||||
}
|
}
|
||||||
#endif
|
#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_XIM) || defined(PROTO)
|
||||||
|
|
||||||
# if defined(FEAT_GUI_GTK) || defined(PROTO)
|
# if defined(FEAT_GUI_GTK) || defined(PROTO)
|
||||||
|
@@ -2330,6 +2330,23 @@ ambw_end:
|
|||||||
}
|
}
|
||||||
#endif
|
#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'
|
// 'operatorfunc'
|
||||||
else if (varp == &p_opfunc)
|
else if (varp == &p_opfunc)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
/* gui_xim.c */
|
/* 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 im_set_active(int active);
|
||||||
void xim_set_focus(int focus);
|
void xim_set_focus(int focus);
|
||||||
void im_set_position(int row, int col);
|
void im_set_position(int row, int col);
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
source view_util.vim
|
source view_util.vim
|
||||||
source check.vim
|
source check.vim
|
||||||
|
source vim9.vim
|
||||||
|
|
||||||
let s:imactivatefunc_called = 0
|
let s:imactivatefunc_called = 0
|
||||||
let s:imstatusfunc_called = 0
|
let s:imstatusfunc_called = 0
|
||||||
@@ -107,4 +108,143 @@ func Test_iminsert_toggle()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
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: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -923,7 +923,7 @@ func Test_completefunc_callback()
|
|||||||
call add(g:MycompleteFunc3_args, [a:findstart, a:base])
|
call add(g:MycompleteFunc3_args, [a:findstart, a:base])
|
||||||
return a:findstart ? 0 : []
|
return a:findstart ? 0 : []
|
||||||
endfunc
|
endfunc
|
||||||
set completefunc={a,\ b,\ ->\ MycompleteFunc3(a,\ b,)}
|
set completefunc={a,\ b\ ->\ MycompleteFunc3(a,\ b)}
|
||||||
new | only
|
new | only
|
||||||
call setline(1, 'five')
|
call setline(1, 'five')
|
||||||
let g:MycompleteFunc3_args = []
|
let g:MycompleteFunc3_args = []
|
||||||
@@ -986,26 +986,29 @@ func Test_completefunc_callback()
|
|||||||
bw!
|
bw!
|
||||||
|
|
||||||
# Test for using a lambda
|
# Test for using a lambda
|
||||||
def MycompleteFunc2(findstart: number, base: string): any
|
def LambdaComplete1(findstart: number, base: string): any
|
||||||
add(g:MycompleteFunc2_args, [findstart, base])
|
add(g:LambdaComplete1_args, [findstart, base])
|
||||||
return findstart ? 0 : []
|
return findstart ? 0 : []
|
||||||
enddef
|
enddef
|
||||||
&completefunc = '(a, b) => MycompleteFunc2(a, b)'
|
&completefunc = '(a, b) => LambdaComplete1(a, b)'
|
||||||
new | only
|
new | only
|
||||||
setline(1, 'two')
|
setline(1, 'two')
|
||||||
g:MycompleteFunc2_args = []
|
g:LambdaComplete1_args = []
|
||||||
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
|
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!
|
bw!
|
||||||
|
|
||||||
# Test for using a variable with a lambda expression
|
# 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)
|
&completefunc = string(Fn)
|
||||||
new | only
|
new | only
|
||||||
setline(1, 'three')
|
setline(1, 'three')
|
||||||
g:MycompleteFunc2_args = []
|
g:LambdaComplete2_args = []
|
||||||
feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
|
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!
|
bw!
|
||||||
END
|
END
|
||||||
call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
@@ -1080,7 +1083,7 @@ func Test_omnifunc_callback()
|
|||||||
call add(g:MyomniFunc3_args, [a:findstart, a:base])
|
call add(g:MyomniFunc3_args, [a:findstart, a:base])
|
||||||
return a:findstart ? 0 : []
|
return a:findstart ? 0 : []
|
||||||
endfunc
|
endfunc
|
||||||
set omnifunc={a,\ b,\ ->\ MyomniFunc3(a,\ b,)}
|
set omnifunc={a,\ b\ ->\ MyomniFunc3(a,\ b)}
|
||||||
new | only
|
new | only
|
||||||
call setline(1, 'five')
|
call setline(1, 'five')
|
||||||
let g:MyomniFunc3_args = []
|
let g:MyomniFunc3_args = []
|
||||||
@@ -1237,7 +1240,7 @@ func Test_thesaurusfunc_callback()
|
|||||||
call add(g:MytsrFunc3_args, [a:findstart, a:base])
|
call add(g:MytsrFunc3_args, [a:findstart, a:base])
|
||||||
return a:findstart ? 0 : []
|
return a:findstart ? 0 : []
|
||||||
endfunc
|
endfunc
|
||||||
set thesaurusfunc={a,\ b,\ ->\ MytsrFunc3(a,\ b,)}
|
set thesaurusfunc={a,\ b\ ->\ MytsrFunc3(a,\ b)}
|
||||||
new | only
|
new | only
|
||||||
call setline(1, 'five')
|
call setline(1, 'five')
|
||||||
let g:MytsrFunc3_args = []
|
let g:MytsrFunc3_args = []
|
||||||
|
@@ -753,6 +753,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3735,
|
||||||
/**/
|
/**/
|
||||||
3734,
|
3734,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user