diff --git a/docs/source/api/image.rst b/docs/source/api/image.rst index dab7be5..f85a235 100644 --- a/docs/source/api/image.rst +++ b/docs/source/api/image.rst @@ -1,5 +1,5 @@ -image -===== +Images Overview +=============== Made of pixels and used by codea for drawing to the screen and texturing meshes @@ -16,6 +16,9 @@ Made of pixels and used by codea for drawing to the screen and texturing meshes sprite(img, WIDTH/2, HEIGHT/2) end +Image +===== + .. lua:class:: image .. lua:staticmethod:: image(width, height, [hasMips = false, numLayers = 1, format = image.rgba, depthFormat = none]) diff --git a/docs/source/api/input.rst b/docs/source/api/input.rst index d2f0771..7a90763 100644 --- a/docs/source/api/input.rst +++ b/docs/source/api/input.rst @@ -12,11 +12,11 @@ Touches Represents a single touch over time. Generated in response to touch events by the device in response to user interactions - .. attribute:: id: number + .. lua:attribute:: id: number An id that can be used to uniquely identify the touch - .. attribute:: state: enum + .. lua:attribute:: state: enum The current state of the touch, can be: @@ -25,7 +25,7 @@ Touches * ``ENDED`` - the touch ended this frame * ``CANCELLED`` - the touch was cancelled (usually by another view or gesture recognizer) - .. attribute:: type: enum + .. lua:attribute:: type: enum The type of touch, can be: @@ -34,75 +34,75 @@ Touches * ``touch.pencil`` - a touch resulting from the pencil * ``touch.pointer`` - a touch resulting from a button based device - .. attribute:: x: number + .. lua:attribute:: x: number The x position of the touch (in screen coordinates) - .. attribute:: y: number + .. lua:attribute:: y: number The y position of the touch (in screen coordinates) - .. attribute:: prevX: number + .. lua:attribute:: prevX: number The previous x position of the touch (in screen coordinates) - .. attribute:: prevY: number + .. lua:attribute:: prevY: number The previous y position of the touch (in screen coordinates) - .. attribute:: deltaX: number + .. lua:attribute:: deltaX: number The x position delta of the touch (in screen coordinates) - .. attribute:: deltaY: number + .. lua:attribute:: deltaY: number The y position delta of the touch (in screen coordinates) - .. attribute:: pos: vec2 + .. lua:attribute:: pos: vec2 The position of the touch (in screen coordinates) as a vector - .. attribute:: prevPos: vec2 + .. lua:attribute:: prevPos: vec2 The previous position of the touch (in screen coordinates) as a vector - .. attribute:: delta: number + .. lua:attribute:: delta: number The position delta of the touch (in screen coordinates) as a vector - .. attribute:: force: number + .. lua:attribute:: force: number The amount of force being applied (only applies to pencil type touches) - .. attribute:: maxForce: number + .. lua:attribute:: maxForce: number The maximum amount of force that can be applied (only applies to pencil type touches) - .. attribute:: timestamp: number + .. lua:attribute:: timestamp: number The time when this touch event occured (only applies to pencil type touches) - .. attribute:: azimuth: number + .. lua:attribute:: azimuth: number The azimuth angle of the pencil (only applies to pencil type touches) - .. attribute:: altitude: number + .. lua:attribute:: altitude: number The altitude angle of the pencil - .. attribute:: radiusTolerance: number + .. lua:attribute:: radiusTolerance: number The amount the estimated radius can vary due to hardware tolerances - .. attribute:: radius: number + .. lua:attribute:: radius: number The estimated radius of the touch - .. attribute:: precisePos: vec2 + .. lua:attribute:: precisePos: vec2 The precise location of the touch (if available) - .. attribute:: precisePrevPos: vec2 + .. lua:attribute:: precisePrevPos: vec2 The previous precise location of the touch (if available) diff --git a/docs/source/api/math_types.rst b/docs/source/api/math_types.rst index 320888d..5ad7235 100644 --- a/docs/source/api/math_types.rst +++ b/docs/source/api/math_types.rst @@ -1,23 +1,24 @@ math types ========== -vec2 -#### +2D Vectors +########## .. lua:class:: vec2 - .. lua:staticmethod:: vec2(x) - vec2(x, y) + This type represents a 2D vector. Most mathematical operators such as equality, addition, subtraction, multiplication and division are provided, so you can use ``vec2`` data types similarly to how you use numerical types. In addition there are a number of methods, such as ``v:dot( vec2 )`` that can be called on vec2 types. - Create a new ``vec2`` by setting both values at once or each one individually + :param x: Initial x value of the vector + :type x: number + :param y: Initial y value of the vector + :type y: number - .. lua:staticmethod:: min(v1, v2) - - Return a ``vec2`` containing the component-wise minimum of two vectors - - .. lua:staticmethod:: max(v1, v2) + :syntax: + .. code-block:: lua - Return a ``vec2`` containing the component-wise maximum two vectors + v = vec2(1, 2) + v = vec2(1) -- set both x and y to 1 + v = vec2() -- set both x and y to 0 .. lua:attribute:: x: number @@ -25,7 +26,15 @@ vec2 .. lua:attribute:: y: number - The y component of this vector + The y component of this vector + + .. lua:staticmethod:: min(v1, v2) + + Return a ``vec2`` containing the component-wise minimum of two vectors + + .. lua:staticmethod:: max(v1, v2) + + Return a ``vec2`` containing the component-wise maximum two vectors .. lua:attribute:: length: number @@ -91,8 +100,8 @@ vec2 Calculate the oriented angle between this vector and another, between -pi and pi -vec3 -#### +3D Vectors +########## .. lua:class:: vec3 @@ -173,8 +182,8 @@ vec3 Unpack this vector as multiple number values -vec4 -#### +4D Vectors +########## .. lua:class:: vec4 @@ -255,7 +264,7 @@ vec4 Unpack this vector as multiple number values -vector swizzling +Vector Swizzling ################ ``vec2``, ``vec3`` and ``vec4`` support swizzling, which allows you to access and manipulate their components in a variety of ways @@ -276,8 +285,8 @@ vector swizzling -quat -#### +Quaternions +########### .. lua:class:: quat @@ -356,8 +365,8 @@ quat :return: a normalized copy of this quaternion -mat2 -#### +2x2 Matrix +########## .. lua:class:: mat2 @@ -400,8 +409,8 @@ mat2 :rtype: vec2 -mat3 -#### +3x3 Matrix +########## .. lua:class:: mat3 @@ -444,8 +453,8 @@ mat3 :rtype: vec3 -mat4 -#### +4x4 Matrix +########## .. lua:class:: mat4 @@ -503,8 +512,8 @@ mat4 :return: the column at a given ``index`` (starting at 1) :rtype: vec3 -aabb -#### +Axis-Aligned Bounding Box (AABB) +################################ .. lua:module:: bounds diff --git a/docs/source/api/motion.rst b/docs/source/api/motion.rst index b95abca..550868a 100644 --- a/docs/source/api/motion.rst +++ b/docs/source/api/motion.rst @@ -1,9 +1,12 @@ -motion -====== +Motion Overview +=============== - Exposes Core Motion functionalities such as accessing the device's accelerometer, gyroscope, and magnetometer data. +Exposes Core Motion functionalities such as accessing the device's accelerometer, gyroscope, and magnetometer data. + +Tracking of motion metrics can impact performance and battery drain. Use this feature judiciously to avoid negatively affecting the user experience. - Tracking of motion metrics can impact performance and battery drain. Use this feature judiciously to avoid negatively affecting the user experience. +Motion +====== .. lua:module:: motion @@ -61,38 +64,53 @@ motion The heading in degrees relative to the current reference frame. +Device Orientation +================== + .. lua:class:: attitude - .. lua:attribute:: pitch: number + Represents a measurement of your device attitude. This orientation of a body relative to a given frame of reference. - The pitch of the device, in radians. + You can set ``motion.attitude.referenceFrame`` to specify the frame of reference in which the attitude is expressed. - .. lua:attribute:: yaw: number + The value can be one of the following ``motion.referenceFrame.XArbitraryZVertical``, ``motion.referenceFrame.XArbitraryCorrectedZVertical``, ``motion.referenceFrame.XMagneticNorthZVertical``, ``motion.referenceFrame.XTrueNorthZVertical``. - The yaw of the device, in radians. + :param pitch: The pitch of the device, in radians. + :type pitch: number - .. lua:attribute:: roll: number + :param yaw: The yaw of the device, in radians. + :type yaw: number - The roll of the device, in radians. + :param roll: The roll of the device, in radians. + :type roll: number - .. lua:attribute:: rotationMatrix: mat3x3 + :param rotationMatrix: The rotation matrix that describes the device's orientation. + :type rotationMatrix: mat3x3 - The rotation matrix that describes the device's orientation. + :param quaternion: The quaternion that describes the device's orientation. + :type quaternion: quat - .. lua:attribute:: quaternion: quat + :param referenceFrame: The reference frame in which motion metrics are tracked. + :type referenceFrame: integer - The quaternion that describes the device's orientation. + .. lua:attribute:: XArbitraryZVertical: integer - .. lua:attribute:: referenceFrame: integer + The X-axis is arbitrary and the Z-axis is vertical. - The reference frame in which motion metrics are tracked. + .. lua:attribute:: XArbitraryCorrectedZVertical: integer - The value can be one of the following: + The X-axis is arbitrary and the Z-axis is vertical. The system will attempt to correct for the device's orientation. + + .. lua:attribute:: XMagneticNorthZVertical: integer + + The X-axis points toward the magnetic north and the Z-axis is vertical. + + .. lua:attribute:: XTrueNorthZVertical: integer + + The X-axis points toward the true north and the Z-axis is vertical. - - ``motion.referenceFrame.XArbitraryZVertical``: The X-axis is arbitrary and the Z-axis is vertical. - - ``motion.referenceFrame.XArbitraryCorrectedZVertical``: The X-axis is arbitrary and the Z-axis is vertical. The system will attempt to correct for the device's orientation. - - ``motion.referenceFrame.XMagneticNorthZVertical``: The X-axis points toward the magnetic north and the Z-axis is vertical. - - ``motion.referenceFrame.XTrueNorthZVertical``: The X-axis points toward the true north and the Z-axis is vertical. +Magnetic Field Data +=================== .. lua:class:: magnetic diff --git a/docs/source/api/style.rst b/docs/source/api/style.rst index 7de3150..67f89fb 100644 --- a/docs/source/api/style.rst +++ b/docs/source/api/style.rst @@ -311,7 +311,7 @@ Constants - Blend Factors Blend factor of :math:`(f, f, f, 1)` where :math:`f = min(A_s, 1 - A_d)` Viewport -####### +######## .. lua:function:: viewRect(x, y, w, h) diff --git a/docs/source/builders/luadoc.py b/docs/source/builders/luadoc.py index 1586e14..d34fcb5 100644 --- a/docs/source/builders/luadoc.py +++ b/docs/source/builders/luadoc.py @@ -1,5 +1,7 @@ import json from sphinx.builders import Builder +from sphinx.addnodes import desc, desc_content +from docutils.nodes import field_list, field, paragraph, literal_block, title, section from docutils import nodes from luastruct import * import os @@ -38,34 +40,62 @@ def __init__(self, builder, doc): super().__init__(doc) self.entries = [] self.class_stack = [] + self.current_group = None + self.current_section_content = [] - def visit_section(self, node): - pass - + def __init__(self, builder, doc): + super().__init__(doc) + self.entries = [] + self.class_stack = [] + self.current_group = None + self.current_section_content = [] + + def has_desc_ancestor(self, node): + """Walk up parent chain to check for desc ancestors""" + current = node + while current: + if isinstance(current, desc): + return True + current = current.parent + return False + def visit_paragraph(self, node): - pass + if isinstance(node.parent, section) and not self.has_desc_ancestor(node): + self.current_section_content.append(OverviewContent(node.astext(), OverviewContentKind.TEXT)) - def visit_text(self, node): - pass + def visit_literal_block(self, node): + if isinstance(node.parent, section) and not self.has_desc_ancestor(node): + self.current_section_content.append(OverviewContent(node.astext(), OverviewContentKind.CODE)) def visit_title(self, node): - pass + self.flush_content() + self.current_group = node.astext() - def visit_index(self, node): - pass + def depart_section(self, node): + self.flush_content() + + def flush_content(self): + if self.current_section_content: + self.entries.append(LuaOverview(self.current_section_content, self.current_group)) + self.current_section_content = [] def unknown_visit(self, node): if hasattr(node, 'attributes'): - objtype = node.attributes.get('objtype') + objtype = node.attributes.get('objtype') + + # Flush content before any Lua object + if objtype: + self.flush_content() + if objtype == 'method': - method = LuaFunction(node, 'method') + method = LuaFunction(node, 'method', self.current_group) if self.class_stack: self.class_stack[-1].members.append(method) else: self.entries.append(method) elif objtype == 'class': - cls = LuaClass(node) + cls = LuaClass(node, self.current_group) if self.class_stack: self.class_stack[-1].members.append(cls) self.class_stack.append(cls) @@ -74,22 +104,22 @@ def unknown_visit(self, node): self.class_stack.append(cls) elif objtype == 'function': - self.entries.append(LuaFunction(node, 'function')) + self.entries.append(LuaFunction(node, 'function', self.current_group)) elif objtype == 'attribute': if self.class_stack: - self.class_stack[-1].members.append(LuaAttribute(node, objtype)) + self.class_stack[-1].members.append(LuaAttribute(node, objtype, self.current_group)) else: - self.entries.append(LuaAttribute(node, objtype)) + self.entries.append(LuaAttribute(node, objtype, self.current_group)) elif objtype == 'classattribute': if self.class_stack: - self.class_stack[-1].members.append(LuaAttribute(node, objtype)) + self.class_stack[-1].members.append(LuaAttribute(node, objtype, self.current_group)) else: - self.entries.append(LuaAttribute(node, objtype)) + self.entries.append(LuaAttribute(node, objtype, self.current_group)) elif objtype == 'staticmethod': - method = LuaFunction(node, 'staticmethod') + method = LuaFunction(node, 'staticmethod', self.current_group) if self.class_stack: self.class_stack[-1].members.append(method) else: diff --git a/docs/source/builders/luastruct.py b/docs/source/builders/luastruct.py index 3f9b5ce..910c9c9 100644 --- a/docs/source/builders/luastruct.py +++ b/docs/source/builders/luastruct.py @@ -1,4 +1,5 @@ from docutils import nodes +from enum import Enum class DocutilsUtils: @staticmethod @@ -8,8 +9,22 @@ def extract_name(node): @staticmethod def extract_description(node): - content_node = next((child for child in node.traverse() if child.tagname == 'paragraph'), None) - return content_node.astext() if content_node else None + desc_content = next((child for child in node.children if child.tagname == 'desc_content'), None) + if not desc_content: + return None + + paragraphs = [child for child in desc_content.children if child.tagname == 'paragraph'] + description_parts = [] + for paragraph in paragraphs: + paragraph_text = [] + for child in paragraph.children: + if isinstance(child, nodes.literal): + paragraph_text.append(f"`{child.astext()}`") + else: + paragraph_text.append(child.astext()) + description_parts.append(''.join(paragraph_text)) + + return '\n\n'.join(description_parts) @staticmethod def extract_module(node): @@ -20,12 +35,127 @@ def extract_module(node): # Return None or a default if no module attribute is found return None + + @staticmethod + def extract_parameters(node, isClass = False): + params = [] + param_list = node.next_node(condition=lambda n: n.tagname == 'desc_parameterlist') + # Search for the field list that contains parameter details + field_list = node.next_node(condition=lambda n: n.tagname == 'field_list') + param_details = {} + + if field_list: + for field in field_list.children: + if isinstance(field, nodes.field): + field_name = field.next_node(condition=lambda n: n.tagname == 'field_name') + if field_name and field_name.astext() == "Parameters": + field_body = field.next_node(condition=lambda n: n.tagname == 'field_body') + if field_body: + bullet_list = field_body.next_node(condition=lambda n: n.tagname == 'bullet_list') + if bullet_list: + for list_item in bullet_list.children: + param_name_node = list_item.next_node(condition=lambda n: n.tagname == 'literal_strong') + param_description_nodes = list_item.next_node(condition=lambda n: n.tagname == 'paragraph') + + if param_name_node and param_description_nodes: + param_name = param_name_node.astext().split('=')[0].strip() # Handle default values here if specified + default_value = param_name_node.astext().split('=')[1].strip() if '=' in param_name_node.astext() else None + # Extract the type if available within parenthesis + param_type = None + description_text = param_description_nodes.astext() + + if ('(' in description_text and ')' in description_text): + start = description_text.find('(') + 1 + end = description_text.find(')') + param_type = description_text[start:end] + + # Description often follows the type enclosed in dash + param_description = description_text.split('–')[-1].strip() + param_details[param_name] = { + 'type': param_type, + 'description': param_description, + 'default': default_value + } + + if param_list and isClass == False: + for child in param_list.children: + if child.tagname == 'desc_parameter' or child.tagname == 'desc_optional': + for param_node in child.children: + param_name = param_node.astext().split('=')[0].strip() + default_value = param_node.astext().split('=')[1].strip() if '=' in param_node.astext() else None + optional = child.tagname == 'desc_optional' + param_info = param_details.get(param_name, {}) + params.append(LuaParameter(name=param_name, + type_hint=param_info.get('type'), + optional=optional, + description=param_info.get('description'), + default=default_value or param_info.get('default'))) + elif isClass == True: + for key, value in param_details.items(): + params.append(LuaParameter(name=key, + type_hint=value.get('type'), + optional=False, + description=value.get('description'), + default=value.get('default'))) + + return params + + @staticmethod + def extract_syntax(node): + field_list = node.next_node(condition=lambda n: n.tagname == 'field_list') + if not field_list: + return None + + for field in field_list.children: + if isinstance(field, nodes.field): + field_name = field.next_node(condition=lambda n: n.tagname == 'field_name') + if field_name and field_name.astext() == "Syntax": + field_body = field.next_node(condition=lambda n: n.tagname == 'field_body') + if field_body: + syntax_node = field_body.next_node(condition=lambda n: n.tagname == 'literal_block') + if syntax_node: + return syntax_node.astext() + return None + + @staticmethod + def extract_code_samples(node): + code_samples = [] + for container in node.traverse(condition=lambda n: n.tagname == 'container' and 'literal-block-wrapper' in n['classes']): + caption_node = container.next_node(condition=lambda n: n.tagname == 'caption') + code_node = container.next_node(condition=lambda n: n.tagname == 'literal_block') + if caption_node and code_node: + code_samples.append({ + 'title': caption_node.astext(), + 'code': code_node.astext() + }) + return code_samples + + @staticmethod + def extract_overview(node): + desc_content = next((child for child in node.children if child.tagname == 'desc_content'), None) + if not desc_content: + return None + + paragraphs = [child for child in desc_content.children if child.tagname == 'paragraph'] + overview_parts = [] + for paragraph in paragraphs: + paragraph_text = [] + for child in paragraph.children: + if isinstance(child, nodes.literal): + paragraph_text.append(f"`{child.astext()}`") + else: + paragraph_text.append(child.astext()) + overview_parts.append(''.join(paragraph_text)) + + return '\n\n'.join(overview_parts) class LuaModule: - def __init__(self, node): + def __init__(self, node, group=None): self.name = DocutilsUtils.extract_name(node) self.description = DocutilsUtils.extract_description(node) + self.examples = DocutilsUtils.extract_code_samples(node) + self.group = group def __str__(self): return f"{self.name}\n\t{self.description}" @@ -34,15 +164,24 @@ def to_dict(self): return { 'name': self.name, 'description': self.description, + 'examples': self.examples, + 'group': self.group } class LuaClass: - def __init__(self, node): + def __init__(self, node, group=None): self.name = DocutilsUtils.extract_name(node) self.description = DocutilsUtils.extract_description(node) self.module = DocutilsUtils.extract_module(node) + self.syntax = DocutilsUtils.extract_syntax(node) + self.parameters = DocutilsUtils.extract_parameters(node, True) + self.examples = DocutilsUtils.extract_code_samples(node) + self.group = group self.members = [] + # if self.name == "vec2": + # print(node) + def __str__(self): return f"{self.name} [{self.module}]\n\t{self.description}" @@ -52,6 +191,10 @@ def to_dict(self): 'kind': 'class', 'description': self.description, 'module': self.module, + 'parameters': [p.to_dict() for p in self.parameters], + 'syntax': self.syntax, + 'examples': self.examples, + 'group': self.group, 'members': [members.to_dict() for members in self.members] } @@ -92,58 +235,16 @@ def to_dict(self): } class LuaFunction: - def __init__(self, node, type): + def __init__(self, node, type, group=None): self.name = DocutilsUtils.extract_name(node) self.module = DocutilsUtils.extract_module(node) self.description = DocutilsUtils.extract_description(node) - self.parameters = self.extract_parameters(node) + self.parameters = DocutilsUtils.extract_parameters(node) + self.syntax = DocutilsUtils.extract_syntax(node) + self.examples = DocutilsUtils.extract_code_samples(node) self.returns = self.extract_returns(node) self.type = type - - def extract_parameters(self, node): - params = [] - param_list = node.next_node(condition=lambda n: n.tagname == 'desc_parameterlist') - # Search for the field list that contains parameter details - field_list = node.next_node(condition=lambda n: n.tagname == 'field_list') - param_details = {} - if field_list: - for field in field_list.children: - if isinstance(field, nodes.field): - param_name_node = field.next_node(condition=lambda n: n.tagname == 'literal_strong') - param_description_nodes = field.next_node(condition=lambda n: n.tagname == 'paragraph') - if param_name_node and param_description_nodes: - param_name = param_name_node.astext().split('=')[0].strip() # Handle default values here if specified - default_value = param_name_node.astext().split('=')[1].strip() if '=' in param_name_node.astext() else None - # Extract the type if available within parenthesis - param_type = None - description_text = param_description_nodes.astext() - if '(' in description_text and ')' in description_text: - start = description_text.find('(') + 1 - end = description_text.find(')') - param_type = description_text[start:end] - # Description often follows the type enclosed in dash - param_description = description_text.split('–')[-1].strip() - param_details[param_name] = { - 'type': param_type, - 'description': param_description, - 'default': default_value - } - - if param_list: - for child in param_list.children: - if child.tagname == 'desc_parameter' or child.tagname == 'desc_optional': - for param_node in child.children: - param_name = param_node.astext().split('=')[0].strip() - default_value = param_node.astext().split('=')[1].strip() if '=' in param_node.astext() else None - optional = child.tagname == 'desc_optional' - param_info = param_details.get(param_name, {}) - params.append(LuaParameter(name=param_name, - type_hint=param_info.get('type'), - optional=optional, - description=param_info.get('description'), - default=default_value or param_info.get('default'))) - - return params + self.group = group def extract_returns(self, node): returns = [] @@ -176,18 +277,24 @@ def to_dict(self): 'module': self.module, 'description': self.description, 'parameters': [p.to_dict() for p in self.parameters], + 'syntax': self.syntax, + 'group': self.group, + 'examples': self.examples, 'returns': [r.to_dict() for r in self.returns] } class LuaAttribute: - def __init__(self, node, kind): + def __init__(self, node, kind, group=None): self.name = DocutilsUtils.extract_name(node) self.module = DocutilsUtils.extract_module(node) + self.syntax = DocutilsUtils.extract_syntax(node) + self.examples = DocutilsUtils.extract_code_samples(node) self.default_value = None # Initializing default value self.type = self.extract_type(node) self.description = DocutilsUtils.extract_description(node) self.kind = kind + self.group = group def extract_type(self, node): # Finds the first 'desc_type' element and extracts its text, along with any default value if specified. @@ -214,8 +321,44 @@ def to_dict(self): 'name': self.name, 'kind': self.kind, 'module': self.module, + 'syntax': self.syntax, + 'examples': self.examples, 'type': self.type, + 'group': self.group, 'defaultValue': self.default_value, 'description': self.description } +class LuaOverview: + def __init__(self, content, group=None): + self.content = content + self.group = group + + def __str__(self): + return f"Overview\n\t{self.content}" + + def to_dict(self): + return { + 'kind': 'overview', + 'content': [c.to_dict() for c in self.content], + 'group': self.group + } + +class OverviewContentKind(Enum): + TEXT = "text" + CODE = "code" + +# Class to represent either code block or text content +class OverviewContent: + def __init__(self, content, type: OverviewContentKind): + self.content = content + self.type = type.value + + def __str__(self): + return f"{self.type}: {self.content}" + + def to_dict(self): + return { + 'type': self.type, + 'content': self.content + } \ No newline at end of file