201 lines
5.1 KiB
Python
Executable File
201 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# A primitive script to parse lua_api.txt for formspec elements.
|
|
#
|
|
|
|
import copy, lua_dump, os, urllib.request
|
|
|
|
def _make_known(**kwargs):
|
|
known = {}
|
|
for k, v in kwargs.items():
|
|
for i in v:
|
|
known[i] = k
|
|
return known
|
|
|
|
_known = _make_known(
|
|
number=('x', 'y', 'w', 'h', 'selected_idx', 'version',
|
|
'starting_item_index', 'scroll_factor'),
|
|
boolean=('auto_clip', 'fixed_size', 'transparent', 'draw_border', 'bool',
|
|
'fullscreen', 'noclip', 'drawborder', 'selected', 'force'),
|
|
table=('param', 'opt', 'prop'),
|
|
null=('',),
|
|
)
|
|
|
|
def _get_name(n):
|
|
if not isinstance(n, tuple) or n[1] == '...':
|
|
return '...'
|
|
return n[0][:-1].rsplit('_', 1)[0].rstrip('_')
|
|
|
|
_aliases = {
|
|
'type': 'elem_type',
|
|
'cell': 'cells',
|
|
}
|
|
|
|
def _fix_param(param):
|
|
if isinstance(param, str):
|
|
if ',' not in param:
|
|
param = param.lower().strip().strip('<>').replace(' ', '_')
|
|
param = _aliases.get(param, param)
|
|
assert param != '...'
|
|
return (param, _known.get(param, 'string'))
|
|
param = param.split(',')
|
|
|
|
res = []
|
|
for p in map(str.strip, param):
|
|
if p != '...':
|
|
res.append(_fix_param(p))
|
|
continue
|
|
assert res
|
|
|
|
last = res.pop()
|
|
# Workaround
|
|
if res and last and isinstance(last, list) and \
|
|
last[0][0].endswith('2') and isinstance(res[-1], list) and \
|
|
res[-1] and res[-1][0][0].endswith('1'):
|
|
last = res.pop()
|
|
last[0] = (last[0][0][:-2], last[0][1])
|
|
|
|
name = _get_name(last)
|
|
if name == '...':
|
|
res.append((last, '...'))
|
|
else:
|
|
while res and _get_name(res[-1]) == name:
|
|
res.pop()
|
|
res.append((_fix_param(name), '...'))
|
|
break
|
|
|
|
return res
|
|
|
|
_hooks = {}
|
|
def hook(name):
|
|
def add_hook(func):
|
|
_hooks[name] = func
|
|
return func
|
|
return add_hook
|
|
|
|
# Fix background9
|
|
@hook('background9')
|
|
def _background9_hook(params):
|
|
assert params[-1] == ('middle', 'string')
|
|
params[-1] = param = []
|
|
param.append(('middle_x', 'number'))
|
|
yield params
|
|
param.append(('middle_y', 'number'))
|
|
yield params
|
|
param.append(('middle_x2', 'number'))
|
|
param.append(('middle_y2', 'number'))
|
|
yield params
|
|
|
|
# Fix bgcolor
|
|
@hook('bgcolor')
|
|
def _bgcolor_hook(params):
|
|
yield params
|
|
for i in range(1, len(params)):
|
|
yield params[:-i]
|
|
|
|
# Fix size
|
|
@hook('size')
|
|
def _size_hook(params):
|
|
yield params
|
|
yield [[('w', 'number'), ('h', 'number')]]
|
|
|
|
# Fix style and style_type
|
|
@hook('style')
|
|
@hook('style_type')
|
|
def _style_hook(params):
|
|
# This is not used when parsing but keeps backwards compatibility when
|
|
# unparsing.
|
|
params[0] = [('name', 'string')]
|
|
yield params
|
|
|
|
params[0] = [(('selectors', 'string'), '...')]
|
|
yield params
|
|
|
|
# Fix scroll_container
|
|
@hook('scroll_container')
|
|
def _scroll_container_hook(params):
|
|
yield params
|
|
yield params[:4]
|
|
|
|
# Fix dropdown
|
|
@hook('dropdown')
|
|
def _scroll_container_hook(params):
|
|
if isinstance(params[1][0], str):
|
|
params[1] = [('w', 'number'), ('h', 'number')]
|
|
else:
|
|
params[1] = ('w', 'number')
|
|
yield params[:5]
|
|
yield params
|
|
|
|
def _raw_parse(data):
|
|
data = data.split('\nElements\n--------\n', 1)[-1].split('\n----', 1)[0]
|
|
for line in data.split('\n'):
|
|
if not line.startswith('### `') or not line.endswith('`'):
|
|
continue
|
|
|
|
elem = line[5:-2]
|
|
name, params = elem.split('[', 1)
|
|
if params:
|
|
params = _fix_param(params.split(';'))
|
|
else:
|
|
params = []
|
|
|
|
if name in _hooks:
|
|
for p in reversed(tuple(map(copy.deepcopy, _hooks[name](params)))):
|
|
yield name, p
|
|
else:
|
|
yield name, params
|
|
|
|
def parse(data):
|
|
"""
|
|
Returns a dict:
|
|
{
|
|
'element_name': [
|
|
['param1', 'param2'],
|
|
['alternate_params'],
|
|
]
|
|
}
|
|
"""
|
|
res = {}
|
|
for k, v in _raw_parse(data):
|
|
if k not in res:
|
|
res[k] = []
|
|
res[k].append(v)
|
|
|
|
for v in res.values():
|
|
v.sort(key=len, reverse=True)
|
|
|
|
return res
|
|
|
|
URL = 'https://github.com/minetest/minetest/raw/master/doc/lua_api.txt'
|
|
def fetch_and_parse(*, url=URL):
|
|
with urllib.request.urlopen(url) as f:
|
|
raw = f.read()
|
|
return parse(raw.decode('utf-8', 'replace'))
|
|
|
|
_comment = """
|
|
--
|
|
-- Formspec elements list. Do not update this by hand, it is auto-generated
|
|
-- by make_elements.py.
|
|
--
|
|
|
|
"""
|
|
|
|
def main():
|
|
dirname = os.path.dirname(__file__)
|
|
filename = os.path.join(dirname, 'elements.lua')
|
|
print('Writing to ' + filename + '...')
|
|
with open(filename, 'w') as f:
|
|
f.write(_comment.lstrip())
|
|
f.write(lua_dump.serialize(fetch_and_parse()))
|
|
# elems = fetch_and_parse()
|
|
# for elem in sorted(elems):
|
|
# for def_ in elems[elem]:
|
|
# f.write('formspec_ast.register_element({}, {})\n'.format(
|
|
# lua_dump.dump(elem), lua_dump.dump(def_)
|
|
# ))
|
|
print('Done.')
|
|
|
|
if __name__ == '__main__':
|
|
main()
|