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.

Raspunde prin e-mail lui