diff --git a/elements.md b/elements.md index 2e3e5a6..645cddf 100644 --- a/elements.md +++ b/elements.md @@ -12,9 +12,17 @@ gui.AnimatedImage { w = 1, h = 2, name = "my_animated_image", -- Optional + + -- The image to use. texture_name = "texture.png", + + -- The number of frames animating the image. frame_count = 3, + + -- Milliseconds between each frame. `0` means the frames don't advance. frame_duration = 4, + + -- The index of the frame to start on. Default `1`. frame_start = 5, -- Optional middle_x = 6, -- Optional middle_y = 7, -- Optional @@ -105,6 +113,10 @@ gui.Field { name = "my_field", -- Optional label = "Hello world!", default = "Hello world!", + + -- Makes changing the field submit it on mobile devices. + -- Requires a recent version of formspec_ast. + enter_after_edit = false, -- Optional } ``` @@ -225,6 +237,9 @@ gui.List { list_name = "Hello world!", w = 1, h = 2, + + -- The index of the first (upper-left) item to draw. + -- Indices start at `0`. Default is `0`. starting_item_index = 3, -- Optional } ``` @@ -239,14 +254,24 @@ gui.Model { w = 1, h = 2, name = "my_model", -- Optional + + -- The mesh model to use. mesh = "Hello world!", + + -- The mesh textures to use according to the mesh materials. textures = {"texture.png", ...}, rotation_x = 3, -- Optional rotation_y = 4, -- Optional + + -- Whether the rotation is continuous. Default `false`. continuous = false, -- Optional + + -- Whether the model can be controlled with the mouse. Default `true`. mouse_control = false, -- Optional frame_loop_begin = 5, -- Optional frame_loop_end = 6, -- Optional + + -- Sets the animation speed. Default 0 FPS. animation_speed = 7, -- Optional } ``` @@ -276,6 +301,8 @@ gui.Table { h = 2, -- Optional name = "my_table", -- Optional cells = {"Hello world!", ...}, + + -- index of row to be selected within table (first row = `1`) selected_idx = 3, } ``` diff --git a/generate_docs.py b/generate_docs.py index bb92661..474509f 100644 --- a/generate_docs.py +++ b/generate_docs.py @@ -1,11 +1,12 @@ from ruamel.yaml import YAML -import collections, re, requests +import collections, functools, re, requests yaml = YAML(typ='safe') hide_elements = { 'background', 'background9', 'scroll_container', 'scrollbar', 'tabheader' } +hide_comments = {'x', 'y', 'w', 'h', 'name', 'selected'} special_case_names = {'tablecolumns': 'TableColumns', 'tableoptions': 'TableOptions'} @@ -16,7 +17,21 @@ def fetch_elements(): return yaml.load(res.text) -Field = collections.namedtuple('Field', 'name type is_list', defaults=(False,)) +@functools.cache +def fetch_lua_api(): + return requests.get('https://github.com/minetest/minetest/raw/' + 'master/doc/lua_api.md').text + + +Field = collections.namedtuple('Field', 'name type is_list comment', + defaults=(False, '')) +special_case_types = { + 'field': ( + Field('enter_after_edit', 'boolean', False, + ('Makes changing the field submit it on mobile devices.\n' + 'Requires a recent version of formspec_ast.')), + ), +} def search_for_fields(obj, *, is_list=False): @@ -40,6 +55,27 @@ def optional(element_name, field_name): return field_name == 'name' +def get_comment(element_name, field): + if field.comment: + return field.comment + + if field.name in hide_comments: + return + + # Try and get something useful from lua_api.md + _, _, docs = fetch_lua_api().partition(f'\n### `{element_name}[') + doc_lines = docs.split('\n###', 1)[0].split('\n') + s = (f'*_`{field.name}`:_', f'*_`{field.name}`_(optional)') + for line in (it := iter(doc_lines)): + if line.lower().replace(' ', '_').startswith(s): + lines = [line.split(': ', 1)[-1]] + for line2 in it: + if not line2.startswith(' ') or 'comma' in line2: + break + lines.append(line2.lstrip()) + return '\n'.join(lines) + + def element_to_docs(element_name, variants): if element_name in special_case_names: flow_name = special_case_names[element_name] @@ -53,6 +89,9 @@ def element_to_docs(element_name, variants): element_name not in special_case_names): return '' + if element_name in special_case_types: + fields.update(special_case_types[element_name]) + lines = [ f'### `gui.{flow_name}`\n', f"Equivalent to Minetest's `{element_name}[]` element.\n", @@ -101,10 +140,16 @@ def element_to_docs(element_name, variants): if field.is_list and field.type != 'table': value = f'{{{value}, ...}}' + if comment := get_comment(element_name, field): + if lines and lines[-1].startswith(indent): + lines.append('') + for comment_line in comment.split('\n'): + lines.append(f'{indent}-- {comment_line}') + line = f'{indent}{field.name} = {value},' if ((count < len(variants) or optional(element_name, field.name)) and field.name != 'gui_element_name'): - line = line + ' -- Optional' + line += ' -- Optional' lines.append(line) if element_name == 'tablecolumns': diff --git a/init.lua b/init.lua index 17201a5..d36a575 100644 --- a/init.lua +++ b/init.lua @@ -544,7 +544,7 @@ local function render_ast(node, embedded) expand(node) local t3 = DEBUG_MODE and minetest.get_us_time() local res = { - formspec_version = 6, + formspec_version = 7, {type = "size", w = w, h = h}, } @@ -996,6 +996,14 @@ local function insert_shorthand_elements(tree) name = node.name, close_on_enter = false, }) + + if node.enter_after_edit then + table.insert(tree, i, { + type = 'field_enter_after_edit', + name = node.name, + enter_after_edit = true, + }) + end end end end diff --git a/test.lua b/test.lua index 2626f90..3c5d20a 100644 --- a/test.lua +++ b/test.lua @@ -370,7 +370,7 @@ describe("Flow", function() it("registers inventory formspecs", function () local stupid_simple_inv_expected = - "formspec_version[6]" .. + "formspec_version[7]" .. "size[10.35,5.35]" .. "list[current_player;main;0.3,0.3;8,4]" local stupid_simple_inv = flow.make_gui(function (p, c) @@ -388,7 +388,7 @@ describe("Flow", function() end) it("can still show a form when an inventory formspec is shown", function () - local expected_one = "formspec_version[6]size[1.6,1.6]box[0.3,0.3;1,1;]" + local expected_one = "formspec_version[7]size[1.6,1.6]box[0.3,0.3;1,1;]" local one = flow.make_gui(function (p, c) return gui.Box{ w = 1, h = 1 } end) @@ -735,6 +735,29 @@ describe("Flow", function() end) end) + describe("extra field parameters", function() + it("default to sensible values", function() + test_render(gui.Field{ + w = 1, h = 1, name = "test", + }, [[ + size[1.6,1.6] + field_close_on_enter[test;false] + field[0.3,0.3;1,1;test;;] + ]]) + end) + + it("can enable field_enter_after_edit", function() + test_render(gui.Field{ + w = 1, h = 1, name = "test", enter_after_edit = true + }, [[ + size[1.6,1.6] + field_enter_after_edit[test;true] + field_close_on_enter[test;false] + field[0.3,0.3;1,1;test;;] + ]]) + end) + end) + describe("inline style parser", function() it("parses inline styles correctly", function() test_render(gui.Box{