diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/doc/if_lua.txt | 285 | ||||
-rw-r--r-- | runtime/lua/vim/shared.lua | 128 |
2 files changed, 286 insertions, 127 deletions
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index b97341e319..7f90074ff0 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -30,7 +30,7 @@ finds and loads Lua modules. The conventions are similar to VimL plugins, with some extra features. See |lua-require-example| for a walkthrough. ============================================================================== -Importing modules *lua-require* +Importing Lua modules *lua-require* Nvim automatically adjusts `package.path` and `package.cpath` according to effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is @@ -258,7 +258,77 @@ position are restricted when the command is executed in the |sandbox|. ============================================================================== -vim.* *lua-vim* *lua-stdlib* +luaeval() *lua-luaeval* *lua-eval* + *luaeval()* + +The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is +"luaeval". "luaeval" takes an expression string and an optional argument used +for _A inside expression 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 + +Lua nils, numbers, strings, tables and booleans are converted to their +respective VimL types. An error is thrown if conversion of any other Lua types +is attempted. + +The magic global "_A" contains the second argument to luaeval(). + +Example: > + :echo luaeval('_A[1] + _A[2]', [40, 2]) + 42 + :echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123') + foo + +Lua tables are used as both dictionaries and lists, so it is impossible to +determine whether empty table is meant to be empty list or empty dictionary. +Additionally lua does not have integer numbers. To distinguish between these +cases there is the following agreement: + +0. Empty table is empty list. +1. Table with N incrementally growing integral numbers, starting from 1 and + ending with N is considered to be a list. +2. Table with string keys, none of which contains NUL byte, is considered to + be a dictionary. +3. Table with string keys, at least one of which contains NUL byte, is also + considered to be a dictionary, but this time it is converted to + a |msgpack-special-map|. + *lua-special-tbl* +4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point + value: + - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to + a floating-point 1.0. Note that by default integral lua numbers are + converted to |Number|s, non-integral are converted to |Float|s. This + variant allows integral |Float|s. + - `{[vim.type_idx]=vim.types.dictionary}` is converted to an empty + dictionary, `{[vim.type_idx]=vim.types.dictionary, [42]=1, a=2}` is + converted to a dictionary `{'a': 42}`: non-string keys are ignored. + Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3. + are errors. + - `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well + as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not + form a 1-step sequence from 1 to N are ignored, as well as all + non-integral keys. + +Examples: > + + :echo luaeval('math.pi') + :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) + +Note that currently second argument to `luaeval` undergoes VimL to lua +conversion, so changing containers in lua do not affect values in VimL. Return +value is also always converted. When converting, |msgpack-special-dict|s are +treated specially. + +============================================================================== +Lua standard modules *lua-stdlib* The Nvim Lua "standard library" (stdlib) is the `vim` module, which exposes various functions and sub-modules. It is always loaded, thus require("vim") @@ -292,7 +362,7 @@ Note that underscore-prefixed functions (e.g. "_os_proc_children") are internal/private and must not be used by plugins. ------------------------------------------------------------------------------ -vim.api.* functions +VIM.API *lua-api* `vim.api` exposes the full Nvim |API| as a table of Lua functions. @@ -302,55 +372,18 @@ For example, to use the "nvim_get_current_line()" API function, call print(tostring(vim.api.nvim_get_current_line())) ------------------------------------------------------------------------------ -vim.* builtin functions - -vim.deepcopy({object}) *vim.deepcopy* - Performs a deep copy of the given object, and returns that copy. - For a non-table object, that just means a usual copy of the object, - while for a table all subtables are copied recursively. - -vim.gsplit({s}, {sep}, {plain}) *vim.gsplit* - Split a given string by a separator. Returns an iterator of the - split components. The separator can be a lua pattern, see - https://www.lua.org/pil/20.2.html - Setting {plain} to `true` turns off pattern matching, as it is passed - to `string:find`, see - http://lua-users.org/wiki/StringLibraryTutorial - - Parameters:~ - {s} String: String to split - {sep} String: Separator pattern. If empty, split by chars. - {plain} Boolean: If false, match {sep} verbatim - - Return:~ - Iterator of strings, which are the components of {s} after - splitting - -vim.split({s}, {sep}, {plain}) *vim.split* - Split a given string by a separator. Returns a table containing the - split components. The separator can be a lua pattern, see - https://www.lua.org/pil/20.2.html - Setting {plain} to `true` turns off pattern matching, as it is passed - to `string:find`, see - http://lua-users.org/wiki/StringLibraryTutorial - - Parameters:~ - {s} String: String to split - {sep} String: Separator pattern. If empty, split by chars. - {plain} Boolean: If false, match {sep} verbatim - - Return:~ - Table of strings, which are the components of {s} after - splitting +VIM *lua-util* + +vim.inspect({object}, {options}) *vim.inspect* + Return a human-readable representation of the passed object. See + https://github.com/kikito/inspect.lua + for details and possible options. vim.stricmp(a, b) *lua-vim.stricmp* Function used for case-insensitive string comparison. Takes two string arguments and returns 0, 1 or -1 if strings are equal, a is greater then b or a is lesser then b respectively. -vim.trim({string}) *vim.trim* - Returns the string with all leading and trailing whitespace removed. - vim.type_idx *lua-vim.type_idx* Type index for use in |lua-special-tbl|. Specifying one of the values from |lua-vim.types| allows typing the empty table (it is @@ -386,86 +419,106 @@ vim.types *lua-vim.types* `vim.types.dictionary` will not change or that `vim.types` table will only contain values for these three types. ------------------------------------------------------------------------------- -vim.* runtime functions +============================================================================== +Lua module: vim *lua-vim* -Those functions are only available after the runtime files have been loaded. -In particular, they are not available when using `nvim -u NONE`. +trim({s}) *vim.trim()* + Trim whitespace (Lua pattern "%%s") from both sides of a + string. -vim.inspect({object}, {options}) *vim.inspect* - Return a human-readable representation of the passed object. See - https://github.com/kikito/inspect.lua - for details and possible options. + Parameters: ~ + {s} String to trim -============================================================================== -luaeval() *lua-luaeval* *lua-eval* - *luaeval()* + Return: ~ + String with whitespace removed from its beginning and end -The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is -"luaeval". "luaeval" takes an expression string and an optional argument used -for _A inside expression 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 + See also: ~ + https://www.lua.org/pil/20.2.html -Lua nils, numbers, strings, tables and booleans are converted to their -respective VimL types. An error is thrown if conversion of any other Lua types -is attempted. -The magic global "_A" contains the second argument to luaeval(). -Example: > - :echo luaeval('_A[1] + _A[2]', [40, 2]) - 42 - :echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123') - foo -Lua tables are used as both dictionaries and lists, so it is impossible to -determine whether empty table is meant to be empty list or empty dictionary. -Additionally lua does not have integer numbers. To distinguish between these -cases there is the following agreement: +deepcopy({orig}) *vim.deepcopy()* + Returns a deep copy of the given object. Non-table objects are + copied as in a typical Lua assignment, whereas table objects + are copied recursively. -0. Empty table is empty list. -1. Table with N incrementally growing integral numbers, starting from 1 and - ending with N is considered to be a list. -2. Table with string keys, none of which contains NUL byte, is considered to - be a dictionary. -3. Table with string keys, at least one of which contains NUL byte, is also - considered to be a dictionary, but this time it is converted to - a |msgpack-special-map|. - *lua-special-tbl* -4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point - value: - - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to - a floating-point 1.0. Note that by default integral lua numbers are - converted to |Number|s, non-integral are converted to |Float|s. This - variant allows integral |Float|s. - - `{[vim.type_idx]=vim.types.dictionary}` is converted to an empty - dictionary, `{[vim.type_idx]=vim.types.dictionary, [42]=1, a=2}` is - converted to a dictionary `{'a': 42}`: non-string keys are ignored. - Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3. - are errors. - - `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well - as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not - form a 1-step sequence from 1 to N are ignored, as well as all - non-integral keys. + Parameters: ~ + {orig} Table to copy -Examples: > + Return: ~ + New table of copied keys and (nested) values. - :echo luaeval('math.pi') - :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) +gsplit({s}, {sep}, {plain}) *vim.gsplit()* + Splits a string at each instance of a separator. -Note that currently second argument to `luaeval` undergoes VimL to lua -conversion, so changing containers in lua do not affect values in VimL. Return -value is also always converted. When converting, |msgpack-special-dict|s are -treated specially. + Parameters: ~ + {s} String to split + {sep} Separator string or pattern + {plain} If `true` use `sep` literally (passed to + String.find) -============================================================================== - vim:tw=78:ts=8:et:ft=help:norl: + Return: ~ + Iterator over the split components + + See also: ~ + |vim.split()| + https://www.lua.org/pil/20.2.html + http://lua-users.org/wiki/StringLibraryTutorial + +split({s}, {sep}, {plain}) *vim.split()* + Splits a string at each instance of a separator. + + Examples: > + split(":aa::b:", ":") --> {'','aa','','bb',''} + split("axaby", "ab?") --> {'','x','y'} + split(x*yz*o, "*", true) --> {'x','yz','o'} +< + + Parameters: ~ + {s} String to split + {sep} Separator string or pattern + {plain} If `true` use `sep` literally (passed to + String.find) + + Return: ~ + List-like table of the split components. + + See also: ~ + |vim.gsplit()| + +tbl_contains({t}, {value}) *vim.tbl_contains()* + Checks if a list-like (vector) table contains `value` . + + Parameters: ~ + {t} Table to check + {value} Value to compare + + Return: ~ + true if `t` contains `value` + +tbl_extend({behavior}, {...}) *vim.tbl_extend()* + Merges two or more map-like tables. + + Parameters: ~ + {behavior} Decides what to do if a key is found in more + than one map: + - "error": raise an error + - "keep": use value from the leftmost map + - "force": use value from the rightmost map + {...} Two or more map-like tables. + + See also: ~ + |extend()| + +tbl_flatten({t}) *vim.tbl_flatten()* + Creates a copy of a list-like table such that any nested + tables are "unrolled" and appended to the result. + + Parameters: ~ + {t} List-like table + + Return: ~ + Flattened copy of the given list-like table. + + vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 9dca51ce9a..07f9f52e5c 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -1,9 +1,107 @@ ---- Shared functions --- - Used by Nvim and tests --- - Can run in vanilla Lua (do not require a running instance of Nvim) +-- Functions shared by Nvim and its test-suite. +-- +-- The singular purpose of this module is to share code with the Nvim +-- test-suite. If, in the future, Nvim itself is used to run the test-suite +-- instead of "vanilla Lua", these functions could move to src/nvim/lua/vim.lua + + +--- Returns a deep copy of the given object. Non-table objects are copied as +--- in a typical Lua assignment, whereas table objects are copied recursively. +--- +--@param orig Table to copy +--@returns New table of copied keys and (nested) values. +local function deepcopy(orig) + error() +end +local function _id(v) + return v +end +local deepcopy_funcs = { + table = function(orig) + local copy = {} + for k, v in pairs(orig) do + copy[deepcopy(k)] = deepcopy(v) + end + return copy + end, + number = _id, + string = _id, + ['nil'] = _id, + boolean = _id, +} +deepcopy = function(orig) + return deepcopy_funcs[type(orig)](orig) +end + +--- Splits a string at each instance of a separator. +--- +--@see |vim.split()| +--@see https://www.lua.org/pil/20.2.html +--@see http://lua-users.org/wiki/StringLibraryTutorial +--- +--@param s String to split +--@param sep Separator string or pattern +--@param plain If `true` use `sep` literally (passed to String.find) +--@returns Iterator over the split components +local function gsplit(s, sep, plain) + assert(type(s) == "string") + assert(type(sep) == "string") + assert(type(plain) == "boolean" or type(plain) == "nil") + local start = 1 + local done = false + + local function _pass(i, j, ...) + if i then + assert(j+1 > start, "Infinite loop detected") + local seg = s:sub(start, i - 1) + start = j + 1 + return seg, ... + else + done = true + return s:sub(start) + end + end --- Checks if a list-like (vector) table contains `value`. + return function() + if done then + return + end + if sep == '' then + if start == #s then + done = true + end + return _pass(start+1, start) + end + return _pass(s:find(sep, start, plain)) + end +end + +--- Splits a string at each instance of a separator. +--- +--- Examples: +--- <pre> +--- split(":aa::b:", ":") --> {'','aa','','bb',''} +--- split("axaby", "ab?") --> {'','x','y'} +--- split(x*yz*o, "*", true) --> {'x','yz','o'} +--- </pre> +-- +--@see |vim.gsplit()| +--- +--@param s String to split +--@param sep Separator string or pattern +--@param plain If `true` use `sep` literally (passed to String.find) +--@returns List-like table of the split components. +local function split(s,sep,plain) + local t={} for c in gsplit(s, sep, plain) do table.insert(t,c) end + return t +end + +--- Checks if a list-like (vector) table contains `value`. +--- +--@param t Table to check +--@param value Value to compare +--@returns true if `t` contains `value` local function tbl_contains(t, value) if type(t) ~= 'table' then error('t must be a table') @@ -17,13 +115,14 @@ local function tbl_contains(t, value) end --- Merges two or more map-like tables. --- +--- --@see |extend()| --- --- behavior: Decides what to do if a key is found in more than one map: --- "error": raise an error --- "keep": use value from the leftmost map --- "force": use value from the rightmost map +--- +--@param behavior Decides what to do if a key is found in more than one map: +--- - "error": raise an error +--- - "keep": use value from the leftmost map +--- - "force": use value from the rightmost map +--@param ... Two or more map-like tables. local function tbl_extend(behavior, ...) if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then error('invalid "behavior": '..tostring(behavior)) @@ -46,7 +145,11 @@ local function tbl_extend(behavior, ...) return ret end --- Flattens a list-like table: unrolls and appends nested tables to table `t`. +--- Creates a copy of a list-like table such that any nested tables are +--- "unrolled" and appended to the result. +--- +--@param t List-like table +--@returns Flattened copy of the given list-like table. local function tbl_flatten(t) -- From https://github.com/premake/premake-core/blob/master/src/base/table.lua local result = {} @@ -66,6 +169,9 @@ local function tbl_flatten(t) end local module = { + deepcopy = deepcopy, + gsplit = gsplit, + split = split, tbl_contains = tbl_contains, tbl_extend = tbl_extend, tbl_flatten = tbl_flatten, |