To: vim_dev@googlegroups.com
Subject: Patch 7.3.490
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
------------

Patch 7.3.490
Problem:    Member confusion in Lua interface.
Solution:   Fix it.  Add luaeval(). (Taro Muraoka, Luis Carvalho)
Files:	    runtime/doc/if_lua.txt, src/eval.c, src/if_lua.c,
	    src/proto/if_lua.pro


*** ../vim-7.3.489/runtime/doc/if_lua.txt	2010-08-15 21:57:14.000000000 +0200
--- runtime/doc/if_lua.txt	2012-04-05 16:41:35.000000000 +0200
***************
*** 1,4 ****
! *if_lua.txt*    For Vim version 7.3.  Last change: 2010 Jul 22
  
  
  		  VIM REFERENCE MANUAL    by Luis Carvalho
--- 1,4 ----
! *if_lua.txt*    For Vim version 7.3.  Last change: 2012 Jan 16
  
  
  		  VIM REFERENCE MANUAL    by Luis Carvalho
***************
*** 8,15 ****
  
  1. Commands			|lua-commands|
  2. The vim module		|lua-vim|
! 3. Buffer userdata		|lua-buffer|
! 4. Window userdata		|lua-window|
  
  {Vi does not have any of these commands}
  
--- 8,18 ----
  
  1. Commands			|lua-commands|
  2. The vim module		|lua-vim|
! 3. List userdata		|lua-list|
! 4. Dict userdata		|lua-dict|
! 5. Buffer userdata		|lua-buffer|
! 6. Window userdata		|lua-window|
! 7. The luaeval function		|lua-luaeval|
  
  {Vi does not have any of these commands}
  
***************
*** 88,98 ****
  All these commands execute a Lua chunk from either the command line (:lua and
  :luado) or a file (:luafile) with the given line [range]. Similarly to the Lua
  interpreter, each chunk has its own scope and so only global variables are
! shared between command calls. Lua default libraries "table", "string", "math",
! and "package" are available, "io" and "debug" are not, and "os" is restricted
! to functions "date", "clock", "time", "difftime", and "getenv". In addition,
! Lua "print" function has its output redirected to the Vim message area, with
! arguments separated by a white space instead of a tab.
  
  Lua uses the "vim" module (see |lua-vim|) to issue commands to Vim
  and manage buffers (|lua-buffer|) and windows (|lua-window|). However,
--- 91,99 ----
  All these commands execute a Lua chunk from either the command line (:lua and
  :luado) or a file (:luafile) with the given line [range]. Similarly to the Lua
  interpreter, each chunk has its own scope and so only global variables are
! shared between command calls. All Lua default libraries are available. In
! addition, Lua "print" function has its output redirected to the Vim message
! area, with arguments separated by a white space instead of a tab.
  
  Lua uses the "vim" module (see |lua-vim|) to issue commands to Vim
  and manage buffers (|lua-buffer|) and windows (|lua-window|). However,
***************
*** 108,116 ****
  module also includes routines for buffer, window, and current line queries,
  Vim evaluation and command execution, and others.
  
! 	vim.isbuffer(value)	Returns 'true' (boolean, not string) if
! 				"value" is a buffer userdata and 'false'
! 				otherwise (see |lua-buffer|).
  
  	vim.buffer([arg])	If "arg" is a number, returns buffer with
  				number "arg" in the buffer list or, if "arg"
--- 109,117 ----
  module also includes routines for buffer, window, and current line queries,
  Vim evaluation and command execution, and others.
  
! 	vim.list()		Returns an empty list (see |List|).
! 
! 	vim.dict()		Returns an empty dictionary (see |Dictionary|).
  
  	vim.buffer([arg])	If "arg" is a number, returns buffer with
  				number "arg" in the buffer list or, if "arg"
***************
*** 121,136 ****
  				'true' returns the first buffer in the buffer
  				list or else the current buffer.
  
- 	vim.iswindow(value)	Returns 'true' (boolean, not string) if
- 				"value" is a window userdata and
- 				'false' otherwise (see |lua-window|).
- 
  	vim.window([arg])	If "arg" is a number, returns window with
  				number "arg" or 'nil' (nil value, not string)
  				if not found. Otherwise, if "toboolean(arg)"
  				is 'true' returns the first window or else the
  				current window.
  
  	vim.command({cmd})	Executes the vim (ex-mode) command {cmd}.
  				Examples: >
  					:lua vim.command"set tw=60"
--- 122,142 ----
  				'true' returns the first buffer in the buffer
  				list or else the current buffer.
  
  	vim.window([arg])	If "arg" is a number, returns window with
  				number "arg" or 'nil' (nil value, not string)
  				if not found. Otherwise, if "toboolean(arg)"
  				is 'true' returns the first window or else the
  				current window.
  
+ 	vim.type({arg})		Returns the type of {arg}. It is equivalent to
+ 				Lua's "type" function, but returns "list",
+ 				"dict", "buffer", or "window" if {arg} is a
+ 				list, dictionary, buffer, or window,
+ 				respectively. Examples: >
+ 					:lua l = vim.list()
+ 					:lua print(type(l), vim.type(l))
+ 					:" userdata list
+ <
  	vim.command({cmd})	Executes the vim (ex-mode) command {cmd}.
  				Examples: >
  					:lua vim.command"set tw=60"
***************
*** 141,147 ****
  				Vim strings and numbers are directly converted
  				to Lua strings and numbers respectively. Vim
  				lists and dictionaries are converted to Lua
! 				tables (lists become integer-keyed tables).
  				Examples: >
  					:lua tw = vim.eval"&tw"
  					:lua print(vim.eval"{'a': 'one'}".a)
--- 147,153 ----
  				Vim strings and numbers are directly converted
  				to Lua strings and numbers respectively. Vim
  				lists and dictionaries are converted to Lua
! 				userdata (see |lua-list| and |lua-dict|).
  				Examples: >
  					:lua tw = vim.eval"&tw"
  					:lua print(vim.eval"{'a': 'one'}".a)
***************
*** 157,163 ****
  
  
  ==============================================================================
! 3. Buffer userdata					*lua-buffer*
  
  Buffer userdata represent vim buffers. A buffer userdata "b" has the following
  properties and methods:
--- 163,234 ----
  
  
  ==============================================================================
! 3. List userdata					*lua-list*
! 
! List userdata represent vim lists, and the interface tries to follow closely
! Vim's syntax for lists. Since lists are objects, changes in list references in
! Lua are reflected in Vim and vice-versa. A list "l" has the following
! properties and methods:
! 
! Properties
! ----------
! 	o "#l" is the number of items in list "l", equivalent to "len(l)"
! 	    in Vim.
! 	o "l[k]" returns the k-th item in "l"; "l" is zero-indexed, as in Vim.
! 	    To modify the k-th item, simply do "l[k] = newitem"; in
! 	    particular, "l[k] = nil" removes the k-th item from "l".
! 	o "l()" returns an iterator for "l".
! 
! Methods
! -------
! 	o "l:add(item)" appends "item" to the end of "l".
! 	o "l:insert(item[, pos])" inserts "item" at (optional)
! 	    position "pos" in the list. The default value for "pos" is 0.
! 
! Examples:
! >
! 	:let l = [1, 'item']
! 	:lua l = vim.eval('l') -- same 'l'
! 	:lua l:add(vim.list())
! 	:lua l[0] = math.pi
! 	:echo l[0] " 3.141593
! 	:lua l[0] = nil -- remove first item
! 	:lua l:insert(true, 1)
! 	:lua print(l, #l, l[0], l[1], l[-1])
! 	:lua for item in l() do print(item) end
! <
! 
! ==============================================================================
! 4. Dict userdata					*lua-dict*
! 
! Similarly to list userdata, dict userdata represent vim dictionaries; since
! dictionaries are also objects, references are kept between Lua and Vim. A dict
! "d" has the following properties:
! 
! Properties
! ----------
! 	o "#d" is the number of items in dict "d", equivalent to "len(d)"
! 	    in Vim.
! 	o "d.key" or "d['key']" returns the value at entry "key" in "d".
! 	    To modify the entry at this key, simply do "d.key = newvalue"; in
! 	    particular, "d.key = nil" removes the entry from "d".
! 	o "d()" returns an iterator for "d" and is equivalent to "items(d)" in
! 	    Vim.
! 
! Examples:
! >
! 	:let d = {'n':10}
! 	:lua d = vim.eval('d') -- same 'd'
! 	:lua print(d, d.n, #d)
! 	:let d.self = d
! 	:lua for k, v in d() do print(d, k, v) end
! 	:lua d.x = math.pi
! 	:lua d.self = nil -- remove entry
! 	:echo d
! <
! 
! ==============================================================================
! 5. Buffer userdata					*lua-buffer*
  
  Buffer userdata represent vim buffers. A buffer userdata "b" has the following
  properties and methods:
***************
*** 209,215 ****
  <
  
  ==============================================================================
! 4. Window userdata					*lua-window*
  
  Window objects represent vim windows. A window userdata "w" has the following
  properties and methods:
--- 280,286 ----
  <
  
  ==============================================================================
! 6. Window userdata					*lua-window*
  
  Window objects represent vim windows. A window userdata "w" has the following
  properties and methods:
***************
*** 241,244 ****
  <
  
  ==============================================================================
!  vim:tw=78:ts=8:ft=help:norl:
--- 312,340 ----
  <
  
  ==============================================================================
! 7. The luaeval function					*lua-luaeval*
! 
! The (dual) equivalent of "vim.eval" for passing Lua values to Vim is
! "luaeval". "luaeval" takes an expression string and an optional argument and
! returns the result of the expression. It is semantically equivalent in Lua to:
! >
! 	local chunkheader = "local _A = select(1, ...) return "
! 	function luaeval (expstr, arg)
! 	    local chunk = assert(loadstring(chunkheader .. expstr, "luaeval"))
! 	    return chunk(arg) -- return typval
! 	end
! <
! Note that "_A" receives the argument to "luaeval". Examples: >
! 
! 	:echo luaeval('math.pi')
! 	:lua a = vim.list():add('newlist')
! 	:let a = luaeval('a')
! 	:echo a[0] " 'newlist'
! 	:function Rand(x,y) " random uniform between x and y
! 	:  return luaeval('(_A.y-_A.x)*math.random()+_A.x', {'x':a:x,'y':a:y})
! 	:  endfunction
! 	:echo Rand(1,10)
! 
! 
! ==============================================================================
!  vim:tw=78:ts=8:noet:ft=help:norl:
*** ../vim-7.3.489/src/eval.c	2012-03-28 16:49:25.000000000 +0200
--- src/eval.c	2012-04-05 16:41:35.000000000 +0200
***************
*** 622,627 ****
--- 622,630 ----
  static void f_log __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_log10 __ARGS((typval_T *argvars, typval_T *rettv));
  #endif
+ #ifdef FEAT_LUA
+ static void f_luaeval __ARGS((typval_T *argvars, typval_T *rettv));
+ #endif
  static void f_map __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv));
***************
*** 6777,6782 ****
--- 6780,6789 ----
      /* v: vars */
      set_ref_in_ht(&vimvarht, copyID);
  
+ #ifdef FEAT_LUA
+     set_ref_in_lua(copyID);
+ #endif
+ 
      /*
       * 2. Free lists and dictionaries that are not referenced.
       */
***************
*** 7946,7951 ****
--- 7953,7961 ----
      {"log",		1, 1, f_log},
      {"log10",		1, 1, f_log10},
  #endif
+ #ifdef FEAT_LUA
+     {"luaeval",         1, 2, f_luaeval},
+ #endif
      {"map",		2, 2, f_map},
      {"maparg",		1, 4, f_maparg},
      {"mapcheck",	1, 3, f_mapcheck},
***************
*** 13626,13631 ****
--- 13636,13658 ----
  }
  #endif
  
+ #ifdef FEAT_LUA
+ /*
+  * "luaeval()" function
+  */
+     static void
+ f_luaeval(argvars, rettv)
+     typval_T	*argvars;
+     typval_T	*rettv;
+ {
+     char_u	*str;
+     char_u	buf[NUMBUFLEN];
+ 
+     str = get_tv_string_buf(&argvars[0], buf);
+     do_luaeval(str, argvars + 1, rettv);
+ }
+ #endif
+ 
  /*
   * "map()" function
   */
*** ../vim-7.3.489/src/if_lua.c	2011-12-08 16:00:12.000000000 +0100
--- src/if_lua.c	2012-04-05 16:41:35.000000000 +0200
***************
*** 1,4 ****
! /* vi:set ts=8 sts=4 sw=4:
   *
   * VIM - Vi IMproved	by Bram Moolenaar
   *
--- 1,4 ----
! /* vi:set ts=8 sts=4 sw=4 noet:
   *
   * VIM - Vi IMproved	by Bram Moolenaar
   *
***************
*** 21,35 ****
--- 21,53 ----
  
  #define LUAVIM_CHUNKNAME "vim chunk"
  #define LUAVIM_NAME "vim"
+ #define LUAVIM_EVALNAME "luaeval"
+ #define LUAVIM_EVALHEADER "local _A=select(1,...) return "
  
  typedef buf_T *luaV_Buffer;
  typedef win_T *luaV_Window;
+ typedef dict_T *luaV_Dict;
+ typedef list_T *luaV_List;
  typedef void (*msgfunc_T)(char_u *);
  
+ static const char LUAVIM_DICT[] = "dict";
+ static const char LUAVIM_LIST[] = "list";
  static const char LUAVIM_BUFFER[] = "buffer";
  static const char LUAVIM_WINDOW[] = "window";
  static const char LUAVIM_FREE[] = "luaV_free";
+ static const char LUAVIM_LUAEVAL[] = "luaV_luaeval";
+ static const char LUAVIM_SETREF[] = "luaV_setref";
  
+ /* most functions are closures with a cache table as first upvalue;
+  * get/setudata manage references to vim userdata in cache table through
+  * object pointers (light userdata) */
+ #define luaV_getudata(L, v) \
+     lua_pushlightuserdata((L), (void *) (v)); \
+     lua_rawget((L), lua_upvalueindex(1))
+ #define luaV_setudata(L, v) \
+     lua_pushlightuserdata((L), (void *) (v)); \
+     lua_pushvalue((L), -2); \
+     lua_rawset((L), lua_upvalueindex(1))
  #define luaV_getfield(L, s) \
      lua_pushlightuserdata((L), (void *)(s)); \
      lua_rawget((L), LUA_REGISTRYINDEX)
***************
*** 38,43 ****
--- 56,70 ----
  #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg)
  #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg)
  
+ static luaV_List *luaV_pushlist (lua_State *L, list_T *lis);
+ static luaV_Dict *luaV_pushdict (lua_State *L, dict_T *dic);
+ 
+ #if LUA_VERSION_NUM <= 501
+ #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
+ #define luaL_typeerror luaL_typerror
+ #else
+ #define luaV_openlib luaL_setfuncs
+ #endif
  
  #ifdef DYNAMIC_LUA
  
***************
*** 54,85 ****
  #endif
  
  /* lauxlib */
  #define luaL_register dll_luaL_register
  #define luaL_typerror dll_luaL_typerror
  #define luaL_checklstring dll_luaL_checklstring
  #define luaL_checkinteger dll_luaL_checkinteger
  #define luaL_optinteger dll_luaL_optinteger
  #define luaL_checktype dll_luaL_checktype
  #define luaL_error dll_luaL_error
- #define luaL_loadfile dll_luaL_loadfile
- #define luaL_loadbuffer dll_luaL_loadbuffer
  #define luaL_newstate dll_luaL_newstate
  #define luaL_buffinit dll_luaL_buffinit
- #define luaL_prepbuffer dll_luaL_prepbuffer
  #define luaL_addlstring dll_luaL_addlstring
  #define luaL_pushresult dll_luaL_pushresult
  /* lua */
  #define lua_close dll_lua_close
  #define lua_gettop dll_lua_gettop
  #define lua_settop dll_lua_settop
  #define lua_pushvalue dll_lua_pushvalue
  #define lua_replace dll_lua_replace
  #define lua_isnumber dll_lua_isnumber
  #define lua_isstring dll_lua_isstring
  #define lua_type dll_lua_type
  #define lua_rawequal dll_lua_rawequal
- #define lua_tonumber dll_lua_tonumber
- #define lua_tointeger dll_lua_tointeger
  #define lua_toboolean dll_lua_toboolean
  #define lua_tolstring dll_lua_tolstring
  #define lua_touserdata dll_lua_touserdata
--- 81,134 ----
  #endif
  
  /* lauxlib */
+ #if LUA_VERSION_NUM <= 501
  #define luaL_register dll_luaL_register
+ #define luaL_prepbuffer dll_luaL_prepbuffer
+ #define luaL_openlib dll_luaL_openlib
  #define luaL_typerror dll_luaL_typerror
+ #define luaL_loadfile dll_luaL_loadfile
+ #define luaL_loadbuffer dll_luaL_loadbuffer
+ #else
+ #define luaL_prepbuffsize dll_luaL_prepbuffsize
+ #define luaL_setfuncs dll_luaL_setfuncs
+ #define luaL_loadfilex dll_luaL_loadfilex
+ #define luaL_loadbufferx dll_luaL_loadbufferx
+ #define luaL_argerror dll_luaL_argerror
+ #endif
  #define luaL_checklstring dll_luaL_checklstring
  #define luaL_checkinteger dll_luaL_checkinteger
  #define luaL_optinteger dll_luaL_optinteger
  #define luaL_checktype dll_luaL_checktype
  #define luaL_error dll_luaL_error
  #define luaL_newstate dll_luaL_newstate
  #define luaL_buffinit dll_luaL_buffinit
  #define luaL_addlstring dll_luaL_addlstring
  #define luaL_pushresult dll_luaL_pushresult
  /* lua */
+ #if LUA_VERSION_NUM <= 501
+ #define lua_tonumber dll_lua_tonumber
+ #define lua_tointeger dll_lua_tointeger
+ #define lua_call dll_lua_call
+ #define lua_pcall dll_lua_pcall
+ #else
+ #define lua_tonumberx dll_lua_tonumberx
+ #define lua_tointegerx dll_lua_tointegerx
+ #define lua_callk dll_lua_callk
+ #define lua_pcallk dll_lua_pcallk
+ #define lua_getglobal dll_lua_getglobal
+ #define lua_setglobal dll_lua_setglobal
+ #define lua_typename dll_lua_typename
+ #endif
  #define lua_close dll_lua_close
  #define lua_gettop dll_lua_gettop
  #define lua_settop dll_lua_settop
  #define lua_pushvalue dll_lua_pushvalue
  #define lua_replace dll_lua_replace
+ #define lua_remove dll_lua_remove
  #define lua_isnumber dll_lua_isnumber
  #define lua_isstring dll_lua_isstring
  #define lua_type dll_lua_type
  #define lua_rawequal dll_lua_rawequal
  #define lua_toboolean dll_lua_toboolean
  #define lua_tolstring dll_lua_tolstring
  #define lua_touserdata dll_lua_touserdata
***************
*** 94,109 ****
  #define lua_pushlightuserdata dll_lua_pushlightuserdata
  #define lua_getfield dll_lua_getfield
  #define lua_rawget dll_lua_rawget
  #define lua_createtable dll_lua_createtable
  #define lua_newuserdata dll_lua_newuserdata
  #define lua_getmetatable dll_lua_getmetatable
  #define lua_setfield dll_lua_setfield
  #define lua_rawset dll_lua_rawset
  #define lua_rawseti dll_lua_rawseti
- #define lua_remove dll_lua_remove
  #define lua_setmetatable dll_lua_setmetatable
- #define lua_call dll_lua_call
- #define lua_pcall dll_lua_pcall
  /* libs */
  #define luaopen_base dll_luaopen_base
  #define luaopen_table dll_luaopen_table
--- 143,156 ----
  #define lua_pushlightuserdata dll_lua_pushlightuserdata
  #define lua_getfield dll_lua_getfield
  #define lua_rawget dll_lua_rawget
+ #define lua_rawgeti dll_lua_rawgeti
  #define lua_createtable dll_lua_createtable
  #define lua_newuserdata dll_lua_newuserdata
  #define lua_getmetatable dll_lua_getmetatable
  #define lua_setfield dll_lua_setfield
  #define lua_rawset dll_lua_rawset
  #define lua_rawseti dll_lua_rawseti
  #define lua_setmetatable dll_lua_setmetatable
  /* libs */
  #define luaopen_base dll_luaopen_base
  #define luaopen_table dll_luaopen_table
***************
*** 116,147 ****
  #define luaL_openlibs dll_luaL_openlibs
  
  /* lauxlib */
  void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
  int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
  const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
  lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
  lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
  void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
  int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
- int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
- int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
  lua_State *(*dll_luaL_newstate) (void);
  void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
- char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
  void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
  void (*dll_luaL_pushresult) (luaL_Buffer *B);
  /* lua */
  void       (*dll_lua_close) (lua_State *L);
  int (*dll_lua_gettop) (lua_State *L);
  void (*dll_lua_settop) (lua_State *L, int idx);
  void (*dll_lua_pushvalue) (lua_State *L, int idx);
  void (*dll_lua_replace) (lua_State *L, int idx);
  int (*dll_lua_isnumber) (lua_State *L, int idx);
  int (*dll_lua_isstring) (lua_State *L, int idx);
  int (*dll_lua_type) (lua_State *L, int idx);
  int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
- lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
- lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
  int (*dll_lua_toboolean) (lua_State *L, int idx);
  const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
  void *(*dll_lua_touserdata) (lua_State *L, int idx);
--- 163,218 ----
  #define luaL_openlibs dll_luaL_openlibs
  
  /* lauxlib */
+ #if LUA_VERSION_NUM <= 501
  void (*dll_luaL_register) (lua_State *L, const char *libname, const luaL_Reg *l);
+ char *(*dll_luaL_prepbuffer) (luaL_Buffer *B);
+ void (*dll_luaL_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup);
  int (*dll_luaL_typerror) (lua_State *L, int narg, const char *tname);
+ int (*dll_luaL_loadfile) (lua_State *L, const char *filename);
+ int (*dll_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name);
+ #else
+ char *(*dll_luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+ void (*dll_luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+ int (*dll_luaL_loadfilex) (lua_State *L, const char *filename, const char *mode);
+ int (*dll_luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
+ int (*dll_luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
+ #endif
  const char *(*dll_luaL_checklstring) (lua_State *L, int numArg, size_t *l);
  lua_Integer (*dll_luaL_checkinteger) (lua_State *L, int numArg);
  lua_Integer (*dll_luaL_optinteger) (lua_State *L, int nArg, lua_Integer def);
  void (*dll_luaL_checktype) (lua_State *L, int narg, int t);
  int (*dll_luaL_error) (lua_State *L, const char *fmt, ...);
  lua_State *(*dll_luaL_newstate) (void);
  void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B);
  void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
  void (*dll_luaL_pushresult) (luaL_Buffer *B);
  /* lua */
+ #if LUA_VERSION_NUM <= 501
+ lua_Number (*dll_lua_tonumber) (lua_State *L, int idx);
+ lua_Integer (*dll_lua_tointeger) (lua_State *L, int idx);
+ void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
+ int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
+ #else
+ lua_Number (*dll_lua_tonumberx) (lua_State *L, int idx, int *isnum);
+ lua_Integer (*dll_lua_tointegerx) (lua_State *L, int idx, int *isnum);
+ void (*dll_lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
+         lua_CFunction k);
+ int (*dll_lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+         int ctx, lua_CFunction k);
+ void (*dll_lua_getglobal) (lua_State *L, const char *var);
+ void (*dll_lua_setglobal) (lua_State *L, const char *var);
+ const char *(*dll_lua_typename) (lua_State *L, int tp);
+ #endif
  void       (*dll_lua_close) (lua_State *L);
  int (*dll_lua_gettop) (lua_State *L);
  void (*dll_lua_settop) (lua_State *L, int idx);
  void (*dll_lua_pushvalue) (lua_State *L, int idx);
  void (*dll_lua_replace) (lua_State *L, int idx);
+ void (*dll_lua_remove) (lua_State *L, int idx);
  int (*dll_lua_isnumber) (lua_State *L, int idx);
  int (*dll_lua_isstring) (lua_State *L, int idx);
  int (*dll_lua_type) (lua_State *L, int idx);
  int (*dll_lua_rawequal) (lua_State *L, int idx1, int idx2);
  int (*dll_lua_toboolean) (lua_State *L, int idx);
  const char *(*dll_lua_tolstring) (lua_State *L, int idx, size_t *len);
  void *(*dll_lua_touserdata) (lua_State *L, int idx);
***************
*** 156,171 ****
  void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
  void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
  void (*dll_lua_rawget) (lua_State *L, int idx);
  void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
  void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
  int (*dll_lua_getmetatable) (lua_State *L, int objindex);
  void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
  void (*dll_lua_rawset) (lua_State *L, int idx);
  void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
- void (*dll_lua_remove) (lua_State *L, int idx);
  int (*dll_lua_setmetatable) (lua_State *L, int objindex);
- void (*dll_lua_call) (lua_State *L, int nargs, int nresults);
- int (*dll_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
  /* libs */
  int (*dll_luaopen_base) (lua_State *L);
  int (*dll_luaopen_table) (lua_State *L);
--- 227,240 ----
  void (*dll_lua_pushlightuserdata) (lua_State *L, void *p);
  void (*dll_lua_getfield) (lua_State *L, int idx, const char *k);
  void (*dll_lua_rawget) (lua_State *L, int idx);
+ void (*dll_lua_rawgeti) (lua_State *L, int idx, int n);
  void (*dll_lua_createtable) (lua_State *L, int narr, int nrec);
  void *(*dll_lua_newuserdata) (lua_State *L, size_t sz);
  int (*dll_lua_getmetatable) (lua_State *L, int objindex);
  void (*dll_lua_setfield) (lua_State *L, int idx, const char *k);
  void (*dll_lua_rawset) (lua_State *L, int idx);
  void (*dll_lua_rawseti) (lua_State *L, int idx, int n);
  int (*dll_lua_setmetatable) (lua_State *L, int objindex);
  /* libs */
  int (*dll_luaopen_base) (lua_State *L);
  int (*dll_luaopen_table) (lua_State *L);
***************
*** 185,216 ****
  
  static const luaV_Reg luaV_dll[] = {
      /* lauxlib */
      {"luaL_register", (luaV_function) &dll_luaL_register},
      {"luaL_typerror", (luaV_function) &dll_luaL_typerror},
      {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring},
      {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger},
      {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger},
      {"luaL_checktype", (luaV_function) &dll_luaL_checktype},
      {"luaL_error", (luaV_function) &dll_luaL_error},
-     {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile},
-     {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer},
      {"luaL_newstate", (luaV_function) &dll_luaL_newstate},
      {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit},
-     {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer},
      {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring},
      {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult},
      /* lua */
      {"lua_close", (luaV_function) &dll_lua_close},
      {"lua_gettop", (luaV_function) &dll_lua_gettop},
      {"lua_settop", (luaV_function) &dll_lua_settop},
      {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue},
      {"lua_replace", (luaV_function) &dll_lua_replace},
      {"lua_isnumber", (luaV_function) &dll_lua_isnumber},
      {"lua_isstring", (luaV_function) &dll_lua_isstring},
      {"lua_type", (luaV_function) &dll_lua_type},
      {"lua_rawequal", (luaV_function) &dll_lua_rawequal},
-     {"lua_tonumber", (luaV_function) &dll_lua_tonumber},
-     {"lua_tointeger", (luaV_function) &dll_lua_tointeger},
      {"lua_toboolean", (luaV_function) &dll_lua_toboolean},
      {"lua_tolstring", (luaV_function) &dll_lua_tolstring},
      {"lua_touserdata", (luaV_function) &dll_lua_touserdata},
--- 254,307 ----
  
  static const luaV_Reg luaV_dll[] = {
      /* lauxlib */
+ #if LUA_VERSION_NUM <= 501
      {"luaL_register", (luaV_function) &dll_luaL_register},
+     {"luaL_prepbuffer", (luaV_function) &dll_luaL_prepbuffer},
+     {"luaL_openlib", (luaV_function) &dll_luaL_openlib},
      {"luaL_typerror", (luaV_function) &dll_luaL_typerror},
+     {"luaL_loadfile", (luaV_function) &dll_luaL_loadfile},
+     {"luaL_loadbuffer", (luaV_function) &dll_luaL_loadbuffer},
+ #else
+     {"luaL_prepbuffsize", (luaV_function) &dll_luaL_prepbuffsize},
+     {"luaL_setfuncs", (luaV_function) &dll_luaL_setfuncs},
+     {"luaL_loadfilex", (luaV_function) &dll_luaL_loadfilex},
+     {"luaL_loadbufferx", (luaV_function) &dll_luaL_loadbufferx},
+     {"luaL_argerror", (luaV_function) &dll_luaL_argerror},
+ #endif
      {"luaL_checklstring", (luaV_function) &dll_luaL_checklstring},
      {"luaL_checkinteger", (luaV_function) &dll_luaL_checkinteger},
      {"luaL_optinteger", (luaV_function) &dll_luaL_optinteger},
      {"luaL_checktype", (luaV_function) &dll_luaL_checktype},
      {"luaL_error", (luaV_function) &dll_luaL_error},
      {"luaL_newstate", (luaV_function) &dll_luaL_newstate},
      {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit},
      {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring},
      {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult},
      /* lua */
+ #if LUA_VERSION_NUM <= 501
+     {"lua_tonumber", (luaV_function) &dll_lua_tonumber},
+     {"lua_tointeger", (luaV_function) &dll_lua_tointeger},
+     {"lua_call", (luaV_function) &dll_lua_call},
+     {"lua_pcall", (luaV_function) &dll_lua_pcall},
+ #else
+     {"lua_tonumberx", (luaV_function) &dll_lua_tonumberx},
+     {"lua_tointegerx", (luaV_function) &dll_lua_tointegerx},
+     {"lua_callk", (luaV_function) &dll_lua_callk},
+     {"lua_pcallk", (luaV_function) &dll_lua_pcallk},
+     {"lua_getglobal", (luaV_function) &dll_lua_getglobal},
+     {"lua_setglobal", (luaV_function) &dll_lua_setglobal},
+     {"lua_typename", (luaV_function) &dll_lua_typename},
+ #endif
      {"lua_close", (luaV_function) &dll_lua_close},
      {"lua_gettop", (luaV_function) &dll_lua_gettop},
      {"lua_settop", (luaV_function) &dll_lua_settop},
      {"lua_pushvalue", (luaV_function) &dll_lua_pushvalue},
      {"lua_replace", (luaV_function) &dll_lua_replace},
+     {"lua_remove", (luaV_function) &dll_lua_remove},
      {"lua_isnumber", (luaV_function) &dll_lua_isnumber},
      {"lua_isstring", (luaV_function) &dll_lua_isstring},
      {"lua_type", (luaV_function) &dll_lua_type},
      {"lua_rawequal", (luaV_function) &dll_lua_rawequal},
      {"lua_toboolean", (luaV_function) &dll_lua_toboolean},
      {"lua_tolstring", (luaV_function) &dll_lua_tolstring},
      {"lua_touserdata", (luaV_function) &dll_lua_touserdata},
***************
*** 225,240 ****
      {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata},
      {"lua_getfield", (luaV_function) &dll_lua_getfield},
      {"lua_rawget", (luaV_function) &dll_lua_rawget},
      {"lua_createtable", (luaV_function) &dll_lua_createtable},
      {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata},
      {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable},
      {"lua_setfield", (luaV_function) &dll_lua_setfield},
      {"lua_rawset", (luaV_function) &dll_lua_rawset},
      {"lua_rawseti", (luaV_function) &dll_lua_rawseti},
-     {"lua_remove", (luaV_function) &dll_lua_remove},
      {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable},
-     {"lua_call", (luaV_function) &dll_lua_call},
-     {"lua_pcall", (luaV_function) &dll_lua_pcall},
      /* libs */
      {"luaopen_base", (luaV_function) &dll_luaopen_base},
      {"luaopen_table", (luaV_function) &dll_luaopen_table},
--- 316,329 ----
      {"lua_pushlightuserdata", (luaV_function) &dll_lua_pushlightuserdata},
      {"lua_getfield", (luaV_function) &dll_lua_getfield},
      {"lua_rawget", (luaV_function) &dll_lua_rawget},
+     {"lua_rawgeti", (luaV_function) &dll_lua_rawgeti},
      {"lua_createtable", (luaV_function) &dll_lua_createtable},
      {"lua_newuserdata", (luaV_function) &dll_lua_newuserdata},
      {"lua_getmetatable", (luaV_function) &dll_lua_getmetatable},
      {"lua_setfield", (luaV_function) &dll_lua_setfield},
      {"lua_rawset", (luaV_function) &dll_lua_rawset},
      {"lua_rawseti", (luaV_function) &dll_lua_rawseti},
      {"lua_setmetatable", (luaV_function) &dll_lua_setmetatable},
      /* libs */
      {"luaopen_base", (luaV_function) &dll_luaopen_base},
      {"luaopen_table", (luaV_function) &dll_luaopen_table},
***************
*** 294,299 ****
--- 383,398 ----
  
  #endif /* DYNAMIC_LUA */
  
+ #if LUA_VERSION_NUM > 501
+     static int
+ luaL_typeerror (lua_State *L, int narg, const char *tname)
+ {
+     const char *msg = lua_pushfstring(L, "%s expected, got %s",
+             tname, luaL_typename(L, narg));
+     return luaL_argerror(L, narg, msg);
+ }
+ #endif
+ 
  
  /* =======   Internal   ======= */
  
***************
*** 327,343 ****
  }
  
      static void *
  luaV_checkudata(lua_State *L, int ud, const char *tname)
  {
      void *p = luaV_toudata(L, ud, tname);
!     if (p == NULL) luaL_typerror(L, ud, tname);
      return p;
  }
  
      static void
  luaV_pushtypval(lua_State *L, typval_T *tv)
  {
!     if (tv == NULL) luaL_error(L, "null type");
      switch (tv->v_type)
      {
  	case VAR_STRING:
--- 426,460 ----
  }
  
      static void *
+ luaV_checkcache(lua_State *L, void *p)
+ {
+     luaV_getudata(L, p);
+     if (lua_isnil(L, -1)) luaL_error(L, "invalid object");
+     lua_pop(L, 1);
+     return p;
+ }
+ 
+ #define luaV_unbox(L,luatyp,ud) (*((luatyp *) lua_touserdata((L),(ud))))
+ 
+ #define luaV_checkvalid(L,luatyp,ud) \
+     luaV_checkcache((L), (void *) luaV_unbox((L),luatyp,(ud)))
+ 
+     static void *
  luaV_checkudata(lua_State *L, int ud, const char *tname)
  {
      void *p = luaV_toudata(L, ud, tname);
!     if (p == NULL) luaL_typeerror(L, ud, tname);
      return p;
  }
  
      static void
  luaV_pushtypval(lua_State *L, typval_T *tv)
  {
!     if (tv == NULL)
!     {
! 	lua_pushnil(L);
! 	return;
!     }
      switch (tv->v_type)
      {
  	case VAR_STRING:
***************
*** 351,418 ****
  	    lua_pushnumber(L, (lua_Number) tv->vval.v_float);
  	    break;
  #endif
! 	case VAR_LIST: {
! 	    list_T *l = tv->vval.v_list;
  
! 	    if (l != NULL)
  	    {
! 		/* check cache */
! 		lua_pushlightuserdata(L, (void *) l);
! 		lua_rawget(L, LUA_ENVIRONINDEX);
! 		if (lua_isnil(L, -1)) /* not interned? */
  		{
! 		    listitem_T *li;
! 		    int n = 0;
! 		    lua_pop(L, 1); /* nil */
! 		    lua_newtable(L);
! 		    lua_pushlightuserdata(L, (void *) l);
! 		    lua_pushvalue(L, -2);
! 		    lua_rawset(L, LUA_ENVIRONINDEX);
! 		    for (li = l->lv_first; li != NULL; li = li->li_next)
! 		    {
! 			luaV_pushtypval(L, &li->li_tv);
! 			lua_rawseti(L, -2, ++n);
! 		    }
  		}
! 	    }
! 	    else lua_pushnil(L);
! 	    break;
! 		       }
! 	case VAR_DICT: {
! 	    dict_T *d = tv->vval.v_dict;
! 
! 	    if (d != NULL)
! 	    {
! 		/* check cache */
! 		lua_pushlightuserdata(L, (void *) d);
! 		lua_rawget(L, LUA_ENVIRONINDEX);
! 		if (lua_isnil(L, -1)) /* not interned? */
  		{
! 		    hashtab_T *ht = &d->dv_hashtab;
! 		    hashitem_T *hi;
! 		    int n = ht->ht_used; /* remaining items */
! 		    lua_pop(L, 1); /* nil */
! 		    lua_newtable(L);
! 		    lua_pushlightuserdata(L, (void *) d);
! 		    lua_pushvalue(L, -2);
! 		    lua_rawset(L, LUA_ENVIRONINDEX);
! 		    for (hi = ht->ht_array; n > 0; hi++)
! 		    {
! 			if (!HASHITEM_EMPTY(hi))
! 			{
! 			    dictitem_T *di = dict_lookup(hi);
! 			    luaV_pushtypval(L, &di->di_tv);
! 			    lua_setfield(L, -2, (char *) hi->hi_key);
! 			    n--;
! 			}
! 		    }
  		}
  	    }
- 	    else lua_pushnil(L);
  	    break;
  	}
  	default:
! 	    luaL_error(L, "invalid type");
      }
  }
  
--- 468,537 ----
  	    lua_pushnumber(L, (lua_Number) tv->vval.v_float);
  	    break;
  #endif
! 	case VAR_LIST:
! 	    luaV_pushlist(L, tv->vval.v_list);
! 	    break;
! 	case VAR_DICT:
! 	    luaV_pushdict(L, tv->vval.v_dict);
! 	    break;
! 	default:
! 	    lua_pushnil(L);
!     }
! }
  
! /* converts lua value at 'pos' to typval 'tv' */
!     static void
! luaV_totypval (lua_State *L, int pos, typval_T *tv)
! {
!     switch(lua_type(L, pos)) {
! 	case LUA_TBOOLEAN:
! 	    tv->v_type = VAR_NUMBER;
! 	    tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos);
! 	    break;
! 	case LUA_TSTRING:
! 	    tv->v_type = VAR_STRING;
! 	    tv->vval.v_string = vim_strsave((char_u *) lua_tostring(L, pos));
! 	    break;
! 	case LUA_TNUMBER:
! #ifdef FEAT_FLOAT
! 	    tv->v_type = VAR_FLOAT;
! 	    tv->vval.v_float = (float_T) lua_tonumber(L, pos);
! #else
! 	    tv->v_type = VAR_NUMBER;
! 	    tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
! #endif
! 	    break;
! 	case LUA_TUSERDATA: {
! 	    void *p = lua_touserdata(L, pos);
! 	    if (lua_getmetatable(L, pos)) /* has metatable? */
  	    {
! 		/* check list */
! 		luaV_getfield(L, LUAVIM_LIST);
! 		if (lua_rawequal(L, -1, -2))
  		{
! 		    tv->v_type = VAR_LIST;
! 		    tv->vval.v_list = *((luaV_List *) p);
! 		    ++tv->vval.v_list->lv_refcount;
! 		    lua_pop(L, 2); /* MTs */
! 		    return;
  		}
! 		/* check dict */
! 		luaV_getfield(L, LUAVIM_DICT);
! 		if (lua_rawequal(L, -1, -3))
  		{
! 		    tv->v_type = VAR_DICT;
! 		    tv->vval.v_dict = *((luaV_Dict *) p);
! 		    ++tv->vval.v_dict->dv_refcount;
! 		    lua_pop(L, 3); /* MTs */
! 		    return;
  		}
+ 		lua_pop(L, 3); /* MTs */
  	    }
  	    break;
  	}
  	default:
! 	    tv->v_type = VAR_NUMBER;
! 	    tv->vval.v_number = 0;
      }
  }
  
***************
*** 481,569 ****
      lua_pop(L, 2); /* original and modified strings */
  }
  
  
! /* =======   Buffer type   ======= */
  
!     static luaV_Buffer *
! luaV_newbuffer(lua_State *L, buf_T *buf)
  {
!     luaV_Buffer *b = (luaV_Buffer *) lua_newuserdata(L, sizeof(luaV_Buffer));
!     *b = buf;
!     lua_pushlightuserdata(L, (void *) buf);
!     lua_pushvalue(L, -2);
!     lua_rawset(L, LUA_ENVIRONINDEX); /* env[buf] = udata */
!     /* to avoid GC, store as key in env */
!     lua_pushvalue(L, -1);
!     lua_pushboolean(L, 1);
!     lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
!     /* set metatable */
!     luaV_getfield(L, LUAVIM_BUFFER);
      lua_setmetatable(L, -2);
!     return b;
  }
  
!     static luaV_Buffer *
! luaV_pushbuffer (lua_State *L, buf_T *buf)
  {
!     luaV_Buffer *b = NULL;
!     if (buf == NULL)
! 	lua_pushnil(L);
!     else {
! 	lua_pushlightuserdata(L, (void *) buf);
! 	lua_rawget(L, LUA_ENVIRONINDEX);
! 	if (lua_isnil(L, -1)) /* not interned? */
  	{
! 	    lua_pop(L, 1);
! 	    b = luaV_newbuffer(L, buf);
  	}
  	else
! 	    b = (luaV_Buffer *) lua_touserdata(L, -1);
      }
!     return b;
  }
  
! /* Buffer metamethods */
  
      static int
! luaV_buffer_tostring(lua_State *L)
  {
!     lua_pushfstring(L, "%s: %p", LUAVIM_BUFFER, lua_touserdata(L, 1));
      return 1;
  }
  
      static int
  luaV_buffer_len(lua_State *L)
  {
!     luaV_Buffer *b = lua_touserdata(L, 1);
!     lua_pushinteger(L, (*b)->b_ml.ml_line_count);
      return 1;
  }
  
      static int
  luaV_buffer_call(lua_State *L)
  {
!     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
      lua_settop(L, 1);
!     set_curbuf(*b, DOBUF_SPLIT);
      return 1;
  }
  
      static int
  luaV_buffer_index(lua_State *L)
  {
!     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
      linenr_T n = (linenr_T) lua_tointeger(L, 2);
!     if (n > 0 && n <= (*b)->b_ml.ml_line_count)
! 	luaV_pushline(L, *b, n);
      else if (lua_isstring(L, 2))
      {
  	const char *s = lua_tostring(L, 2);
  	if (strncmp(s, "name", 4) == 0)
! 	    lua_pushstring(L, (char *) (*b)->b_sfname);
  	else if (strncmp(s, "fname", 5) == 0)
! 	    lua_pushstring(L, (char *) (*b)->b_ffname);
  	else if (strncmp(s, "number", 6) == 0)
! 	    lua_pushinteger(L, (*b)->b_fnum);
  	/* methods */
  	else if (strncmp(s,   "insert", 6) == 0
  		|| strncmp(s, "next", 4) == 0
--- 600,1107 ----
      lua_pop(L, 2); /* original and modified strings */
  }
  
+ #define luaV_newtype(typ,tname,luatyp,luatname) \
+ 	static luatyp * \
+     luaV_new##tname (lua_State *L, typ *obj) \
+     { \
+ 	luatyp *o = (luatyp *) lua_newuserdata(L, sizeof(luatyp)); \
+ 	*o = obj; \
+ 	luaV_setudata(L, obj); /* cache[obj] = udata */ \
+ 	luaV_getfield(L, luatname); \
+ 	lua_setmetatable(L, -2); \
+ 	return o; \
+     }
+ 
+ #define luaV_pushtype(typ,tname,luatyp) \
+ 	static luatyp * \
+     luaV_push##tname (lua_State *L, typ *obj) \
+     { \
+ 	luatyp *o = NULL; \
+ 	if (obj == NULL) \
+ 	    lua_pushnil(L); \
+ 	else { \
+ 	    luaV_getudata(L, obj); \
+ 	    if (lua_isnil(L, -1)) /* not interned? */ \
+ 	    { \
+ 		lua_pop(L, 1); \
+ 		o = luaV_new##tname(L, obj); \
+ 	    } \
+ 	    else \
+ 		o = (luatyp *) lua_touserdata(L, -1); \
+ 	} \
+ 	return o; \
+     }
+ 
+ #define luaV_type_tostring(tname,luatname) \
+ 	static int \
+     luaV_##tname##_tostring (lua_State *L) \
+     { \
+ 	lua_pushfstring(L, "%s: %p", luatname, lua_touserdata(L, 1)); \
+ 	return 1; \
+     }
+ 
  
! /* adapted from eval.c */
! 
! #define listitem_alloc() (listitem_T *)alloc(sizeof(listitem_T))
! 
!     static listitem_T *
! list_find (list_T *l, long n)
! {
!     listitem_T *li;
!     if (l == NULL || n < -l->lv_len || n >= l->lv_len)
! 	return NULL;
!     if (n < 0) /* search backward? */
! 	for (li = l->lv_last; n < -1; li = li->li_prev)
! 	    n++;
!     else /* search forward */
! 	for (li = l->lv_first; n > 0; li = li->li_next)
! 	    n--;
!     return li;
! }
  
!     static void
! list_remove (list_T *l, listitem_T *li)
  {
!     listwatch_T *lw;
!     --l->lv_len;
!     /* fix watchers */
!     for (lw = l->lv_watch; lw != NULL; lw = lw->lw_next)
! 	if (lw->lw_item == li)
! 	    lw->lw_item = li->li_next;
!     /* fix list pointers */
!     if (li->li_next == NULL) /* last? */
! 	l->lv_last = li->li_prev;
!     else
! 	li->li_next->li_prev = li->li_prev;
!     if (li->li_prev == NULL) /* first? */
! 	l->lv_first = li->li_next;
!     else
! 	li->li_prev->li_next = li->li_next;
!     l->lv_idx_item = NULL;
! }
! 
!     static void
! list_append(list_T *l, listitem_T *item)
! {
!     if (l->lv_last == NULL) /* empty list? */
! 	l->lv_first = item;
!     else
! 	l->lv_last->li_next = item;
!     item->li_prev = l->lv_last;
!     item->li_next = NULL;
!     l->lv_last = item;
!     ++l->lv_len;
! }
! 
!     static int
! list_insert_tv(list_T *l, typval_T *tv, listitem_T *item)
! {
!     listitem_T	*ni = listitem_alloc();
! 
!     if (ni == NULL)
! 	return FAIL;
!     copy_tv(tv, &ni->li_tv);
!     if (item == NULL)
! 	list_append(l, ni);
!     else
!     {
! 	ni->li_prev = item->li_prev;
! 	ni->li_next = item;
! 	if (item->li_prev == NULL)
! 	{
! 	    l->lv_first = ni;
! 	    ++l->lv_idx;
! 	}
! 	else
! 	{
! 	    item->li_prev->li_next = ni;
! 	    l->lv_idx_item = NULL;
! 	}
! 	item->li_prev = ni;
! 	++l->lv_len;
!     }
!     return OK;
! }
! 
! /* set references */
! 
! static void set_ref_in_tv (typval_T *tv, int copyID);
! 
!     static void
! set_ref_in_dict(dict_T *d, int copyID)
! {
!     hashtab_T *ht = &d->dv_hashtab;
!     int n = ht->ht_used;
!     hashitem_T *hi;
!     for (hi = ht->ht_array; n > 0; ++hi)
! 	if (!HASHITEM_EMPTY(hi))
! 	{
! 	    dictitem_T *di = dict_lookup(hi);
! 	    set_ref_in_tv(&di->di_tv, copyID);
! 	    --n;
! 	}
! }
! 
!     static void
! set_ref_in_list(list_T *l, int copyID)
! {
!     listitem_T *li;
!     for (li = l->lv_first; li != NULL; li = li->li_next)
! 	set_ref_in_tv(&li->li_tv, copyID);
! }
! 
!     static void
! set_ref_in_tv(typval_T *tv, int copyID)
! {
!     if (tv->v_type == VAR_LIST)
!     {
! 	list_T *l = tv->vval.v_list;
! 	if (l != NULL && l->lv_copyID != copyID)
! 	{
! 	    l->lv_copyID = copyID;
! 	    set_ref_in_list(l, copyID);
! 	}
!     }
!     else if (tv->v_type == VAR_DICT)
!     {
! 	dict_T *d = tv->vval.v_dict;
! 	if (d != NULL && d->dv_copyID != copyID)
! 	{
! 	    d->dv_copyID = copyID;
! 	    set_ref_in_dict(d, copyID);
! 	}
!     }
! }
! 
! 
! /* =======   List type   ======= */
! 
!     static luaV_List *
! luaV_newlist (lua_State *L, list_T *lis)
! {
!     luaV_List *l = (luaV_List *) lua_newuserdata(L, sizeof(luaV_List));
!     *l = lis;
!     lis->lv_refcount++; /* reference in Lua */
!     luaV_setudata(L, lis); /* cache[lis] = udata */
!     luaV_getfield(L, LUAVIM_LIST);
      lua_setmetatable(L, -2);
!     return l;
  }
  
! luaV_pushtype(list_T, list, luaV_List)
! luaV_type_tostring(list, LUAVIM_LIST)
! 
!     static int
! luaV_list_gc (lua_State *L)
  {
!     list_unref(luaV_unbox(L, luaV_List, 1));
!     return 0;
! }
! 
!     static int
! luaV_list_len (lua_State *L)
! {
!     list_T *l = luaV_unbox(L, luaV_List, 1);
!     lua_pushinteger(L, (l == NULL) ? 0 : (int) l->lv_len);
!     return 1;
! }
! 
!     static int
! luaV_list_iter (lua_State *L)
! {
!     listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2));
!     if (li == NULL) return 0;
!     luaV_pushtypval(L, &li->li_tv);
!     lua_pushlightuserdata(L, (void *) li->li_next);
!     lua_replace(L, lua_upvalueindex(2));
!     return 1;
! }
! 
!     static int
! luaV_list_call (lua_State *L)
! {
!     list_T *l = luaV_unbox(L, luaV_List, 1);
!     lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
!     lua_pushlightuserdata(L, (void *) l->lv_first);
!     lua_pushcclosure(L, luaV_list_iter, 2);
!     return 1;
! }
! 
!     static int
! luaV_list_index (lua_State *L)
! {
!     list_T *l = luaV_unbox(L, luaV_List, 1);
!     if (lua_isnumber(L, 2)) /* list item? */
!     {
! 	listitem_T *li = list_find(l, (long) luaL_checkinteger(L, 2));
! 	if (li == NULL)
! 	    lua_pushnil(L);
! 	else
! 	    luaV_pushtypval(L, &li->li_tv);
!     }
!     else if (lua_isstring(L, 2)) /* method? */
!     {
! 	const char *s = lua_tostring(L, 2);
! 	if (strncmp(s, "add", 3) == 0
! 		|| strncmp(s, "insert", 6) == 0
! 		|| strncmp(s, "extend", 6) == 0)
  	{
! 	    lua_getmetatable(L, 1);
! 	    lua_getfield(L, -1, s);
  	}
  	else
! 	    lua_pushnil(L);
      }
!     else
! 	lua_pushnil(L);
!     return 1;
  }
  
!     static int
! luaV_list_newindex (lua_State *L)
! {
!     list_T *l = luaV_unbox(L, luaV_List, 1);
!     long n = (long) luaL_checkinteger(L, 2);
!     listitem_T *li;
!     if (l->lv_lock)
! 	luaL_error(L, "list is locked");
!     li = list_find(l, n);
!     if (li == NULL) return 0;
!     if (lua_isnil(L, 3)) /* remove? */
!     {
! 	list_remove(l, li);
! 	clear_tv(&li->li_tv);
! 	vim_free(li);
!     }
!     else
!     {
! 	typval_T v;
! 	luaV_totypval(L, 3, &v);
! 	clear_tv(&li->li_tv);
! 	copy_tv(&v, &li->li_tv);
!     }
!     return 0;
! }
  
      static int
! luaV_list_add (lua_State *L)
  {
!     luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
!     list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
!     listitem_T *li;
!     if (l->lv_lock)
! 	luaL_error(L, "list is locked");
!     li = listitem_alloc();
!     if (li != NULL)
!     {
! 	typval_T v;
! 	lua_settop(L, 2);
! 	luaV_totypval(L, 2, &v);
! 	copy_tv(&v, &li->li_tv);
! 	list_append(l, li);
!     }
!     lua_settop(L, 1);
      return 1;
  }
  
      static int
+ luaV_list_insert (lua_State *L)
+ {
+     luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
+     list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
+     long pos = luaL_optlong(L, 3, 0);
+     listitem_T *li = NULL;
+     typval_T v;
+     if (l->lv_lock)
+ 	luaL_error(L, "list is locked");
+     if (pos < l->lv_len)
+     {
+ 	li = list_find(l, pos);
+ 	if (li == NULL)
+ 	    luaL_error(L, "invalid position");
+     }
+     lua_settop(L, 2);
+     luaV_totypval(L, 2, &v);
+     list_insert_tv(l, &v, li);
+     lua_settop(L, 1);
+     return 1;
+ }
+ 
+ static const luaL_Reg luaV_List_mt[] = {
+     {"__tostring", luaV_list_tostring},
+     {"__gc", luaV_list_gc},
+     {"__len", luaV_list_len},
+     {"__call", luaV_list_call},
+     {"__index", luaV_list_index},
+     {"__newindex", luaV_list_newindex},
+     {"add", luaV_list_add},
+     {"insert", luaV_list_insert},
+     {NULL, NULL}
+ };
+ 
+ 
+ /* =======   Dict type   ======= */
+ 
+     static luaV_Dict *
+ luaV_newdict (lua_State *L, dict_T *dic)
+ {
+     luaV_Dict *d = (luaV_Dict *) lua_newuserdata(L, sizeof(luaV_Dict));
+     *d = dic;
+     dic->dv_refcount++; /* reference in Lua */
+     luaV_setudata(L, dic); /* cache[dic] = udata */
+     luaV_getfield(L, LUAVIM_DICT);
+     lua_setmetatable(L, -2);
+     return d;
+ }
+ 
+ luaV_pushtype(dict_T, dict, luaV_Dict)
+ luaV_type_tostring(dict, LUAVIM_DICT)
+ 
+     static int
+ luaV_dict_gc (lua_State *L)
+ {
+     dict_unref(luaV_unbox(L, luaV_Dict, 1));
+     return 0;
+ }
+ 
+     static int
+ luaV_dict_len (lua_State *L)
+ {
+     dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+     lua_pushinteger(L, (d == NULL) ? 0 : (int) d->dv_hashtab.ht_used);
+     return 1;
+ }
+ 
+     static int
+ luaV_dict_iter (lua_State *L)
+ {
+     hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2));
+     int n = lua_tointeger(L, lua_upvalueindex(3));
+     dictitem_T *di;
+     if (n <= 0) return 0;
+     while (HASHITEM_EMPTY(hi)) hi++;
+     di = dict_lookup(hi);
+     lua_pushstring(L, (char *) hi->hi_key);
+     luaV_pushtypval(L, &di->di_tv);
+     lua_pushlightuserdata(L, (void *) (hi + 1));
+     lua_replace(L, lua_upvalueindex(2));
+     lua_pushinteger(L, n - 1);
+     lua_replace(L, lua_upvalueindex(3));
+     return 2;
+ }
+ 
+     static int
+ luaV_dict_call (lua_State *L)
+ {
+     dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+     hashtab_T *ht = &d->dv_hashtab;
+     lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
+     lua_pushlightuserdata(L, (void *) ht->ht_array);
+     lua_pushinteger(L, ht->ht_used); /* # remaining items */
+     lua_pushcclosure(L, luaV_dict_iter, 3);
+     return 1;
+ }
+ 
+     static int
+ luaV_dict_index (lua_State *L)
+ {
+     dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+     char_u *key = (char_u *) luaL_checkstring(L, 2);
+     dictitem_T *di = dict_find(d, key, -1);
+     if (di == NULL)
+ 	lua_pushnil(L);
+     else
+ 	luaV_pushtypval(L, &di->di_tv);
+     return 1;
+ }
+ 
+     static int
+ luaV_dict_newindex (lua_State *L)
+ {
+     dict_T *d = luaV_unbox(L, luaV_Dict, 1);
+     char_u *key = (char_u *) luaL_checkstring(L, 2);
+     dictitem_T *di;
+     if (d->dv_lock)
+ 	luaL_error(L, "dict is locked");
+     di = dict_find(d, key, -1);
+     if (di == NULL) /* non-existing key? */
+     {
+ 	if (lua_isnil(L, 3)) return 0;
+ 	di = dictitem_alloc(key);
+ 	if (di == NULL) return 0;
+ 	if (dict_add(d, di) == FAIL)
+ 	{
+ 		vim_free(di);
+ 		return 0;
+ 	}
+     }
+     else
+ 	clear_tv(&di->di_tv);
+     if (lua_isnil(L, 3)) /* remove? */
+     {
+ 	hashitem_T *hi = hash_find(&d->dv_hashtab, di->di_key);
+ 	hash_remove(&d->dv_hashtab, hi);
+ 	dictitem_free(di);
+     }
+     else {
+ 	typval_T v;
+ 	luaV_totypval(L, 3, &v);
+ 	copy_tv(&v, &di->di_tv);
+     }
+     return 0;
+ }
+ 
+ static const luaL_Reg luaV_Dict_mt[] = {
+     {"__tostring", luaV_dict_tostring},
+     {"__gc", luaV_dict_gc},
+     {"__len", luaV_dict_len},
+     {"__call", luaV_dict_call},
+     {"__index", luaV_dict_index},
+     {"__newindex", luaV_dict_newindex},
+     {NULL, NULL}
+ };
+ 
+ 
+ /* =======   Buffer type   ======= */
+ 
+ luaV_newtype(buf_T, buffer, luaV_Buffer, LUAVIM_BUFFER)
+ luaV_pushtype(buf_T, buffer, luaV_Buffer)
+ luaV_type_tostring(buffer, LUAVIM_BUFFER)
+ 
+     static int
  luaV_buffer_len(lua_State *L)
  {
!     buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
!     lua_pushinteger(L, b->b_ml.ml_line_count);
      return 1;
  }
  
      static int
  luaV_buffer_call(lua_State *L)
  {
!     buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
      lua_settop(L, 1);
!     set_curbuf(b, DOBUF_SPLIT);
      return 1;
  }
  
      static int
  luaV_buffer_index(lua_State *L)
  {
!     buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
      linenr_T n = (linenr_T) lua_tointeger(L, 2);
!     if (n > 0 && n <= b->b_ml.ml_line_count)
! 	luaV_pushline(L, b, n);
      else if (lua_isstring(L, 2))
      {
  	const char *s = lua_tostring(L, 2);
  	if (strncmp(s, "name", 4) == 0)
! 	    lua_pushstring(L, (char *) b->b_sfname);
  	else if (strncmp(s, "fname", 5) == 0)
! 	    lua_pushstring(L, (char *) b->b_ffname);
  	else if (strncmp(s, "number", 6) == 0)
! 	    lua_pushinteger(L, b->b_fnum);
  	/* methods */
  	else if (strncmp(s,   "insert", 6) == 0
  		|| strncmp(s, "next", 4) == 0
***************
*** 584,600 ****
      static int
  luaV_buffer_newindex(lua_State *L)
  {
!     luaV_Buffer *b = (luaV_Buffer *) lua_touserdata(L, 1);
      linenr_T n = (linenr_T) luaL_checkinteger(L, 2);
  #ifdef HAVE_SANDBOX
      luaV_checksandbox(L);
  #endif
!     if (n < 1 || n > (*b)->b_ml.ml_line_count)
  	luaL_error(L, "invalid line number");
      if (lua_isnil(L, 3)) /* delete line */
      {
  	buf_T *buf = curbuf;
! 	curbuf = *b;
  	if (u_savedel(n, 1L) == FAIL)
  	{
  	    curbuf = buf;
--- 1122,1138 ----
      static int
  luaV_buffer_newindex(lua_State *L)
  {
!     buf_T *b = (buf_T *) luaV_checkvalid(L, luaV_Buffer, 1);
      linenr_T n = (linenr_T) luaL_checkinteger(L, 2);
  #ifdef HAVE_SANDBOX
      luaV_checksandbox(L);
  #endif
!     if (n < 1 || n > b->b_ml.ml_line_count)
  	luaL_error(L, "invalid line number");
      if (lua_isnil(L, 3)) /* delete line */
      {
  	buf_T *buf = curbuf;
! 	curbuf = b;
  	if (u_savedel(n, 1L) == FAIL)
  	{
  	    curbuf = buf;
***************
*** 607,613 ****
  	}
  	else {
  	    deleted_lines_mark(n, 1L);
! 	    if (*b == curwin->w_buffer) /* fix cursor in current window? */
  	    {
  		if (curwin->w_cursor.lnum >= n)
  		{
--- 1145,1151 ----
  	}
  	else {
  	    deleted_lines_mark(n, 1L);
! 	    if (b == curwin->w_buffer) /* fix cursor in current window? */
  	    {
  		if (curwin->w_cursor.lnum >= n)
  		{
***************
*** 627,633 ****
      else if (lua_isstring(L, 3)) /* update line */
      {
  	buf_T *buf = curbuf;
! 	curbuf = *b;
  	if (u_savesub(n) == FAIL)
  	{
  	    curbuf = buf;
--- 1165,1171 ----
      else if (lua_isstring(L, 3)) /* update line */
      {
  	buf_T *buf = curbuf;
! 	curbuf = b;
  	if (u_savesub(n) == FAIL)
  	{
  	    curbuf = buf;
***************
*** 640,646 ****
  	}
  	else changed_bytes(n, 0);
  	curbuf = buf;
! 	if (*b == curwin->w_buffer)
  	    check_cursor_col();
      }
      else
--- 1178,1184 ----
  	}
  	else changed_bytes(n, 0);
  	curbuf = buf;
! 	if (b == curwin->w_buffer)
  	    check_cursor_col();
      }
      else
***************
*** 651,658 ****
      static int
  luaV_buffer_insert(lua_State *L)
  {
!     luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     linenr_T last = (*b)->b_ml.ml_line_count;
      linenr_T n = (linenr_T) luaL_optinteger(L, 3, last);
      buf_T *buf;
      luaL_checktype(L, 2, LUA_TSTRING);
--- 1189,1197 ----
      static int
  luaV_buffer_insert(lua_State *L)
  {
!     luaV_Buffer *lb = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     buf_T *b = (buf_T *) luaV_checkcache(L, (void *) *lb);
!     linenr_T last = b->b_ml.ml_line_count;
      linenr_T n = (linenr_T) luaL_optinteger(L, 3, last);
      buf_T *buf;
      luaL_checktype(L, 2, LUA_TSTRING);
***************
*** 664,670 ****
      if (n > last) n = last;
      /* insert */
      buf = curbuf;
!     curbuf = *b;
      if (u_save(n, n + 1) == FAIL)
      {
  	curbuf = buf;
--- 1203,1209 ----
      if (n > last) n = last;
      /* insert */
      buf = curbuf;
!     curbuf = b;
      if (u_save(n, n + 1) == FAIL)
      {
  	curbuf = buf;
***************
*** 686,692 ****
  luaV_buffer_next(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     luaV_pushbuffer(L, (*b)->b_next);
      return 1;
  }
  
--- 1225,1232 ----
  luaV_buffer_next(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     buf_T *buf = (buf_T *) luaV_checkcache(L, (void *) *b);
!     luaV_pushbuffer(L, buf->b_next);
      return 1;
  }
  
***************
*** 694,700 ****
  luaV_buffer_previous(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     luaV_pushbuffer(L, (*b)->b_prev);
      return 1;
  }
  
--- 1234,1241 ----
  luaV_buffer_previous(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     buf_T *buf = (buf_T *) luaV_checkcache(L, (void *) *b);
!     luaV_pushbuffer(L, buf->b_prev);
      return 1;
  }
  
***************
*** 702,709 ****
  luaV_buffer_isvalid(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     lua_pushlightuserdata(L, (void *) (*b));
!     lua_rawget(L, LUA_ENVIRONINDEX);
      lua_pushboolean(L, !lua_isnil(L, -1));
      return 1;
  }
--- 1243,1249 ----
  luaV_buffer_isvalid(lua_State *L)
  {
      luaV_Buffer *b = luaV_checkudata(L, 1, LUAVIM_BUFFER);
!     luaV_getudata(L, *b);
      lua_pushboolean(L, !lua_isnil(L, -1));
      return 1;
  }
***************
*** 724,801 ****
  
  /* =======   Window type   ======= */
  
!     static luaV_Window *
! luaV_newwindow(lua_State *L, win_T *win)
! {
!     luaV_Window *w = (luaV_Window *) lua_newuserdata(L, sizeof(luaV_Window));
!     *w = win;
!     lua_pushlightuserdata(L, (void *) win);
!     lua_pushvalue(L, -2);
!     lua_rawset(L, LUA_ENVIRONINDEX); /* env[win] = udata */
!     /* to avoid GC, store as key in env */
!     lua_pushvalue(L, -1);
!     lua_pushboolean(L, 1);
!     lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = true */
!     /* set metatable */
!     luaV_getfield(L, LUAVIM_WINDOW);
!     lua_setmetatable(L, -2);
!     return w;
! }
! 
!     static luaV_Window *
! luaV_pushwindow(lua_State *L, win_T *win)
! {
!     luaV_Window *w = NULL;
!     if (win == NULL)
! 	lua_pushnil(L);
!     else {
! 	lua_pushlightuserdata(L, (void *) win);
! 	lua_rawget(L, LUA_ENVIRONINDEX);
! 	if (lua_isnil(L, -1)) /* not interned? */
! 	{
! 	    lua_pop(L, 1);
! 	    w = luaV_newwindow(L, win);
! 	}
! 	else w = (luaV_Window *) lua_touserdata(L, -1);
!     }
!     return w;
! }
! 
! /* Window metamethods */
! 
!     static int
! luaV_window_tostring(lua_State *L)
! {
!     lua_pushfstring(L, "%s: %p", LUAVIM_WINDOW, lua_touserdata(L, 1));
!     return 1;
! }
  
      static int
  luaV_window_call(lua_State *L)
  {
!     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
      lua_settop(L, 1);
!     win_goto(*w);
      return 1;
  }
  
      static int
  luaV_window_index(lua_State *L)
  {
!     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
      const char *s = luaL_checkstring(L, 2);
      if (strncmp(s, "buffer", 6) == 0)
! 	luaV_pushbuffer(L, (*w)->w_buffer);
      else if (strncmp(s, "line", 4) == 0)
! 	lua_pushinteger(L, (*w)->w_cursor.lnum);
      else if (strncmp(s, "col", 3) == 0)
! 	lua_pushinteger(L, (*w)->w_cursor.col + 1);
  #ifdef FEAT_VERTSPLIT
      else if (strncmp(s, "width", 5) == 0)
! 	lua_pushinteger(L, W_WIDTH((*w)));
  #endif
      else if (strncmp(s, "height", 6) == 0)
! 	lua_pushinteger(L, (*w)->w_height);
      /* methods */
      else if (strncmp(s,   "next", 4) == 0
  	    || strncmp(s, "previous", 8) == 0
--- 1264,1299 ----
  
  /* =======   Window type   ======= */
  
! luaV_newtype(win_T, window, luaV_Window, LUAVIM_WINDOW)
! luaV_pushtype(win_T, window, luaV_Window)
! luaV_type_tostring(window, LUAVIM_WINDOW)
  
      static int
  luaV_window_call(lua_State *L)
  {
!     win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
      lua_settop(L, 1);
!     win_goto(w);
      return 1;
  }
  
      static int
  luaV_window_index(lua_State *L)
  {
!     win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
      const char *s = luaL_checkstring(L, 2);
      if (strncmp(s, "buffer", 6) == 0)
! 	luaV_pushbuffer(L, w->w_buffer);
      else if (strncmp(s, "line", 4) == 0)
! 	lua_pushinteger(L, w->w_cursor.lnum);
      else if (strncmp(s, "col", 3) == 0)
! 	lua_pushinteger(L, w->w_cursor.col + 1);
  #ifdef FEAT_VERTSPLIT
      else if (strncmp(s, "width", 5) == 0)
! 	lua_pushinteger(L, W_WIDTH(w));
  #endif
      else if (strncmp(s, "height", 6) == 0)
! 	lua_pushinteger(L, w->w_height);
      /* methods */
      else if (strncmp(s,   "next", 4) == 0
  	    || strncmp(s, "previous", 8) == 0
***************
*** 812,818 ****
      static int
  luaV_window_newindex (lua_State *L)
  {
!     luaV_Window *w = (luaV_Window *) lua_touserdata(L, 1);
      const char *s = luaL_checkstring(L, 2);
      int v = luaL_checkinteger(L, 3);
      if (strncmp(s, "line", 4) == 0)
--- 1310,1316 ----
      static int
  luaV_window_newindex (lua_State *L)
  {
!     win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
      const char *s = luaL_checkstring(L, 2);
      int v = luaL_checkinteger(L, 3);
      if (strncmp(s, "line", 4) == 0)
***************
*** 820,828 ****
  #ifdef HAVE_SANDBOX
  	luaV_checksandbox(L);
  #endif
! 	if (v < 1 || v > (*w)->w_buffer->b_ml.ml_line_count)
  	    luaL_error(L, "line out of range");
! 	(*w)->w_cursor.lnum = v;
  	update_screen(VALID);
      }
      else if (strncmp(s, "col", 3) == 0)
--- 1318,1326 ----
  #ifdef HAVE_SANDBOX
  	luaV_checksandbox(L);
  #endif
! 	if (v < 1 || v > w->w_buffer->b_ml.ml_line_count)
  	    luaL_error(L, "line out of range");
! 	w->w_cursor.lnum = v;
  	update_screen(VALID);
      }
      else if (strncmp(s, "col", 3) == 0)
***************
*** 830,836 ****
  #ifdef HAVE_SANDBOX
  	luaV_checksandbox(L);
  #endif
! 	(*w)->w_cursor.col = v - 1;
  	update_screen(VALID);
      }
  #ifdef FEAT_VERTSPLIT
--- 1328,1334 ----
  #ifdef HAVE_SANDBOX
  	luaV_checksandbox(L);
  #endif
! 	w->w_cursor.col = v - 1;
  	update_screen(VALID);
      }
  #ifdef FEAT_VERTSPLIT
***************
*** 840,846 ****
  #ifdef FEAT_GUI
  	need_mouse_correct = TRUE;
  #endif
! 	curwin = *w;
  	win_setwidth(v);
  	curwin = win;
      }
--- 1338,1344 ----
  #ifdef FEAT_GUI
  	need_mouse_correct = TRUE;
  #endif
! 	curwin = w;
  	win_setwidth(v);
  	curwin = win;
      }
***************
*** 851,857 ****
  #ifdef FEAT_GUI
  	need_mouse_correct = TRUE;
  #endif
! 	curwin = *w;
  	win_setheight(v);
  	curwin = win;
      }
--- 1349,1355 ----
  #ifdef FEAT_GUI
  	need_mouse_correct = TRUE;
  #endif
! 	curwin = w;
  	win_setheight(v);
  	curwin = win;
      }
***************
*** 864,870 ****
  luaV_window_next(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     luaV_pushwindow(L, (*w)->w_next);
      return 1;
  }
  
--- 1362,1369 ----
  luaV_window_next(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     win_T *win = (win_T *) luaV_checkcache(L, (void *) *w);
!     luaV_pushwindow(L, win->w_next);
      return 1;
  }
  
***************
*** 872,878 ****
  luaV_window_previous(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     luaV_pushwindow(L, (*w)->w_prev);
      return 1;
  }
  
--- 1371,1378 ----
  luaV_window_previous(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     win_T *win = (win_T *) luaV_checkcache(L, (void *) *w);
!     luaV_pushwindow(L, win->w_prev);
      return 1;
  }
  
***************
*** 880,887 ****
  luaV_window_isvalid(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     lua_pushlightuserdata(L, (void *) (*w));
!     lua_rawget(L, LUA_ENVIRONINDEX);
      lua_pushboolean(L, !lua_isnil(L, -1));
      return 1;
  }
--- 1380,1386 ----
  luaV_window_isvalid(lua_State *L)
  {
      luaV_Window *w = luaV_checkudata(L, 1, LUAVIM_WINDOW);
!     luaV_getudata(L, *w);
      lua_pushboolean(L, !lua_isnil(L, -1));
      return 1;
  }
***************
*** 983,988 ****
--- 1482,1509 ----
  }
  
      static int
+ luaV_list(lua_State *L)
+ {
+     list_T *l = list_alloc();
+     if (l == NULL)
+ 	lua_pushnil(L);
+     else
+ 	luaV_newlist(L, l);
+     return 1;
+ }
+ 
+     static int
+ luaV_dict(lua_State *L)
+ {
+     dict_T *d = dict_alloc();
+     if (d == NULL)
+ 	lua_pushnil(L);
+     else
+ 	luaV_newdict(L, d);
+     return 1;
+ }
+ 
+     static int
  luaV_buffer(lua_State *L)
  {
      buf_T *buf;
***************
*** 1008,1022 ****
  		    break;
  	    }
  	}
- 	if (buf == NULL) /* not found? */
- 	    lua_pushnil(L);
- 	else
- 	    luaV_pushbuffer(L, buf);
      }
!     else {
  	buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
! 	luaV_pushbuffer(L, buf);
!     }
      return 1;
  }
  
--- 1529,1538 ----
  		    break;
  	    }
  	}
      }
!     else
  	buf = (lua_toboolean(L, 1)) ? firstbuf : curbuf; /* first buffer? */
!     luaV_pushbuffer(L, buf);
      return 1;
  }
  
***************
*** 1029,1043 ****
  	int n = lua_tointeger(L, 1);
  	for (win = firstwin; win != NULL; win = win->w_next, n--)
  	    if (n == 1) break;
- 	if (win == NULL) /* not found? */
- 	    lua_pushnil(L);
- 	else
- 	    luaV_pushwindow(L, win);
      }
!     else {
  	win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
! 	luaV_pushwindow(L, win);
!     }
      return 1;
  }
  
--- 1545,1554 ----
  	int n = lua_tointeger(L, 1);
  	for (win = firstwin; win != NULL; win = win->w_next, n--)
  	    if (n == 1) break;
      }
!     else
  	win = (lua_toboolean(L, 1)) ? firstwin : curwin; /* first window? */
!     luaV_pushwindow(L, win);
      return 1;
  }
  
***************
*** 1054,1086 ****
  }
  
      static int
! luaV_isbuffer(lua_State *L)
! {
!     lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_BUFFER) != NULL);
!     return 1;
! }
! 
!     static int
! luaV_iswindow(lua_State *L)
  {
!     lua_pushboolean(L, luaV_toudata(L, 1, LUAVIM_WINDOW) != NULL);
!     return 1;
! }
! 
! /* for freeing buffer and window objects; lightuserdata as arg */
!     static int
! luaV_free(lua_State *L)
! {
!     lua_pushvalue(L, 1); /* lightudata */
!     lua_rawget(L, LUA_ENVIRONINDEX);
!     if (!lua_isnil(L, -1))
      {
! 	lua_pushnil(L);
! 	lua_rawset(L, LUA_ENVIRONINDEX); /* env[udata] = nil */
! 	lua_pushnil(L);
! 	lua_rawset(L, LUA_ENVIRONINDEX); /* env[lightudata] = nil */
      }
!     return 0;
  }
  
  static const luaL_Reg luaV_module[] = {
--- 1565,1606 ----
  }
  
      static int
! luaV_type(lua_State *L)
  {
!     luaL_checkany(L, 1);
!     if (lua_type(L, 1) == LUA_TUSERDATA) /* check vim udata? */
      {
! 	lua_settop(L, 1);
! 	if (lua_getmetatable(L, 1))
! 	{
! 	    luaV_getfield(L, LUAVIM_LIST);
! 	    if (lua_rawequal(L, -1, 2))
! 	    {
! 		lua_pushstring(L, "list");
! 		return 1;
! 	    }
! 	    luaV_getfield(L, LUAVIM_DICT);
! 	    if (lua_rawequal(L, -1, 2))
! 	    {
! 		lua_pushstring(L, "dict");
! 		return 1;
! 	    }
! 	    luaV_getfield(L, LUAVIM_BUFFER);
! 	    if (lua_rawequal(L, -1, 2))
! 	    {
! 		lua_pushstring(L, "buffer");
! 		return 1;
! 	    }
! 	    luaV_getfield(L, LUAVIM_WINDOW);
! 	    if (lua_rawequal(L, -1, 2))
! 	    {
! 		lua_pushstring(L, "window");
! 		return 1;
! 	    }
! 	}
      }
!     lua_pushstring(L, luaL_typename(L, 1)); /* fallback */
!     return 1;
  }
  
  static const luaL_Reg luaV_module[] = {
***************
*** 1088,1111 ****
      {"eval", luaV_eval},
      {"beep", luaV_beep},
      {"line", luaV_line},
      {"buffer", luaV_buffer},
      {"window", luaV_window},
      {"open", luaV_open},
!     {"isbuffer", luaV_isbuffer},
!     {"iswindow", luaV_iswindow},
      {NULL, NULL}
  };
  
      static int
  luaopen_vim(lua_State *L)
  {
!     /* set environment */
      lua_newtable(L);
      lua_newtable(L);
!     lua_pushliteral(L, "v");
      lua_setfield(L, -2, "__mode");
!     lua_setmetatable(L, -2);
!     lua_replace(L, LUA_ENVIRONINDEX);
      /* print */
      lua_pushcfunction(L, luaV_print);
      lua_setglobal(L, "print");
--- 1608,1695 ----
      {"eval", luaV_eval},
      {"beep", luaV_beep},
      {"line", luaV_line},
+     {"list", luaV_list},
+     {"dict", luaV_dict},
      {"buffer", luaV_buffer},
      {"window", luaV_window},
      {"open", luaV_open},
!     {"type", luaV_type},
      {NULL, NULL}
  };
  
+ /* for freeing list, dict, buffer and window objects; lightuserdata as arg */
+     static int
+ luaV_free(lua_State *L)
+ {
+     lua_pushnil(L);
+     luaV_setudata(L, lua_touserdata(L, 1));
+     return 0;
+ }
+ 
+     static int
+ luaV_luaeval (lua_State *L)
+ {
+     luaL_Buffer b;
+     size_t l;
+     const char *str = lua_tolstring(L, 1, &l);
+     typval_T *arg = (typval_T *) lua_touserdata(L, 2);
+     typval_T *rettv = (typval_T *) lua_touserdata(L, 3);
+     luaL_buffinit(L, &b);
+     luaL_addlstring(&b, LUAVIM_EVALHEADER, sizeof(LUAVIM_EVALHEADER) - 1);
+     luaL_addlstring(&b, str, l);
+     luaL_pushresult(&b);
+     str = lua_tolstring(L, -1, &l);
+     if (luaL_loadbuffer(L, str, l, LUAVIM_EVALNAME)) /* compile error? */
+     {
+ 	luaV_emsg(L);
+ 	return 0;
+     }
+     luaV_pushtypval(L, arg);
+     if (lua_pcall(L, 1, 1, 0)) /* running error? */
+     {
+ 	luaV_emsg(L);
+ 	return 0;
+     }
+     luaV_totypval(L, -1, rettv);
+     return 0;
+ }
+ 
+     static int
+ luaV_setref (lua_State *L)
+ {
+     int copyID = lua_tointeger(L, 1);
+     typval_T tv;
+     luaV_getfield(L, LUAVIM_LIST);
+     luaV_getfield(L, LUAVIM_DICT);
+     lua_pushnil(L);
+     while (lua_next(L, lua_upvalueindex(1)) != 0) /* traverse cache table */
+     {
+ 	lua_getmetatable(L, -1);
+ 	if (lua_rawequal(L, -1, 2)) /* list? */
+ 	{
+ 	    tv.v_type = VAR_LIST;
+ 	    tv.vval.v_list = (list_T *) lua_touserdata(L, 4); /* key */
+ 	}
+ 	else if (lua_rawequal(L, -1, 3)) /* dict? */
+ 	{
+ 	    tv.v_type = VAR_DICT;
+ 	    tv.vval.v_dict = (dict_T *) lua_touserdata(L, 4); /* key */
+ 	}
+ 	lua_pop(L, 2); /* metatable and value */
+ 	set_ref_in_tv(&tv, copyID);
+     }
+     return 0;
+ }
+ 
      static int
  luaopen_vim(lua_State *L)
  {
!     /* set cache table */
      lua_newtable(L);
      lua_newtable(L);
!     lua_pushstring(L, "v");
      lua_setfield(L, -2, "__mode");
!     lua_setmetatable(L, -2); /* cache is weak-valued */
      /* print */
      lua_pushcfunction(L, luaV_print);
      lua_setglobal(L, "print");
***************
*** 1116,1129 ****
      lua_pop(L, 1);
      /* free */
      lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
!     lua_pushcfunction(L, luaV_free);
      lua_rawset(L, LUA_REGISTRYINDEX);
      /* register */
      luaV_newmetatable(L, LUAVIM_BUFFER);
!     luaL_register(L, NULL, luaV_Buffer_mt);
      luaV_newmetatable(L, LUAVIM_WINDOW);
!     luaL_register(L, NULL, luaV_Window_mt);
!     luaL_register(L, LUAVIM_NAME, luaV_module);
      return 0;
  }
  
--- 1700,1735 ----
      lua_pop(L, 1);
      /* free */
      lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
!     lua_pushvalue(L, 1); /* cache table */
!     lua_pushcclosure(L, luaV_free, 1);
!     lua_rawset(L, LUA_REGISTRYINDEX);
!     /* luaeval */
!     lua_pushlightuserdata(L, (void *) LUAVIM_LUAEVAL);
!     lua_pushvalue(L, 1); /* cache table */
!     lua_pushcclosure(L, luaV_luaeval, 1);
!     lua_rawset(L, LUA_REGISTRYINDEX);
!     /* setref */
!     lua_pushlightuserdata(L, (void *) LUAVIM_SETREF);
!     lua_pushvalue(L, 1); /* cache table */
!     lua_pushcclosure(L, luaV_setref, 1);
      lua_rawset(L, LUA_REGISTRYINDEX);
      /* register */
+     luaV_newmetatable(L, LUAVIM_LIST);
+     lua_pushvalue(L, 1);
+     luaV_openlib(L, luaV_List_mt, 1);
+     luaV_newmetatable(L, LUAVIM_DICT);
+     lua_pushvalue(L, 1);
+     luaV_openlib(L, luaV_Dict_mt, 1);
      luaV_newmetatable(L, LUAVIM_BUFFER);
!     lua_pushvalue(L, 1); /* cache table */
!     luaV_openlib(L, luaV_Buffer_mt, 1);
      luaV_newmetatable(L, LUAVIM_WINDOW);
!     lua_pushvalue(L, 1); /* cache table */
!     luaV_openlib(L, luaV_Window_mt, 1);
!     lua_newtable(L); /* vim table */
!     lua_pushvalue(L, 1); /* cache table */
!     luaV_openlib(L, luaV_module, 1);
!     lua_setglobal(L, LUAVIM_NAME);
      return 0;
  }
  
***************
*** 1154,1160 ****
  static lua_State *L = NULL;
  
      static int
! lua_is_open(void)
  {
      return L != NULL;
  }
--- 1760,1766 ----
  static lua_State *L = NULL;
  
      static int
! lua_isopen(void)
  {
      return L != NULL;
  }
***************
*** 1162,1168 ****
      static int
  lua_init(void)
  {
!     if (L == NULL)
      {
  #ifdef DYNAMIC_LUA
  	if (!lua_enabled(TRUE))
--- 1768,1774 ----
      static int
  lua_init(void)
  {
!     if (!lua_isopen())
      {
  #ifdef DYNAMIC_LUA
  	if (!lua_enabled(TRUE))
***************
*** 1179,1185 ****
      void
  lua_end(void)
  {
!     if (L != NULL)
      {
  	lua_close(L);
  	L = NULL;
--- 1785,1791 ----
      void
  lua_end(void)
  {
!     if (lua_isopen())
      {
  	lua_close(L);
  	L = NULL;
***************
*** 1273,1295 ****
      }
  }
  
! /* buffer */
      void
! lua_buffer_free(buf_T *buf)
  {
!     if (!lua_is_open()) return;
!     luaV_getfield(L, LUAVIM_FREE);
!     lua_pushlightuserdata(L, (void *) buf);
!     lua_call(L, 1, 0);
  }
  
- /* window */
      void
! lua_window_free(win_T *win)
  {
!     if (!lua_is_open()) return;
!     luaV_getfield(L, LUAVIM_FREE);
!     lua_pushlightuserdata(L, (void *) win);
      lua_call(L, 1, 0);
  }
  
--- 1879,1914 ----
      }
  }
  
! #define luaV_freetype(typ,tname) \
! 	void \
!     lua_##tname##_free(typ *o) \
!     { \
! 	if (!lua_isopen()) return; \
! 	luaV_getfield(L, LUAVIM_FREE); \
! 	lua_pushlightuserdata(L, (void *) o); \
! 	lua_call(L, 1, 0); \
!     }
! 
! luaV_freetype(buf_T, buffer)
! luaV_freetype(win_T, window)
! 
      void
! do_luaeval (char_u *str, typval_T *arg, typval_T *rettv)
  {
!     lua_init();
!     luaV_getfield(L, LUAVIM_LUAEVAL);
!     lua_pushstring(L, (char *) str);
!     lua_pushlightuserdata(L, (void *) arg);
!     lua_pushlightuserdata(L, (void *) rettv);
!     lua_call(L, 3, 0);
  }
  
      void
! set_ref_in_lua (int copyID)
  {
!     if (!lua_isopen()) return;
!     luaV_getfield(L, LUAVIM_SETREF);
!     lua_pushinteger(L, copyID);
      lua_call(L, 1, 0);
  }
  
*** ../vim-7.3.489/src/proto/if_lua.pro	2010-08-15 21:57:28.000000000 +0200
--- src/proto/if_lua.pro	2012-04-05 16:41:35.000000000 +0200
***************
*** 6,9 ****
--- 6,11 ----
  void ex_luafile __ARGS((exarg_T *eap));
  void lua_buffer_free __ARGS((buf_T *buf));
  void lua_window_free __ARGS((win_T *win));
+ void do_luaeval __ARGS((char_u *str, typval_T *arg, typval_T *rettv));
+ void set_ref_in_lua __ARGS((int copyID));
  /* vim: set ft=c : */
*** ../vim-7.3.489/src/version.c	2012-04-05 16:07:01.000000000 +0200
--- src/version.c	2012-04-05 16:52:08.000000000 +0200
***************
*** 716,717 ****
--- 716,719 ----
  {   /* Add new patch number below this line */
+ /**/
+     490,
  /**/

-- 
Even got a Datapoint 3600(?) with a DD50 connector instead of the
usual DB25...  what a nightmare trying to figure out the pinout
for *that* with no spex...

 /// Bram Moolenaar -- Bram@Moolenaar.net -- 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    ///
