Merge #9740 from KillTheMule/luadoc

This commit is contained in:
Justin M. Keyes 2019-05-19 18:45:21 +02:00 committed by GitHub
commit 8e941c59ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1259 additions and 372 deletions

View File

@ -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
@ -257,146 +257,6 @@ procedures that alter buffer content, open new buffers, and change cursor
position are restricted when the command is executed in the |sandbox|.
==============================================================================
vim.* *lua-vim* *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")
is unnecessary.
You can peek at the module properties: >
:lua print(vim.inspect(vim))
Result is something like this: >
{
_os_proc_children = <function 1>,
_os_proc_info = <function 2>,
...
api = {
nvim__id = <function 5>,
nvim__id_array = <function 6>,
...
},
deepcopy = <function 106>,
gsplit = <function 107>,
...
}
To find documentation on e.g. the "deepcopy" function: >
:help vim.deepcopy
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` exposes the full Nvim |API| as a table of Lua functions.
For example, to use the "nvim_get_current_line()" API function, call
"vim.api.nvim_get_current_line()": >
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.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
unclear whether empty lua table represents empty list or empty array)
and forcing integral numbers to be |Float|. See |lua-special-tbl| for
more details.
vim.val_idx *lua-vim.val_idx*
Value index for tables representing |Float|s. A table representing
floating-point value 1.0 looks like this: >
{
[vim.type_idx] = vim.types.float,
[vim.val_idx] = 1.0,
}
< See also |lua-vim.type_idx| and |lua-special-tbl|.
vim.types *lua-vim.types*
Table with possible values for |lua-vim.type_idx|. Contains two sets
of key-value pairs: first maps possible values for |lua-vim.type_idx|
to human-readable strings, second maps human-readable type names to
values for |lua-vim.type_idx|. Currently contains pairs for `float`,
`array` and `dictionary` types.
Note: one must expect that values corresponding to `vim.types.float`,
`vim.types.array` and `vim.types.dictionary` fall under only two
following assumptions:
1. Value may serve both as a key and as a value in a table. Given the
properties of lua tables this basically means “value is not `nil`”.
2. For each value in `vim.types` table `vim.types[vim.types[value]]`
is the same as `value`.
No other restrictions are put on types, and it is not guaranteed that
values corresponding to `vim.types.float`, `vim.types.array` and
`vim.types.dictionary` will not change or that `vim.types` table will
only contain values for these three types.
------------------------------------------------------------------------------
vim.* runtime functions
Those functions are only available after the runtime files have been loaded.
In particular, they are not available when using `nvim -u NONE`.
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.
==============================================================================
luaeval() *lua-luaeval* *lua-eval*
*luaeval()*
@ -468,4 +328,197 @@ value is also always converted. When converting, |msgpack-special-dict|s are
treated specially.
==============================================================================
vim:tw=78:ts=8:et:ft=help:norl:
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")
is unnecessary.
You can peek at the module properties: >
:lua print(vim.inspect(vim))
Result is something like this: >
{
_os_proc_children = <function 1>,
_os_proc_info = <function 2>,
...
api = {
nvim__id = <function 5>,
nvim__id_array = <function 6>,
...
},
deepcopy = <function 106>,
gsplit = <function 107>,
...
}
To find documentation on e.g. the "deepcopy" function: >
:help vim.deepcopy
Note that underscore-prefixed functions (e.g. "_os_proc_children") are
internal/private and must not be used by plugins.
------------------------------------------------------------------------------
VIM.API *lua-api*
`vim.api` exposes the full Nvim |API| as a table of Lua functions.
For example, to use the "nvim_get_current_line()" API function, call
"vim.api.nvim_get_current_line()": >
print(tostring(vim.api.nvim_get_current_line()))
------------------------------------------------------------------------------
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.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
unclear whether empty lua table represents empty list or empty array)
and forcing integral numbers to be |Float|. See |lua-special-tbl| for
more details.
vim.val_idx *lua-vim.val_idx*
Value index for tables representing |Float|s. A table representing
floating-point value 1.0 looks like this: >
{
[vim.type_idx] = vim.types.float,
[vim.val_idx] = 1.0,
}
< See also |lua-vim.type_idx| and |lua-special-tbl|.
vim.types *lua-vim.types*
Table with possible values for |lua-vim.type_idx|. Contains two sets
of key-value pairs: first maps possible values for |lua-vim.type_idx|
to human-readable strings, second maps human-readable type names to
values for |lua-vim.type_idx|. Currently contains pairs for `float`,
`array` and `dictionary` types.
Note: one must expect that values corresponding to `vim.types.float`,
`vim.types.array` and `vim.types.dictionary` fall under only two
following assumptions:
1. Value may serve both as a key and as a value in a table. Given the
properties of lua tables this basically means “value is not `nil`”.
2. For each value in `vim.types` table `vim.types[vim.types[value]]`
is the same as `value`.
No other restrictions are put on types, and it is not guaranteed that
values corresponding to `vim.types.float`, `vim.types.array` and
`vim.types.dictionary` will not change or that `vim.types` table will
only contain values for these three types.
==============================================================================
Lua module: vim *lua-vim*
trim({s}) *vim.trim()*
Trim whitespace (Lua pattern "%%s") from both sides of a
string.
Parameters: ~
{s} String to trim
Return: ~
String with whitespace removed from its beginning and end
See also: ~
https://www.lua.org/pil/20.2.html
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.
Parameters: ~
{orig} Table to copy
Return: ~
New table of copied keys and (nested) values.
gsplit({s}, {sep}, {plain}) *vim.gsplit()*
Splits a string at each instance of a separator.
Parameters: ~
{s} String to split
{sep} Separator string or pattern
{plain} If `true` use `sep` literally (passed to
String.find)
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:

View File

@ -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
-- Checks if a list-like (vector) table contains `value`.
--- 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
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,

View File

@ -48,26 +48,65 @@ DEBUG = ('DEBUG' in os.environ)
INCLUDE_C_DECL = ('INCLUDE_C_DECL' in os.environ)
INCLUDE_DEPRECATED = ('INCLUDE_DEPRECATED' in os.environ)
doc_filename = 'api.txt'
# String used to find the start of the generated part of the doc.
section_start_token = '*api-global*'
# Required prefix for API function names.
api_func_name_prefix = 'nvim_'
text_width = 78
script_path = os.path.abspath(__file__)
base_dir = os.path.dirname(os.path.dirname(script_path))
out_dir = os.path.join(base_dir, 'tmp-{mode}-doc')
filter_cmd = '%s %s' % (sys.executable, script_path)
seen_funcs = set()
lua2dox_filter = os.path.join(base_dir, 'scripts', 'lua2dox_filter')
# Section name overrides.
section_name = {
'vim.c': 'Global',
CONFIG = {
'api': {
'filename': 'api.txt',
# String used to find the start of the generated part of the doc.
'section_start_token': '*api-global*',
# Section ordering.
'section_order' : [
'vim.c',
'buffer.c',
'window.c',
'tabpage.c',
'ui.c',
],
# List of files/directories for doxygen to read, separated by blanks
'files': os.path.join(base_dir, 'src/nvim/api'),
# file patterns used by doxygen
'file_patterns': '*.h *.c',
# Only function with this prefix are considered
'func_name_prefix': 'nvim_',
# Section name overrides.
'section_name': {
'vim.c': 'Global',
},
# Module name overrides (for Lua).
'module_override': {},
# Append the docs for these modules, do not start a new section.
'append_only' : [],
},
'lua': {
'filename': 'if_lua.txt',
'section_start_token': '*lua-vim*',
'section_order' : [
'vim.lua',
'shared.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
]),
'file_patterns': '*.lua',
'func_name_prefix': '',
'section_name': {},
'module_override': {
'shared': 'vim', # `shared` functions are exposed on the `vim` module.
},
'append_only' : [
'shared.lua',
],
},
}
# Section ordering.
section_order = (
'vim.c',
'buffer.c',
'window.c',
'tabpage.c',
'ui.c',
)
param_exclude = (
'channel_id',
)
@ -77,13 +116,6 @@ annotation_map = {
'FUNC_API_ASYNC': '{async}',
}
text_width = 78
script_path = os.path.abspath(__file__)
base_dir = os.path.dirname(os.path.dirname(script_path))
src_dir = os.path.join(base_dir, 'src/nvim/api')
out_dir = os.path.join(base_dir, 'tmp-api-doc')
filter_cmd = '%s %s' % (sys.executable, script_path)
seen_funcs = set()
# Tracks `xrefsect` titles. As of this writing, used only for separating
# deprecated functions.
@ -286,7 +318,7 @@ def render_node(n, text, prefix='', indent='', width=62):
elif n.nodeName == 'listitem':
for c in n.childNodes:
text += indent + prefix + render_node(c, text, indent=indent+(' ' * len(prefix)), width=width)
elif n.nodeName == 'para':
elif n.nodeName in ('para', 'heading'):
for c in n.childNodes:
text += render_node(c, text, indent=indent, width=width)
if is_inline(n):
@ -400,7 +432,7 @@ def parse_parblock(parent, prefix='', width=62, indent=''):
# }}}
def parse_source_xml(filename):
def parse_source_xml(filename, mode):
"""Collects API functions.
Returns two strings:
@ -415,9 +447,12 @@ def parse_source_xml(filename):
deprecated_functions = []
dom = minidom.parse(filename)
compoundname = get_text(dom.getElementsByTagName('compoundname')[0])
for member in dom.getElementsByTagName('memberdef'):
if member.getAttribute('static') == 'yes' or \
member.getAttribute('kind') != 'function':
member.getAttribute('kind') != 'function' or \
member.getAttribute('prot') == 'private' or \
get_text(get_child(member, 'name')).startswith('_'):
continue
loc = find_first(member, 'location')
@ -444,7 +479,13 @@ def parse_source_xml(filename):
annotations = filter(None, map(lambda x: annotation_map.get(x),
annotations.split()))
vimtag = '*{}()*'.format(name)
if mode == 'lua':
fstem = compoundname.split('.')[0]
fstem = CONFIG[mode]['module_override'].get(fstem, fstem)
vimtag = '*{}.{}()*'.format(fstem, name)
else:
vimtag = '*{}()*'.format(name)
params = []
type_length = 0
@ -454,6 +495,10 @@ def parse_source_xml(filename):
declname = get_child(param, 'declname')
if declname:
param_name = get_text(declname).strip()
elif mode == 'lua':
# that's how it comes out of lua2dox
param_name = param_type
param_type = ''
if param_name in param_exclude:
continue
@ -521,7 +566,7 @@ def parse_source_xml(filename):
if 'Deprecated' in xrefs:
deprecated_functions.append(func_doc)
elif name.startswith(api_func_name_prefix):
elif name.startswith(CONFIG[mode]['func_name_prefix']):
functions.append(func_doc)
xrefs.clear()
@ -547,115 +592,129 @@ def gen_docs(config):
Doxygen is called and configured through stdin.
"""
p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE)
p.communicate(config.format(input=src_dir, output=out_dir,
filter=filter_cmd).encode('utf8'))
if p.returncode:
sys.exit(p.returncode)
for mode in CONFIG:
output_dir = out_dir.format(mode=mode)
p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE)
p.communicate(
config.format(
input=CONFIG[mode]['files'],
output=output_dir,
filter=filter_cmd,
file_patterns=CONFIG[mode]['file_patterns'])
.encode('utf8')
)
if p.returncode:
sys.exit(p.returncode)
sections = {}
intros = {}
sep = '=' * text_width
sections = {}
intros = {}
sep = '=' * text_width
base = os.path.join(out_dir, 'xml')
dom = minidom.parse(os.path.join(base, 'index.xml'))
base = os.path.join(output_dir, 'xml')
dom = minidom.parse(os.path.join(base, 'index.xml'))
# generate docs for section intros
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'group':
continue
groupname = get_text(find_first(compound, 'name'))
groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid'))
desc = find_first(minidom.parse(groupxml), 'detaileddescription')
if desc:
doc = parse_parblock(desc)
if doc:
intros[groupname] = doc
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'file':
continue
filename = get_text(find_first(compound, 'name'))
if filename.endswith('.c'):
functions, deprecated = parse_source_xml(
os.path.join(base, '%s.xml' % compound.getAttribute('refid')))
if not functions and not deprecated:
# generate docs for section intros
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'group':
continue
if functions or deprecated:
name = os.path.splitext(os.path.basename(filename))[0]
if name == 'ui':
name = name.upper()
else:
name = name.title()
doc = ''
intro = intros.get('api-%s' % name.lower())
if intro:
doc += '\n\n' + intro
if functions:
doc += '\n\n' + functions
if INCLUDE_DEPRECATED and deprecated:
doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name
doc += deprecated
groupname = get_text(find_first(compound, 'name'))
groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid'))
desc = find_first(minidom.parse(groupxml), 'detaileddescription')
if desc:
doc = parse_parblock(desc)
if doc:
filename = os.path.basename(filename)
name = section_name.get(filename, name)
title = '%s Functions' % name
helptag = '*api-%s*' % name.lower()
sections[filename] = (title, helptag, doc)
intros[groupname] = doc
if not sections:
return
for compound in dom.getElementsByTagName('compound'):
if compound.getAttribute('kind') != 'file':
continue
docs = ''
filename = get_text(find_first(compound, 'name'))
if filename.endswith('.c') or filename.endswith('.lua'):
functions, deprecated = parse_source_xml(
os.path.join(base, '%s.xml' %
compound.getAttribute('refid')), mode)
i = 0
for filename in section_order:
if filename not in sections:
continue
title, helptag, section_doc = sections.pop(filename)
if not functions and not deprecated:
continue
i += 1
docs += sep
docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title)))
docs += section_doc
docs += '\n\n\n'
if functions or deprecated:
name = os.path.splitext(os.path.basename(filename))[0]
if name == 'ui':
name = name.upper()
else:
name = name.title()
if sections:
# In case new API sources are added without updating the order dict.
for title, helptag, section_doc in sections.values():
doc = ''
intro = intros.get('api-%s' % name.lower())
if intro:
doc += '\n\n' + intro
if functions:
doc += '\n\n' + functions
if INCLUDE_DEPRECATED and deprecated:
doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name
doc += deprecated
if doc:
filename = os.path.basename(filename)
name = CONFIG[mode]['section_name'].get(filename, name)
if mode == 'lua':
title = 'Lua module: {}'.format(name.lower())
helptag = '*lua-{}*'.format(name.lower())
else:
title = '{} Functions'.format(name)
helptag = '*api-{}*'.format(name.lower())
sections[filename] = (title, helptag, doc)
if not sections:
return
docs = ''
i = 0
for filename in CONFIG[mode]['section_order']:
if filename not in sections:
raise RuntimeError('found new module "{}"; update the "section_order" map'.format(filename))
title, helptag, section_doc = sections.pop(filename)
i += 1
docs += sep
docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title)))
if filename not in CONFIG[mode]['append_only']:
docs += sep
docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title)))
docs += section_doc
docs += '\n\n\n'
docs = docs.rstrip() + '\n\n'
docs += ' vim:tw=78:ts=8:ft=help:norl:\n'
docs = docs.rstrip() + '\n\n'
docs += ' vim:tw=78:ts=8:ft=help:norl:\n'
doc_file = os.path.join(base_dir, 'runtime/doc', doc_filename)
delete_lines_below(doc_file, section_start_token)
with open(doc_file, 'ab') as fp:
fp.write(docs.encode('utf8'))
shutil.rmtree(out_dir)
doc_file = os.path.join(base_dir, 'runtime', 'doc',
CONFIG[mode]['filename'])
delete_lines_below(doc_file, CONFIG[mode]['section_start_token'])
with open(doc_file, 'ab') as fp:
fp.write(docs.encode('utf8'))
shutil.rmtree(output_dir)
def filter_source(filename):
"""Filters the source to fix macros that confuse Doxygen."""
with open(filename, 'rt') as fp:
print(re.sub(r'^(ArrayOf|DictionaryOf)(\(.*?\))',
lambda m: m.group(1)+'_'.join(
re.split(r'[^\w]+', m.group(2))),
fp.read(), flags=re.M))
name, extension = os.path.splitext(filename)
if extension == '.lua':
p = subprocess.run([lua2dox_filter, filename], stdout=subprocess.PIPE)
op = ('?' if 0 != p.returncode else p.stdout.decode('utf-8'))
print(op)
else:
"""Filters the source to fix macros that confuse Doxygen."""
with open(filename, 'rt') as fp:
print(re.sub(r'^(ArrayOf|DictionaryOf)(\(.*?\))',
lambda m: m.group(1)+'_'.join(
re.split(r'[^\w]+', m.group(2))),
fp.read(), flags=re.M))
# Doxygen Config {{{
@ -663,13 +722,15 @@ Doxyfile = '''
OUTPUT_DIRECTORY = {output}
INPUT = {input}
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h *.c
FILE_PATTERNS = {file_patterns}
RECURSIVE = YES
INPUT_FILTER = "{filter}"
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = */private/*
EXCLUDE_SYMBOLS =
EXTENSION_MAPPING = lua=C
EXTRACT_PRIVATE = NO
GENERATE_HTML = NO
GENERATE_DOCSET = NO

666
scripts/lua2dox.lua Normal file
View File

@ -0,0 +1,666 @@
--[[--------------------------------------------------------------------------
-- Copyright (C) 2012 by Simon Dales --
-- simon@purrsoft.co.uk --
-- --
-- This program is free software; you can redistribute it and/or modify --
-- it under the terms of the GNU General Public License as published by --
-- the Free Software Foundation; either version 2 of the License, or --
-- (at your option) any later version. --
-- --
-- This program is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
-- GNU General Public License for more details. --
-- --
-- You should have received a copy of the GNU General Public License --
-- along with this program; if not, write to the --
-- Free Software Foundation, Inc., --
-- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
----------------------------------------------------------------------------]]
--[[!
\file
\brief a hack lua2dox converter
]]
--[[!
\mainpage
Introduction
------------
A hack lua2dox converter
Version 0.2
This lets us make Doxygen output some documentation to let
us develop this code.
It is partially cribbed from the functionality of lua2dox
(http://search.cpan.org/~alec/Doxygen-Lua-0.02/lib/Doxygen/Lua.pm).
Found on CPAN when looking for something else; kinda handy.
Improved from lua2dox to make the doxygen output more friendly.
Also it runs faster in lua rather than Perl.
Because this Perl based system is called "lua2dox"., I have decided to add ".lua" to the name
to keep the two separate.
Running
-------
<ol>
<li> Ensure doxygen is installed on your system and that you are familiar with its use.
Best is to try to make and document some simple C/C++/PHP to see what it produces.
You can experiment with the enclosed example code.
<li> Run "doxygen -g" to create a default Doxyfile.
Then alter it to let it recognise lua. Add the two following lines:
\code{.bash}
FILE_PATTERNS = *.lua
FILTER_PATTERNS = *.lua=lua2dox_filter
\endcode
Either add them to the end or find the appropriate entry in Doxyfile.
There are other lines that you might like to alter, but see futher documentation for details.
<li> When Doxyfile is edited run "doxygen"
The core function reads the input file (filename or stdin) and outputs some pseudo C-ish language.
It only has to be good enough for doxygen to see it as legal.
Therefore our lua interpreter is fairly limited, but "good enough".
One limitation is that each line is treated separately (except for long comments).
The implication is that class and function declarations must be on the same line.
Some functions can have their parameter lists extended over multiple lines to make it look neat.
Managing this where there are also some comments is a bit more coding than I want to do at this stage,
so it will probably not document accurately if we do do this.
However I have put in a hack that will insert the "missing" close paren.
The effect is that you will get the function documented, but not with the parameter list you might expect.
</ol>
Installation
------------
Here for linux or unix-like, for any other OS you need to refer to other documentation.
This file is "lua2dox.lua". It gets called by "lua2dox_filter"(bash).
Somewhere in your path (e.g. "~/bin" or "/usr/local/bin") put a link to "lua2dox_filter".
Documentation
-------------
Read the external documentation that should be part of this package.
For example look for the "README" and some .PDFs.
]]
-- we won't use our library code, so this becomes more portable
-- require 'elijah_fix_require'
-- require 'elijah_class'
--
--! \brief ``declare'' as class
--!
--! use as:
--! \code{.lua}
--! TWibble = class()
--! function TWibble.init(this,Str)
--! this.str = Str
--! -- more stuff here
--! end
--! \endcode
--!
function class(BaseClass, ClassInitialiser)
local newClass = {} -- a new class newClass
if not ClassInitialiser and type(BaseClass) == 'function' then
ClassInitialiser = BaseClass
BaseClass = nil
elseif type(BaseClass) == 'table' then
-- our new class is a shallow copy of the base class!
for i,v in pairs(BaseClass) do
newClass[i] = v
end
newClass._base = BaseClass
end
-- the class will be the metatable for all its newInstanceects,
-- and they will look up their methods in it.
newClass.__index = newClass
-- expose a constructor which can be called by <classname>(<args>)
local classMetatable = {}
classMetatable.__call =
function(class_tbl, ...)
local newInstance = {}
setmetatable(newInstance,newClass)
--if init then
-- init(newInstance,...)
if class_tbl.init then
class_tbl.init(newInstance,...)
else
-- make sure that any stuff from the base class is initialized!
if BaseClass and BaseClass.init then
BaseClass.init(newInstance, ...)
end
end
return newInstance
end
newClass.init = ClassInitialiser
newClass.is_a =
function(this, klass)
local thisMetatable = getmetatable(this)
while thisMetatable do
if thisMetatable == klass then
return true
end
thisMetatable = thisMetatable._base
end
return false
end
setmetatable(newClass, classMetatable)
return newClass
end
-- require 'elijah_clock'
--! \class TCore_Clock
--! \brief a clock
TCore_Clock = class()
--! \brief get the current time
function TCore_Clock.GetTimeNow()
if os.gettimeofday then
return os.gettimeofday()
else
return os.time()
end
end
--! \brief constructor
function TCore_Clock.init(this,T0)
if T0 then
this.t0 = T0
else
this.t0 = TCore_Clock.GetTimeNow()
end
end
--! \brief get time string
function TCore_Clock.getTimeStamp(this,T0)
local t0
if T0 then
t0 = T0
else
t0 = this.t0
end
return os.date('%c %Z',t0)
end
--require 'elijah_io'
--! \class TCore_IO
--! \brief io to console
--!
--! pseudo class (no methods, just to keep documentation tidy)
TCore_IO = class()
--
--! \brief write to stdout
function TCore_IO_write(Str)
if (Str) then
io.write(Str)
end
end
--! \brief write to stdout
function TCore_IO_writeln(Str)
if (Str) then
io.write(Str)
end
io.write("\n")
end
--require 'elijah_string'
--! \brief trims a string
function string_trim(Str)
return Str:match("^%s*(.-)%s*$")
end
--! \brief split a string
--!
--! \param Str
--! \param Pattern
--! \returns table of string fragments
function string_split(Str, Pattern)
local splitStr = {}
local fpat = "(.-)" .. Pattern
local last_end = 1
local str, e, cap = string.find(Str,fpat, 1)
while str do
if str ~= 1 or cap ~= "" then
table.insert(splitStr,cap)
end
last_end = e+1
str, e, cap = string.find(Str,fpat, last_end)
end
if last_end <= #Str then
cap = string.sub(Str,last_end)
table.insert(splitStr, cap)
end
return splitStr
end
--require 'elijah_commandline'
--! \class TCore_Commandline
--! \brief reads/parses commandline
TCore_Commandline = class()
--! \brief constructor
function TCore_Commandline.init(this)
this.argv = arg
this.parsed = {}
this.params = {}
end
--! \brief get value
function TCore_Commandline.getRaw(this,Key,Default)
local val = this.argv[Key]
if not val then
val = Default
end
return val
end
--require 'elijah_debug'
-------------------------------
--! \brief file buffer
--!
--! an input file buffer
TStream_Read = class()
--! \brief get contents of file
--!
--! \param Filename name of file to read (or nil == stdin)
function TStream_Read.getContents(this,Filename)
-- get lines from file
local filecontents
if Filename then
-- syphon lines to our table
--TCore_Debug_show_var('Filename',Filename)
filecontents={}
for line in io.lines(Filename) do
table.insert(filecontents,line)
end
else
-- get stuff from stdin as a long string (with crlfs etc)
filecontents=io.read('*a')
-- make it a table of lines
filecontents = TString_split(filecontents,'[\n]') -- note this only works for unix files.
Filename = 'stdin'
end
if filecontents then
this.filecontents = filecontents
this.contentsLen = #filecontents
this.currentLineNo = 1
end
return filecontents
end
--! \brief get lineno
function TStream_Read.getLineNo(this)
return this.currentLineNo
end
--! \brief get a line
function TStream_Read.getLine(this)
local line
if this.currentLine then
line = this.currentLine
this.currentLine = nil
else
-- get line
if this.currentLineNo<=this.contentsLen then
line = this.filecontents[this.currentLineNo]
this.currentLineNo = this.currentLineNo + 1
else
line = ''
end
end
return line
end
--! \brief save line fragment
function TStream_Read.ungetLine(this,LineFrag)
this.currentLine = LineFrag
end
--! \brief is it eof?
function TStream_Read.eof(this)
if this.currentLine or this.currentLineNo<=this.contentsLen then
return false
end
return true
end
--! \brief output stream
TStream_Write = class()
--! \brief constructor
function TStream_Write.init(this)
this.tailLine = {}
end
--! \brief write immediately
function TStream_Write.write(this,Str)
TCore_IO_write(Str)
end
--! \brief write immediately
function TStream_Write.writeln(this,Str)
TCore_IO_writeln(Str)
end
--! \brief write immediately
function TStream_Write.writelnComment(this,Str)
TCore_IO_write('// ZZ: ')
TCore_IO_writeln(Str)
end
--! \brief write to tail
function TStream_Write.writelnTail(this,Line)
if not Line then
Line = ''
end
table.insert(this.tailLine,Line)
end
--! \brief outout tail lines
function TStream_Write.write_tailLines(this)
for k,line in ipairs(this.tailLine) do
TCore_IO_writeln(line)
end
TCore_IO_write('// Lua2DoX new eof')
end
--! \brief input filter
TLua2DoX_filter = class()
--! \brief allow us to do errormessages
function TLua2DoX_filter.warning(this,Line,LineNo,Legend)
this.outStream:writelnTail(
'//! \todo warning! ' .. Legend .. ' (@' .. LineNo .. ')"' .. Line .. '"'
)
end
--! \brief trim comment off end of string
--!
--! If the string has a comment on the end, this trims it off.
--!
local function TString_removeCommentFromLine(Line)
local pos_comment = string.find(Line,'%-%-')
local tailComment
if pos_comment then
Line = string.sub(Line,1,pos_comment-1)
tailComment = string.sub(Line,pos_comment)
end
return Line,tailComment
end
--! \brief get directive from magic
local function getMagicDirective(Line)
local macro,tail
local macroStr = '[\\@]'
local pos_macro = string.find(Line,macroStr)
if pos_macro then
--! ....\\ macro...stuff
--! ....\@ macro...stuff
local line = string.sub(Line,pos_macro+1)
local space = string.find(line,'%s+')
if space then
macro = string.sub(line,1,space-1)
tail = string_trim(string.sub(line,space+1))
else
macro = line
tail = ''
end
end
return macro,tail
end
--! \brief check comment for fn
local function checkComment4fn(Fn_magic,MagicLines)
local fn_magic = Fn_magic
-- TCore_IO_writeln('// checkComment4fn "' .. MagicLines .. '"')
local magicLines = string_split(MagicLines,'\n')
local macro,tail
for k,line in ipairs(magicLines) do
macro,tail = getMagicDirective(line)
if macro == 'fn' then
fn_magic = tail
-- TCore_IO_writeln('// found fn "' .. fn_magic .. '"')
else
--TCore_IO_writeln('// not found fn "' .. line .. '"')
end
end
return fn_magic
end
--! \brief run the filter
function TLua2DoX_filter.readfile(this,AppStamp,Filename)
local err
local inStream = TStream_Read()
local outStream = TStream_Write()
this.outStream = outStream -- save to this obj
if (inStream:getContents(Filename)) then
-- output the file
local line
local fn_magic -- function name/def from magic comment
outStream:writelnTail('// #######################')
outStream:writelnTail('// app run:' .. AppStamp)
outStream:writelnTail('// #######################')
outStream:writelnTail()
while not (err or inStream:eof()) do
line = string_trim(inStream:getLine())
-- TCore_Debug_show_var('inStream',inStream)
-- TCore_Debug_show_var('line',line )
if string.sub(line,1,2)=='--' then -- its a comment
if string.sub(line,3,3)=='@' then -- it's a magic comment
local magic = string.sub(line,4)
outStream:writeln('/// @' .. magic)
fn_magic = checkComment4fn(fn_magic,magic)
elseif string.sub(line,3,3)=='-' then -- it's a nonmagic doc comment
local comment = string.sub(line,4)
outStream:writeln('/// '.. comment)
elseif string.sub(line,3,4)=='[[' then -- it's a long comment
line = string.sub(line,5) -- nibble head
local comment = ''
local closeSquare,hitend,thisComment
while (not err) and (not hitend) and (not inStream:eof()) do
closeSquare = string.find(line,']]')
if not closeSquare then -- need to look on another line
thisComment = line .. '\n'
line = inStream:getLine()
else
thisComment = string.sub(line,1,closeSquare-1)
hitend = true
-- unget the tail of the line
-- in most cases it's empty. This may make us less efficient but
-- easier to program
inStream:ungetLine(string_trim(string.sub(line,closeSquare+2)))
end
comment = comment .. thisComment
end
if string.sub(comment,1,1)=='@' then -- it's a long magic comment
outStream:write('/*' .. comment .. '*/ ')
fn_magic = checkComment4fn(fn_magic,comment)
else -- discard
outStream:write('/* zz:' .. comment .. '*/ ')
fn_magic = nil
end
else
outStream:writeln('// zz:"' .. line .. '"')
fn_magic = nil
end
elseif string.find(line,'^function') or string.find(line,'^local%s+function') then
-- it's a function
local pos_fn = string.find(line,'function')
-- function
-- ....v...
if pos_fn then
-- we've got a function
local fn_type
if string.find(line,'^local%s+') then
fn_type = ''--'static ' -- static functions seem to be excluded
else
fn_type = ''
end
local fn = TString_removeCommentFromLine(string_trim(string.sub(line,pos_fn+8)))
if fn_magic then
fn = fn_magic
fn_magic = nil
end
if string.sub(fn,1,1)=='(' then
-- it's an anonymous function
outStream:writelnComment(line)
else
-- fn has a name, so is interesting
-- want to fix for iffy declarations
local open_paren = string.find(fn,'[%({]')
local fn0 = fn
if open_paren then
fn0 = string.sub(fn,1,open_paren-1)
-- we might have a missing close paren
if not string.find(fn,'%)') then
fn = fn .. ' ___MissingCloseParenHere___)'
end
end
local dot = string.find(fn0,'[%.:]')
if dot then -- it's a method
local klass = string.sub(fn,1,dot-1)
local method = string.sub(fn,dot+1)
--TCore_IO_writeln('function ' .. klass .. '::' .. method .. ftail .. '{}')
--TCore_IO_writeln(klass .. '::' .. method .. ftail .. '{}')
outStream:writeln(
'/*! \\memberof ' .. klass .. ' */ '
.. method .. '{}'
)
else
-- add vanilla function
outStream:writeln(fn_type .. 'function ' .. fn .. '{}')
end
end
else
this:warning(inStream:getLineNo(),'something weird here')
end
fn_magic = nil -- mustn't indavertently use it again
elseif string.find(line,'=%s*class%(') then
-- it's a class declaration
local tailComment
line,tailComment = TString_removeCommentFromLine(line)
local equals = string.find(line,'=')
local klass = string_trim(string.sub(line,1,equals-1))
local tail = string_trim(string.sub(line,equals+1))
-- class(wibble wibble)
-- ....v.
local parent = string.sub(tail,7,-2)
if #parent>0 then
parent = ' :public ' .. parent
end
outStream:writeln('class ' .. klass .. parent .. '{};')
else
-- we don't know what this line means, so we can probably just comment it out
if #line>0 then
outStream:writeln('// zz: ' .. line)
else
outStream:writeln() -- keep this line blank
end
end
end
-- output the tail
outStream:write_tailLines()
else
outStream:writeln('!empty file')
end
end
--! \brief this application
TApp = class()
--! \brief constructor
function TApp.init(this)
local t0 = TCore_Clock()
this.timestamp = t0:getTimeStamp()
this.name = 'Lua2DoX'
this.version = '0.2 20130128'
this.copyright = 'Copyright (c) Simon Dales 2012-13'
end
function TApp.getRunStamp(this)
return this.name .. ' (' .. this.version .. ') '
.. this.timestamp
end
function TApp.getVersion(this)
return this.name .. ' (' .. this.version .. ') '
end
function TApp.getCopyright(this)
return this.copyright
end
local This_app = TApp()
--main
local cl = TCore_Commandline()
local argv1 = cl:getRaw(2)
if argv1 == '--help' then
TCore_IO_writeln(This_app:getVersion())
TCore_IO_writeln(This_app:getCopyright())
TCore_IO_writeln([[
run as:
lua2dox_filter <param>
--------------
Param:
<filename> : interprets filename
--version : show version/copyright info
--help : this help text]])
elseif argv1 == '--version' then
TCore_IO_writeln(This_app:getVersion())
TCore_IO_writeln(This_app:getCopyright())
else
-- it's a filter
local appStamp = This_app:getRunStamp()
local filename = argv1
local filter = TLua2DoX_filter()
filter:readfile(appStamp,filename)
end
--eof

87
scripts/lua2dox_filter Executable file
View File

@ -0,0 +1,87 @@
#!/bin/bash
###########################################################################
# Copyright (C) 2012 by Simon Dales #
# simon@purrsoft.co.uk #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the #
# Free Software Foundation, Inc., #
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
###########################################################################
LANG=""
##! \brief test executable to see if it exists
test_executable(){
P_EXE="$1"
#########
WHICH=`which ${P_EXE}`
if test -z "${WHICH}"
then
echo "not found \"${P_EXE}\""
else
EXE="${P_EXE}"
fi
}
##! \brief sets the lua interpreter
set_lua(){
test_executable 'texlua'
if test -z "${EXE}"
then
test_executable 'lua'
fi
#echo "final EXE=\"${EXE}\""
}
##! \brief makes canonical name of file
##!
##! Note that "readlink -f" doesn't work in MacOSX
##!
do_readlink(){
pushd . > /dev/null
TARGET_FILE=$1
cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`
# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]
do
TARGET_FILE=`readlink $TARGET_FILE`
cd `dirname $TARGET_FILE`
TARGET_FILE=`basename $TARGET_FILE`
done
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR
popd > /dev/null
}
##main
set_lua
if test -z "${EXE}"
then
echo "no lua interpreter available"
else
BASENAME=`basename "$0"`
do_readlink "$0"
DIRNAME="${RESULT}"
LUASCRIPT="${DIRNAME}/lua2dox.lua ${BASENAME}"
#echo "lua[${LUASCRIPT}]"
${EXE} ${LUASCRIPT} $@
fi
#
##eof

View File

@ -243,7 +243,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
# that for custom extensions you also need to set FILE_PATTERNS otherwise the
# files are not read by doxygen.
EXTENSION_MAPPING =
EXTENSION_MAPPING = lua=C
# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
# comments according to the Markdown format, which allows for more readable
@ -672,7 +672,7 @@ INPUT_ENCODING = UTF-8
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS = *.h *.c
FILE_PATTERNS = *.h *.c *.lua
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@ -758,7 +758,7 @@ INPUT_FILTER =
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
FILTER_PATTERNS = *.lua=scripts/lua2dox_filter
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source

View File

@ -1,10 +1,10 @@
-- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib)
--
-- Lua code lives in one of three places:
-- 1. The runtime (`runtime/lua/vim/`). For "nice to have" features, e.g.
-- the `inspect` and `lpeg` modules.
-- 2. The `vim.shared` module: code shared between Nvim and its test-suite.
-- 3. Compiled-into Nvim itself (`src/nvim/lua/`).
-- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the
-- `inspect` and `lpeg` modules.
-- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests.
-- 3. src/nvim/lua/: Compiled-into Nvim itself.
--
-- Guideline: "If in doubt, put it in the runtime".
--
@ -154,75 +154,17 @@ local function _update_package_paths()
last_nvim_paths = cur_nvim_paths
end
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
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
local function split(s,sep,plain)
local t={} for c in gsplit(s, sep, plain) do table.insert(t,c) end
return t
end
--- Trim whitespace (Lua pattern "%%s") from both sides of a string.
---
--@see https://www.lua.org/pil/20.2.html
--@param s String to trim
--@returns String with whitespace removed from its beginning and end
local function trim(s)
assert(type(s) == "string", "Only strings can be trimmed")
local result = s:gsub("^%s+", ""):gsub("%s+$", "")
assert(type(s) == 'string', 'Only strings can be trimmed')
local result = s:gsub('^%s+', ''):gsub('%s+$', '')
return result
end
local deepcopy
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
local function __index(t, key)
if key == 'inspect' then
t.inspect = require('vim.inspect')
@ -240,9 +182,6 @@ local module = {
_os_proc_info = _os_proc_info,
_system = _system,
trim = trim,
split = split,
gsplit = gsplit,
deepcopy = deepcopy,
}
setmetatable(module, {

View File

@ -336,30 +336,6 @@ local function shallowcopy(orig)
return copy
end
local deepcopy
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
local REMOVE_THIS = {}
local function mergedicts_copy(d1, d2)
@ -728,7 +704,6 @@ local module = {
check_logs = check_logs,
concat_tables = concat_tables,
dedent = dedent,
deepcopy = deepcopy,
dictdiff = dictdiff,
eq = eq,
expect_err = expect_err,