Loading ...
Sorry, an error occurred while loading the content.

Patch 7.4.107

Expand Messages
  • Bram Moolenaar
    Patch 7.4.107 Problem: Python: When vim.eval() encounters a Vim error, a try/catch in the Python code doesn t catch it. (Yggdroot Chen) Solution: Throw
    Message 1 of 1 , Nov 28, 2013
    • 0 Attachment
      Patch 7.4.107
      Problem: Python: When vim.eval() encounters a Vim error, a try/catch in the
      Python code doesn't catch it. (Yggdroot Chen)
      Solution: Throw exceptions on errors in vim.eval(). (ZyX)
      Files: src/ex_eval.c, src/if_py_both.h, src/proto/ex_eval.pro,
      src/testdir/test86.in, src/testdir/test86.ok,
      src/testdir/test87.in, src/testdir/test87.ok


      *** ../vim-7.4.106/src/ex_eval.c 2013-06-08 15:50:28.000000000 +0200
      --- src/ex_eval.c 2013-11-28 16:59:09.000000000 +0100
      ***************
      *** 321,326 ****
      --- 321,337 ----
      }

      /*
      + * Free global "*msg_list" and the messages it contains, then set "*msg_list"
      + * to NULL.
      + */
      + void
      + free_global_msglist()
      + {
      + free_msglist(*msg_list);
      + *msg_list = NULL;
      + }
      +
      + /*
      * Throw the message specified in the call to cause_errthrow() above as an
      * error exception. If cstack is NULL, postpone the throw until do_cmdline()
      * has returned (see do_one_cmd()).
      ***************
      *** 410,475 ****
      return TRUE;
      }

      -
      /*
      ! * Throw a new exception. Return FAIL when out of memory or it was tried to
      ! * throw an illegal user exception. "value" is the exception string for a user
      ! * or interrupt exception, or points to a message list in case of an error
      ! * exception.
      */
      ! static int
      ! throw_exception(value, type, cmdname)
      void *value;
      int type;
      char_u *cmdname;
      {
      ! except_T *excp;
      ! char_u *p, *mesg, *val;
      int cmdlen;
      !
      ! /*
      ! * Disallow faking Interrupt or error exceptions as user exceptions. They
      ! * would be treated differently from real interrupt or error exceptions when
      ! * no active try block is found, see do_cmdline().
      ! */
      ! if (type == ET_USER)
      ! {
      ! if (STRNCMP((char_u *)value, "Vim", 3) == 0 &&
      ! (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':' ||
      ! ((char_u *)value)[3] == '('))
      ! {
      ! EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
      ! goto fail;
      ! }
      ! }
      !
      ! excp = (except_T *)alloc((unsigned)sizeof(except_T));
      ! if (excp == NULL)
      ! goto nomem;

      if (type == ET_ERROR)
      {
      ! /* Store the original message and prefix the exception value with
      ! * "Vim:" or, if a command name is given, "Vim(cmdname):". */
      ! excp->messages = (struct msglist *)value;
      ! mesg = excp->messages->throw_msg;
      if (cmdname != NULL && *cmdname != NUL)
      {
      cmdlen = (int)STRLEN(cmdname);
      ! excp->value = vim_strnsave((char_u *)"Vim(",
      4 + cmdlen + 2 + (int)STRLEN(mesg));
      ! if (excp->value == NULL)
      ! goto nomem;
      ! STRCPY(&excp->value[4], cmdname);
      ! STRCPY(&excp->value[4 + cmdlen], "):");
      ! val = excp->value + 4 + cmdlen + 2;
      }
      else
      {
      ! excp->value = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
      ! if (excp->value == NULL)
      ! goto nomem;
      ! val = excp->value + 4;
      }

      /* msg_add_fname may have been used to prefix the message with a file
      --- 421,461 ----
      return TRUE;
      }

      /*
      ! * Get an exception message that is to be stored in current_exception->value.
      */
      ! char_u *
      ! get_exception_string(value, type, cmdname, should_free)
      void *value;
      int type;
      char_u *cmdname;
      + int *should_free;
      {
      ! char_u *ret, *mesg;
      int cmdlen;
      ! char_u *p, *val;

      if (type == ET_ERROR)
      {
      ! *should_free = FALSE;
      ! mesg = ((struct msglist *)value)->throw_msg;
      if (cmdname != NULL && *cmdname != NUL)
      {
      cmdlen = (int)STRLEN(cmdname);
      ! ret = vim_strnsave((char_u *)"Vim(",
      4 + cmdlen + 2 + (int)STRLEN(mesg));
      ! if (ret == NULL)
      ! return ret;
      ! STRCPY(&ret[4], cmdname);
      ! STRCPY(&ret[4 + cmdlen], "):");
      ! val = ret + 4 + cmdlen + 2;
      }
      else
      {
      ! ret = vim_strnsave((char_u *)"Vim:", 4 + (int)STRLEN(mesg));
      ! if (ret == NULL)
      ! return ret;
      ! val = ret + 4;
      }

      /* msg_add_fname may have been used to prefix the message with a file
      ***************
      *** 506,519 ****
      }
      }
      else
      ! excp->value = value;

      excp->type = type;
      excp->throw_name = vim_strsave(sourcing_name == NULL
      ? (char_u *)"" : sourcing_name);
      if (excp->throw_name == NULL)
      {
      ! if (type == ET_ERROR)
      vim_free(excp->value);
      goto nomem;
      }
      --- 492,556 ----
      }
      }
      else
      ! {
      ! *should_free = FALSE;
      ! ret = (char_u *) value;
      ! }
      !
      ! return ret;
      ! }
      !
      !
      ! /*
      ! * Throw a new exception. Return FAIL when out of memory or it was tried to
      ! * throw an illegal user exception. "value" is the exception string for a
      ! * user or interrupt exception, or points to a message list in case of an
      ! * error exception.
      ! */
      ! static int
      ! throw_exception(value, type, cmdname)
      ! void *value;
      ! int type;
      ! char_u *cmdname;
      ! {
      ! except_T *excp;
      ! int should_free;
      !
      ! /*
      ! * Disallow faking Interrupt or error exceptions as user exceptions. They
      ! * would be treated differently from real interrupt or error exceptions
      ! * when no active try block is found, see do_cmdline().
      ! */
      ! if (type == ET_USER)
      ! {
      ! if (STRNCMP((char_u *)value, "Vim", 3) == 0
      ! && (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':'
      ! || ((char_u *)value)[3] == '('))
      ! {
      ! EMSG(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
      ! goto fail;
      ! }
      ! }
      !
      ! excp = (except_T *)alloc((unsigned)sizeof(except_T));
      ! if (excp == NULL)
      ! goto nomem;
      !
      ! if (type == ET_ERROR)
      ! /* Store the original message and prefix the exception value with
      ! * "Vim:" or, if a command name is given, "Vim(cmdname):". */
      ! excp->messages = (struct msglist *)value;
      !
      ! excp->value = get_exception_string(value, type, cmdname, &should_free);
      ! if (excp->value == NULL && should_free)
      ! goto nomem;

      excp->type = type;
      excp->throw_name = vim_strsave(sourcing_name == NULL
      ? (char_u *)"" : sourcing_name);
      if (excp->throw_name == NULL)
      {
      ! if (should_free)
      vim_free(excp->value);
      goto nomem;
      }
      ***************
      *** 2033,2042 ****
      /* If an error was about to be converted to an exception when
      * enter_cleanup() was called, free the message list. */
      if (msg_list != NULL)
      ! {
      ! free_msglist(*msg_list);
      ! *msg_list = NULL;
      ! }
      }

      /*
      --- 2070,2076 ----
      /* If an error was about to be converted to an exception when
      * enter_cleanup() was called, free the message list. */
      if (msg_list != NULL)
      ! free_global_msglist();
      }

      /*
      *** ../vim-7.4.106/src/if_py_both.h 2013-11-11 01:05:43.000000000 +0100
      --- src/if_py_both.h 2013-11-28 17:00:22.000000000 +0100
      ***************
      *** 566,571 ****
      --- 566,593 ----
      PyErr_SetNone(PyExc_KeyboardInterrupt);
      return -1;
      }
      + else if (msg_list != NULL && *msg_list != NULL)
      + {
      + int should_free;
      + char_u *msg;
      +
      + msg = get_exception_string(*msg_list, ET_ERROR, NULL, &should_free);
      +
      + if (msg == NULL)
      + {
      + PyErr_NoMemory();
      + return -1;
      + }
      +
      + PyErr_SetVim((char *) msg);
      +
      + free_global_msglist();
      +
      + if (should_free)
      + vim_free(msg);
      +
      + return -1;
      + }
      else if (!did_throw)
      return (PyErr_Occurred() ? -1 : 0);
      /* Python exception is preferred over vim one; unlikely to occur though */
      *** ../vim-7.4.106/src/proto/ex_eval.pro 2013-08-10 13:37:10.000000000 +0200
      --- src/proto/ex_eval.pro 2013-11-28 16:56:33.000000000 +0100
      ***************
      *** 4,11 ****
      --- 4,13 ----
      int should_abort __ARGS((int retcode));
      int aborted_in_try __ARGS((void));
      int cause_errthrow __ARGS((char_u *mesg, int severe, int *ignore));
      + void free_global_msglist __ARGS((void));
      void do_errthrow __ARGS((struct condstack *cstack, char_u *cmdname));
      int do_intthrow __ARGS((struct condstack *cstack));
      + char_u *get_exception_string __ARGS((void *value, int type, char_u *cmdname, int *should_free));
      void discard_current_exception __ARGS((void));
      void report_make_pending __ARGS((int pending, void *value));
      void report_resume_pending __ARGS((int pending, void *value));
      *** ../vim-7.4.106/src/testdir/test86.in 2013-11-11 01:05:43.000000000 +0100
      --- src/testdir/test86.in 2013-11-28 16:41:01.000000000 +0100
      ***************
      *** 179,184 ****
      --- 179,210 ----
      :unlockvar! l
      :"
      :" Function calls
      + py << EOF
      + import sys
      + def ee(expr, g=globals(), l=locals()):
      + try:
      + exec(expr, g, l)
      + except:
      + ei = sys.exc_info()
      + msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
      + msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
      + if expr.find('None') > -1:
      + msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
      + 'TypeError:("\'NoneType\' object is not iterable",)')
      + if expr.find('FailingNumber') > -1:
      + msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
      + msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
      + 'TypeError:("\'FailingNumber\' object is not iterable",)')
      + if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
      + msg = msg.replace('(\'', '("').replace('\',)', '",)')
      + if expr == 'fd(self=[])':
      + # HACK: PyMapping_Check changed meaning
      + msg = msg.replace('AttributeError:(\'keys\',)',
      + 'TypeError:(\'unable to convert list to vim dictionary\',)')
      + vim.current.buffer.append(expr + ':' + msg)
      + else:
      + vim.current.buffer.append(expr + ':NOT FAILED')
      + EOF
      :fun New(...)
      : return ['NewStart']+a:000+['NewEnd']
      :endfun
      ***************
      *** 193,210 ****
      :$put =string(l)
      :py l.extend([l[0].name])
      :$put =string(l)
      ! :try
      ! : py l[1](1, 2, 3)
      ! :catch
      ! : $put =v:exception[:16]
      ! :endtry
      :py f=l[0]
      :delfunction New
      ! :try
      ! : py f(1, 2, 3)
      ! :catch
      ! : $put =v:exception[:16]
      ! :endtry
      :if has('float')
      : let l=[0.0]
      : py l=vim.bindeval('l')
      --- 219,228 ----
      :$put =string(l)
      :py l.extend([l[0].name])
      :$put =string(l)
      ! :py ee('l[1](1, 2, 3)')
      :py f=l[0]
      :delfunction New
      ! :py ee('f(1, 2, 3)')
      :if has('float')
      : let l=[0.0]
      : py l=vim.bindeval('l')
      ***************
      *** 216,222 ****
      :let messages=[]
      :delfunction DictNew
      py <<EOF
      - import sys
      d=vim.bindeval('{}')
      m=vim.bindeval('messages')
      def em(expr, g=globals(), l=locals()):
      --- 234,239 ----
      ***************
      *** 323,328 ****
      --- 340,346 ----
      :py l[0] = t.t > 8 # check if the background thread is working
      :py del time
      :py del threading
      + :py del t
      :$put =string(l)
      :"
      :" settrace
      ***************
      *** 882,910 ****
      :fun D()
      :endfun
      py << EOF
      - def ee(expr, g=globals(), l=locals()):
      - try:
      - exec(expr, g, l)
      - except:
      - ei = sys.exc_info()
      - msg = sys.exc_info()[0].__name__ + ':' + repr(sys.exc_info()[1].args)
      - msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'')
      - if expr.find('None') > -1:
      - msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
      - 'TypeError:("\'NoneType\' object is not iterable",)')
      - if expr.find('FailingNumber') > -1:
      - msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'')
      - msg = msg.replace('TypeError:(\'iteration over non-sequence\',)',
      - 'TypeError:("\'FailingNumber\' object is not iterable",)')
      - if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1:
      - msg = msg.replace('(\'', '("').replace('\',)', '",)')
      - if expr == 'fd(self=[])':
      - # HACK: PyMapping_Check changed meaning
      - msg = msg.replace('AttributeError:(\'keys\',)',
      - 'TypeError:(\'unable to convert list to vim dictionary\',)')
      - cb.append(expr + ':' + msg)
      - else:
      - cb.append(expr + ':NOT FAILED')
      d = vim.Dictionary()
      ned = vim.Dictionary(foo='bar', baz='abcD')
      dl = vim.Dictionary(a=1)
      --- 900,905 ----
      ***************
      *** 1276,1281 ****
      --- 1271,1277 ----
      ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
      ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
      ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
      + ee('vim.eval("xxx_unknown_function_xxx()")')
      ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
      del Exe
      EOF
      *** ../vim-7.4.106/src/testdir/test86.ok 2013-11-11 01:05:43.000000000 +0100
      --- src/testdir/test86.ok 2013-11-28 16:41:01.000000000 +0100
      ***************
      *** 53,60 ****
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
      ! Vim(python):E725:
      ! Vim(python):E117:
      [0.0, 0.0]
      KeyError
      TypeError
      --- 53,60 ----
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
      ! l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)
      ! f(1, 2, 3):error:('Vim:E117: Unknown function: New',)
      [0.0, 0.0]
      KeyError
      TypeError
      ***************
      *** 1197,1202 ****
      --- 1197,1203 ----
      vim.eval("Exe('throw ''ghi''')"):error:('ghi',)
      vim.eval("Exe('echoerr ''jkl''')"):error:('Vim(echoerr):jkl',)
      vim.eval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
      + vim.eval("xxx_unknown_function_xxx()"):error:('Vim:E117: Unknown function: xxx_unknown_function_xxx',)
      vim.bindeval("Exe('xxx_non_existent_command_xxx')"):error:('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)
      Caught KeyboardInterrupt
      Running :put
      *** ../vim-7.4.106/src/testdir/test87.in 2013-11-11 01:05:43.000000000 +0100
      --- src/testdir/test87.in 2013-11-28 16:41:01.000000000 +0100
      ***************
      *** 172,177 ****
      --- 172,207 ----
      :unlockvar! l
      :"
      :" Function calls
      + py3 << EOF
      + import sys
      + import re
      +
      + py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
      +
      + def ee(expr, g=globals(), l=locals()):
      + cb = vim.current.buffer
      + try:
      + try:
      + exec(expr, g, l)
      + except Exception as e:
      + if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
      + cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
      + elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
      + cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", '')))))
      + elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
      + m = py33_type_error_pattern.search(str(e))
      + if m:
      + msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
      + cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
      + else:
      + cb.append(expr + ':' + repr((e.__class__, e)))
      + else:
      + cb.append(expr + ':' + repr((e.__class__, e)))
      + else:
      + cb.append(expr + ':NOT FAILED')
      + except Exception as e:
      + cb.append(expr + '::' + repr((e.__class__, e)))
      + EOF
      :fun New(...)
      : return ['NewStart']+a:000+['NewEnd']
      :endfun
      ***************
      *** 186,203 ****
      :$put =string(l)
      :py3 l+=[l[0].name]
      :$put =string(l)
      ! :try
      ! : py3 l[1](1, 2, 3)
      ! :catch
      ! : $put =v:exception[:13]
      ! :endtry
      :py3 f=l[0]
      :delfunction New
      ! :try
      ! : py3 f(1, 2, 3)
      ! :catch
      ! : $put =v:exception[:13]
      ! :endtry
      :if has('float')
      : let l=[0.0]
      : py3 l=vim.bindeval('l')
      --- 216,225 ----
      :$put =string(l)
      :py3 l+=[l[0].name]
      :$put =string(l)
      ! :py3 ee('l[1](1, 2, 3)')
      :py3 f=l[0]
      :delfunction New
      ! :py3 ee('f(1, 2, 3)')
      :if has('float')
      : let l=[0.0]
      : py3 l=vim.bindeval('l')
      ***************
      *** 315,320 ****
      --- 337,343 ----
      :py3 l[0] = t.t > 8 # check if the background thread is working
      :py3 del time
      :py3 del threading
      + :py3 del t
      :$put =string(l)
      :"
      :" settrace
      ***************
      *** 829,861 ****
      :fun D()
      :endfun
      py3 << EOF
      - import re
      -
      - py33_type_error_pattern = re.compile('^__call__\(\) takes (\d+) positional argument but (\d+) were given$')
      -
      - def ee(expr, g=globals(), l=locals()):
      - try:
      - try:
      - exec(expr, g, l)
      - except Exception as e:
      - if sys.version_info >= (3, 3) and e.__class__ is AttributeError and str(e).find('has no attribute')>=0 and not str(e).startswith("'vim."):
      - cb.append(expr + ':' + repr((e.__class__, AttributeError(str(e)[str(e).rfind(" '") + 2:-1]))))
      - elif sys.version_info >= (3, 3) and e.__class__ is ImportError and str(e).find('No module named \'') >= 0:
      - cb.append(expr + ':' + repr((e.__class__, ImportError(str(e).replace("'", '')))))
      - elif sys.version_info >= (3, 3) and e.__class__ is TypeError:
      - m = py33_type_error_pattern.search(str(e))
      - if m:
      - msg = '__call__() takes exactly {0} positional argument ({1} given)'.format(m.group(1), m.group(2))
      - cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
      - else:
      - cb.append(expr + ':' + repr((e.__class__, e)))
      - else:
      - cb.append(expr + ':' + repr((e.__class__, e)))
      - else:
      - cb.append(expr + ':NOT FAILED')
      - except Exception as e:
      - cb.append(expr + '::' + repr((e.__class__, e)))
      -
      d = vim.Dictionary()
      ned = vim.Dictionary(foo='bar', baz='abcD')
      dl = vim.Dictionary(a=1)
      --- 852,857 ----
      ***************
      *** 1227,1232 ****
      --- 1223,1229 ----
      ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")')
      ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")')
      ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")')
      + ee('vim.eval("xxx_unknown_function_xxx()")')
      ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")')
      del Exe
      EOF
      *** ../vim-7.4.106/src/testdir/test87.ok 2013-11-11 01:05:43.000000000 +0100
      --- src/testdir/test87.ok 2013-11-28 16:41:01.000000000 +0100
      ***************
      *** 53,60 ****
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
      ! Vim(py3):E725:
      ! Vim(py3):E117:
      [0.0, 0.0]
      KeyError
      TypeError
      --- 53,60 ----
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
      [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']
      ! l[1](1, 2, 3):(<class 'vim.error'>, error('Vim:E725: Calling dict function without Dictionary: DictNew',))
      ! f(1, 2, 3):(<class 'vim.error'>, error('Vim:E117: Unknown function: New',))
      [0.0, 0.0]
      KeyError
      TypeError
      ***************
      *** 1186,1191 ****
      --- 1186,1192 ----
      vim.eval("Exe('throw ''ghi''')"):(<class 'vim.error'>, error('ghi',))
      vim.eval("Exe('echoerr ''jkl''')"):(<class 'vim.error'>, error('Vim(echoerr):jkl',))
      vim.eval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
      + vim.eval("xxx_unknown_function_xxx()"):(<class 'vim.error'>, error('Vim:E117: Unknown function: xxx_unknown_function_xxx',))
      vim.bindeval("Exe('xxx_non_existent_command_xxx')"):(<class 'vim.error'>, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',))
      Caught KeyboardInterrupt
      Running :put
      *** ../vim-7.4.106/src/version.c 2013-11-28 16:32:34.000000000 +0100
      --- src/version.c 2013-11-28 16:41:43.000000000 +0100
      ***************
      *** 740,741 ****
      --- 740,743 ----
      { /* Add new patch number below this line */
      + /**/
      + 107,
      /**/

      --
      hundred-and-one symptoms of being an internet addict:
      8. You spend half of the plane trip with your laptop on your lap...and your
      child in the overhead compartment.

      /// Bram Moolenaar -- Bram@... -- http://www.Moolenaar.net \\\
      /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
      \\\ an exciting new programming language -- http://www.Zimbu.org ///
      \\\ 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 vim_dev+unsubscribe@....
      For more options, visit https://groups.google.com/groups/opt_out.
    Your message has been successfully submitted and would be delivered to recipients shortly.