refactor: remove obsolete documentation generators
Removes ~3,979 lines of hardcoded Python documentation dictionaries. Documentation is now generated from C++ docstrings via macros. Deleted: - generate_complete_api_docs.py (959 lines) - generate_complete_markdown_docs.py (820 lines) - generate_api_docs.py (481 lines) - generate_api_docs_simple.py (118 lines) - generate_api_docs_html.py (1,601 lines) Addresses issue #97. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7f253da581
commit
1f6175bfa5
|
|
@ -1,482 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate API reference documentation for McRogueFace.
|
||||
|
||||
This script generates comprehensive API documentation in multiple formats:
|
||||
- Markdown for GitHub/documentation sites
|
||||
- HTML for local browsing
|
||||
- RST for Sphinx integration (future)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
from pathlib import Path
|
||||
|
||||
# We need to run this with McRogueFace as the interpreter
|
||||
# so mcrfpy is available
|
||||
import mcrfpy
|
||||
|
||||
def escape_markdown(text: str) -> str:
|
||||
"""Escape special markdown characters."""
|
||||
if not text:
|
||||
return ""
|
||||
# Escape backticks in inline code
|
||||
return text.replace("`", "\\`")
|
||||
|
||||
def format_signature(name: str, doc: str) -> str:
|
||||
"""Extract and format function signature from docstring."""
|
||||
if not doc:
|
||||
return f"{name}(...)"
|
||||
|
||||
lines = doc.strip().split('\n')
|
||||
if lines and '(' in lines[0]:
|
||||
# First line contains signature
|
||||
return lines[0].split('->')[0].strip()
|
||||
|
||||
return f"{name}(...)"
|
||||
|
||||
def get_class_info(cls: type) -> Dict[str, Any]:
|
||||
"""Extract comprehensive information about a class."""
|
||||
info = {
|
||||
'name': cls.__name__,
|
||||
'doc': cls.__doc__ or "",
|
||||
'methods': [],
|
||||
'properties': [],
|
||||
'bases': [base.__name__ for base in cls.__bases__ if base.__name__ != 'object'],
|
||||
}
|
||||
|
||||
# Get all attributes
|
||||
for attr_name in sorted(dir(cls)):
|
||||
if attr_name.startswith('_') and not attr_name.startswith('__'):
|
||||
continue
|
||||
|
||||
try:
|
||||
attr = getattr(cls, attr_name)
|
||||
|
||||
if isinstance(attr, property):
|
||||
prop_info = {
|
||||
'name': attr_name,
|
||||
'doc': (attr.fget.__doc__ if attr.fget else "") or "",
|
||||
'readonly': attr.fset is None
|
||||
}
|
||||
info['properties'].append(prop_info)
|
||||
elif callable(attr) and not attr_name.startswith('__'):
|
||||
method_info = {
|
||||
'name': attr_name,
|
||||
'doc': attr.__doc__ or "",
|
||||
'signature': format_signature(attr_name, attr.__doc__)
|
||||
}
|
||||
info['methods'].append(method_info)
|
||||
except:
|
||||
pass
|
||||
|
||||
return info
|
||||
|
||||
def get_function_info(func: Any, name: str) -> Dict[str, Any]:
|
||||
"""Extract information about a function."""
|
||||
return {
|
||||
'name': name,
|
||||
'doc': func.__doc__ or "",
|
||||
'signature': format_signature(name, func.__doc__)
|
||||
}
|
||||
|
||||
def generate_markdown_class(cls_info: Dict[str, Any]) -> List[str]:
|
||||
"""Generate markdown documentation for a class."""
|
||||
lines = []
|
||||
|
||||
# Class header
|
||||
lines.append(f"### class `{cls_info['name']}`")
|
||||
if cls_info['bases']:
|
||||
lines.append(f"*Inherits from: {', '.join(cls_info['bases'])}*")
|
||||
lines.append("")
|
||||
|
||||
# Class description
|
||||
if cls_info['doc']:
|
||||
doc_lines = cls_info['doc'].strip().split('\n')
|
||||
# First line is usually the constructor signature
|
||||
if doc_lines and '(' in doc_lines[0]:
|
||||
lines.append(f"```python")
|
||||
lines.append(doc_lines[0])
|
||||
lines.append("```")
|
||||
lines.append("")
|
||||
# Rest is description
|
||||
if len(doc_lines) > 2:
|
||||
lines.extend(doc_lines[2:])
|
||||
lines.append("")
|
||||
else:
|
||||
lines.extend(doc_lines)
|
||||
lines.append("")
|
||||
|
||||
# Properties
|
||||
if cls_info['properties']:
|
||||
lines.append("#### Properties")
|
||||
lines.append("")
|
||||
for prop in cls_info['properties']:
|
||||
readonly = " *(readonly)*" if prop['readonly'] else ""
|
||||
lines.append(f"- **`{prop['name']}`**{readonly}")
|
||||
if prop['doc']:
|
||||
lines.append(f" - {prop['doc'].strip()}")
|
||||
lines.append("")
|
||||
|
||||
# Methods
|
||||
if cls_info['methods']:
|
||||
lines.append("#### Methods")
|
||||
lines.append("")
|
||||
for method in cls_info['methods']:
|
||||
lines.append(f"##### `{method['signature']}`")
|
||||
if method['doc']:
|
||||
# Parse docstring for better formatting
|
||||
doc_lines = method['doc'].strip().split('\n')
|
||||
# Skip the signature line if it's repeated
|
||||
start = 1 if doc_lines and method['name'] in doc_lines[0] else 0
|
||||
for line in doc_lines[start:]:
|
||||
lines.append(line)
|
||||
lines.append("")
|
||||
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
def generate_markdown_function(func_info: Dict[str, Any]) -> List[str]:
|
||||
"""Generate markdown documentation for a function."""
|
||||
lines = []
|
||||
|
||||
lines.append(f"### `{func_info['signature']}`")
|
||||
lines.append("")
|
||||
|
||||
if func_info['doc']:
|
||||
doc_lines = func_info['doc'].strip().split('\n')
|
||||
# Skip signature line if present
|
||||
start = 1 if doc_lines and func_info['name'] in doc_lines[0] else 0
|
||||
|
||||
# Process documentation sections
|
||||
in_section = None
|
||||
for line in doc_lines[start:]:
|
||||
if line.strip() in ['Args:', 'Returns:', 'Raises:', 'Note:', 'Example:']:
|
||||
in_section = line.strip()
|
||||
lines.append(f"**{in_section}**")
|
||||
elif in_section and line.strip():
|
||||
# Indent content under sections
|
||||
lines.append(f"{line}")
|
||||
else:
|
||||
lines.append(line)
|
||||
lines.append("")
|
||||
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
def generate_markdown_docs() -> str:
|
||||
"""Generate complete markdown API documentation."""
|
||||
lines = []
|
||||
|
||||
# Header
|
||||
lines.append("# McRogueFace API Reference")
|
||||
lines.append("")
|
||||
lines.append(f"*Generated on {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*")
|
||||
lines.append("")
|
||||
|
||||
# Module description
|
||||
if mcrfpy.__doc__:
|
||||
lines.append("## Overview")
|
||||
lines.append("")
|
||||
lines.extend(mcrfpy.__doc__.strip().split('\n'))
|
||||
lines.append("")
|
||||
|
||||
# Table of contents
|
||||
lines.append("## Table of Contents")
|
||||
lines.append("")
|
||||
lines.append("- [Classes](#classes)")
|
||||
lines.append("- [Functions](#functions)")
|
||||
lines.append("- [Automation Module](#automation-module)")
|
||||
lines.append("")
|
||||
|
||||
# Collect all components
|
||||
classes = []
|
||||
functions = []
|
||||
constants = []
|
||||
|
||||
for name in sorted(dir(mcrfpy)):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
|
||||
obj = getattr(mcrfpy, name)
|
||||
|
||||
if isinstance(obj, type):
|
||||
classes.append((name, obj))
|
||||
elif callable(obj):
|
||||
functions.append((name, obj))
|
||||
elif not inspect.ismodule(obj):
|
||||
constants.append((name, obj))
|
||||
|
||||
# Document classes
|
||||
lines.append("## Classes")
|
||||
lines.append("")
|
||||
|
||||
# Group classes by category
|
||||
ui_classes = []
|
||||
collection_classes = []
|
||||
system_classes = []
|
||||
other_classes = []
|
||||
|
||||
for name, cls in classes:
|
||||
if name in ['Frame', 'Caption', 'Sprite', 'Grid', 'Entity']:
|
||||
ui_classes.append((name, cls))
|
||||
elif 'Collection' in name:
|
||||
collection_classes.append((name, cls))
|
||||
elif name in ['Color', 'Vector', 'Texture', 'Font']:
|
||||
system_classes.append((name, cls))
|
||||
else:
|
||||
other_classes.append((name, cls))
|
||||
|
||||
# UI Classes
|
||||
if ui_classes:
|
||||
lines.append("### UI Components")
|
||||
lines.append("")
|
||||
for name, cls in ui_classes:
|
||||
lines.extend(generate_markdown_class(get_class_info(cls)))
|
||||
|
||||
# Collections
|
||||
if collection_classes:
|
||||
lines.append("### Collections")
|
||||
lines.append("")
|
||||
for name, cls in collection_classes:
|
||||
lines.extend(generate_markdown_class(get_class_info(cls)))
|
||||
|
||||
# System Classes
|
||||
if system_classes:
|
||||
lines.append("### System Types")
|
||||
lines.append("")
|
||||
for name, cls in system_classes:
|
||||
lines.extend(generate_markdown_class(get_class_info(cls)))
|
||||
|
||||
# Other Classes
|
||||
if other_classes:
|
||||
lines.append("### Other Classes")
|
||||
lines.append("")
|
||||
for name, cls in other_classes:
|
||||
lines.extend(generate_markdown_class(get_class_info(cls)))
|
||||
|
||||
# Document functions
|
||||
lines.append("## Functions")
|
||||
lines.append("")
|
||||
|
||||
# Group functions by category
|
||||
scene_funcs = []
|
||||
audio_funcs = []
|
||||
ui_funcs = []
|
||||
system_funcs = []
|
||||
|
||||
for name, func in functions:
|
||||
if 'scene' in name.lower() or name in ['createScene', 'setScene']:
|
||||
scene_funcs.append((name, func))
|
||||
elif any(x in name.lower() for x in ['sound', 'music', 'volume']):
|
||||
audio_funcs.append((name, func))
|
||||
elif name in ['find', 'findAll']:
|
||||
ui_funcs.append((name, func))
|
||||
else:
|
||||
system_funcs.append((name, func))
|
||||
|
||||
# Scene Management
|
||||
if scene_funcs:
|
||||
lines.append("### Scene Management")
|
||||
lines.append("")
|
||||
for name, func in scene_funcs:
|
||||
lines.extend(generate_markdown_function(get_function_info(func, name)))
|
||||
|
||||
# Audio
|
||||
if audio_funcs:
|
||||
lines.append("### Audio")
|
||||
lines.append("")
|
||||
for name, func in audio_funcs:
|
||||
lines.extend(generate_markdown_function(get_function_info(func, name)))
|
||||
|
||||
# UI Utilities
|
||||
if ui_funcs:
|
||||
lines.append("### UI Utilities")
|
||||
lines.append("")
|
||||
for name, func in ui_funcs:
|
||||
lines.extend(generate_markdown_function(get_function_info(func, name)))
|
||||
|
||||
# System
|
||||
if system_funcs:
|
||||
lines.append("### System")
|
||||
lines.append("")
|
||||
for name, func in system_funcs:
|
||||
lines.extend(generate_markdown_function(get_function_info(func, name)))
|
||||
|
||||
# Automation module
|
||||
if hasattr(mcrfpy, 'automation'):
|
||||
lines.append("## Automation Module")
|
||||
lines.append("")
|
||||
lines.append("The `mcrfpy.automation` module provides testing and automation capabilities.")
|
||||
lines.append("")
|
||||
|
||||
automation = mcrfpy.automation
|
||||
auto_funcs = []
|
||||
|
||||
for name in sorted(dir(automation)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(automation, name)
|
||||
if callable(obj):
|
||||
auto_funcs.append((name, obj))
|
||||
|
||||
for name, func in auto_funcs:
|
||||
# Format as static method
|
||||
func_info = get_function_info(func, name)
|
||||
lines.append(f"### `automation.{func_info['signature']}`")
|
||||
lines.append("")
|
||||
if func_info['doc']:
|
||||
lines.append(func_info['doc'])
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def generate_html_docs(markdown_content: str) -> str:
|
||||
"""Convert markdown to HTML."""
|
||||
# Simple conversion - in production use a proper markdown parser
|
||||
html = ['<!DOCTYPE html>']
|
||||
html.append('<html><head>')
|
||||
html.append('<meta charset="UTF-8">')
|
||||
html.append('<title>McRogueFace API Reference</title>')
|
||||
html.append('<style>')
|
||||
html.append('''
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
line-height: 1.6; color: #333; max-width: 900px; margin: 0 auto; padding: 20px; }
|
||||
h1, h2, h3, h4, h5 { color: #2c3e50; margin-top: 24px; }
|
||||
h1 { border-bottom: 2px solid #3498db; padding-bottom: 10px; }
|
||||
h2 { border-bottom: 1px solid #ecf0f1; padding-bottom: 8px; }
|
||||
code { background: #f4f4f4; padding: 2px 4px; border-radius: 3px; font-size: 90%; }
|
||||
pre { background: #f4f4f4; padding: 12px; border-radius: 5px; overflow-x: auto; }
|
||||
pre code { background: none; padding: 0; }
|
||||
blockquote { border-left: 4px solid #3498db; margin: 0; padding-left: 16px; color: #7f8c8d; }
|
||||
hr { border: none; border-top: 1px solid #ecf0f1; margin: 24px 0; }
|
||||
a { color: #3498db; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.property { color: #27ae60; }
|
||||
.method { color: #2980b9; }
|
||||
.class-name { color: #8e44ad; font-weight: bold; }
|
||||
ul { padding-left: 24px; }
|
||||
li { margin: 4px 0; }
|
||||
''')
|
||||
html.append('</style>')
|
||||
html.append('</head><body>')
|
||||
|
||||
# Very basic markdown to HTML conversion
|
||||
lines = markdown_content.split('\n')
|
||||
in_code_block = False
|
||||
in_list = False
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
|
||||
if stripped.startswith('```'):
|
||||
if in_code_block:
|
||||
html.append('</code></pre>')
|
||||
in_code_block = False
|
||||
else:
|
||||
lang = stripped[3:] or 'python'
|
||||
html.append(f'<pre><code class="language-{lang}">')
|
||||
in_code_block = True
|
||||
continue
|
||||
|
||||
if in_code_block:
|
||||
html.append(line)
|
||||
continue
|
||||
|
||||
# Headers
|
||||
if stripped.startswith('#'):
|
||||
level = len(stripped.split()[0])
|
||||
text = stripped[level:].strip()
|
||||
html.append(f'<h{level}>{text}</h{level}>')
|
||||
# Lists
|
||||
elif stripped.startswith('- '):
|
||||
if not in_list:
|
||||
html.append('<ul>')
|
||||
in_list = True
|
||||
html.append(f'<li>{stripped[2:]}</li>')
|
||||
# Horizontal rule
|
||||
elif stripped == '---':
|
||||
if in_list:
|
||||
html.append('</ul>')
|
||||
in_list = False
|
||||
html.append('<hr>')
|
||||
# Emphasis
|
||||
elif stripped.startswith('*') and stripped.endswith('*') and len(stripped) > 2:
|
||||
html.append(f'<em>{stripped[1:-1]}</em>')
|
||||
# Bold
|
||||
elif stripped.startswith('**') and stripped.endswith('**'):
|
||||
html.append(f'<strong>{stripped[2:-2]}</strong>')
|
||||
# Regular paragraph
|
||||
elif stripped:
|
||||
if in_list:
|
||||
html.append('</ul>')
|
||||
in_list = False
|
||||
# Convert inline code
|
||||
text = stripped
|
||||
if '`' in text:
|
||||
import re
|
||||
text = re.sub(r'`([^`]+)`', r'<code>\1</code>', text)
|
||||
html.append(f'<p>{text}</p>')
|
||||
else:
|
||||
if in_list:
|
||||
html.append('</ul>')
|
||||
in_list = False
|
||||
# Empty line
|
||||
html.append('')
|
||||
|
||||
if in_list:
|
||||
html.append('</ul>')
|
||||
if in_code_block:
|
||||
html.append('</code></pre>')
|
||||
|
||||
html.append('</body></html>')
|
||||
return '\n'.join(html)
|
||||
|
||||
def main():
|
||||
"""Generate API documentation in multiple formats."""
|
||||
print("Generating McRogueFace API Documentation...")
|
||||
|
||||
# Create docs directory
|
||||
docs_dir = Path("docs")
|
||||
docs_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Generate markdown documentation
|
||||
print("- Generating Markdown documentation...")
|
||||
markdown_content = generate_markdown_docs()
|
||||
|
||||
# Write markdown
|
||||
md_path = docs_dir / "API_REFERENCE.md"
|
||||
with open(md_path, 'w') as f:
|
||||
f.write(markdown_content)
|
||||
print(f" ✓ Written to {md_path}")
|
||||
|
||||
# Generate HTML
|
||||
print("- Generating HTML documentation...")
|
||||
html_content = generate_html_docs(markdown_content)
|
||||
|
||||
# Write HTML
|
||||
html_path = docs_dir / "api_reference.html"
|
||||
with open(html_path, 'w') as f:
|
||||
f.write(html_content)
|
||||
print(f" ✓ Written to {html_path}")
|
||||
|
||||
# Summary statistics
|
||||
lines = markdown_content.split('\n')
|
||||
class_count = markdown_content.count('### class')
|
||||
func_count = len([l for l in lines if l.strip().startswith('### `') and 'class' not in l])
|
||||
|
||||
print("\nDocumentation Statistics:")
|
||||
print(f"- Classes documented: {class_count}")
|
||||
print(f"- Functions documented: {func_count}")
|
||||
print(f"- Total lines: {len(lines)}")
|
||||
print(f"- File size: {len(markdown_content):,} bytes")
|
||||
|
||||
print("\nAPI documentation generated successfully!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,119 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate API reference documentation for McRogueFace - Simple version."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
|
||||
import mcrfpy
|
||||
|
||||
def generate_markdown_docs():
|
||||
"""Generate markdown API documentation."""
|
||||
lines = []
|
||||
|
||||
# Header
|
||||
lines.append("# McRogueFace API Reference")
|
||||
lines.append("")
|
||||
lines.append("*Generated on {}*".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
|
||||
lines.append("")
|
||||
|
||||
# Module description
|
||||
if mcrfpy.__doc__:
|
||||
lines.append("## Overview")
|
||||
lines.append("")
|
||||
lines.extend(mcrfpy.__doc__.strip().split('\n'))
|
||||
lines.append("")
|
||||
|
||||
# Collect all components
|
||||
classes = []
|
||||
functions = []
|
||||
|
||||
for name in sorted(dir(mcrfpy)):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
|
||||
obj = getattr(mcrfpy, name)
|
||||
|
||||
if isinstance(obj, type):
|
||||
classes.append((name, obj))
|
||||
elif callable(obj):
|
||||
functions.append((name, obj))
|
||||
|
||||
# Document classes
|
||||
lines.append("## Classes")
|
||||
lines.append("")
|
||||
|
||||
for name, cls in classes:
|
||||
lines.append("### class {}".format(name))
|
||||
if cls.__doc__:
|
||||
doc_lines = cls.__doc__.strip().split('\n')
|
||||
for line in doc_lines[:5]: # First 5 lines
|
||||
lines.append(line)
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
# Document functions
|
||||
lines.append("## Functions")
|
||||
lines.append("")
|
||||
|
||||
for name, func in functions:
|
||||
lines.append("### {}".format(name))
|
||||
if func.__doc__:
|
||||
doc_lines = func.__doc__.strip().split('\n')
|
||||
for line in doc_lines[:5]: # First 5 lines
|
||||
lines.append(line)
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
# Automation module
|
||||
if hasattr(mcrfpy, 'automation'):
|
||||
lines.append("## Automation Module")
|
||||
lines.append("")
|
||||
|
||||
automation = mcrfpy.automation
|
||||
for name in sorted(dir(automation)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(automation, name)
|
||||
if callable(obj):
|
||||
lines.append("### automation.{}".format(name))
|
||||
if obj.__doc__:
|
||||
lines.append(obj.__doc__.strip().split('\n')[0])
|
||||
lines.append("")
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def main():
|
||||
"""Generate API documentation."""
|
||||
print("Generating McRogueFace API Documentation...")
|
||||
|
||||
# Create docs directory
|
||||
docs_dir = Path("docs")
|
||||
docs_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Generate markdown
|
||||
markdown_content = generate_markdown_docs()
|
||||
|
||||
# Write markdown
|
||||
md_path = docs_dir / "API_REFERENCE.md"
|
||||
with open(md_path, 'w') as f:
|
||||
f.write(markdown_content)
|
||||
print("Written to {}".format(md_path))
|
||||
|
||||
# Summary
|
||||
lines = markdown_content.split('\n')
|
||||
class_count = markdown_content.count('### class')
|
||||
func_count = markdown_content.count('### ') - class_count - markdown_content.count('### automation.')
|
||||
|
||||
print("\nDocumentation Statistics:")
|
||||
print("- Classes documented: {}".format(class_count))
|
||||
print("- Functions documented: {}".format(func_count))
|
||||
print("- Total lines: {}".format(len(lines)))
|
||||
|
||||
print("\nAPI documentation generated successfully!")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,960 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate COMPLETE HTML API reference documentation for McRogueFace with NO missing methods."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import html
|
||||
from pathlib import Path
|
||||
import mcrfpy
|
||||
|
||||
def escape_html(text: str) -> str:
|
||||
"""Escape HTML special characters."""
|
||||
return html.escape(text) if text else ""
|
||||
|
||||
def get_complete_method_documentation():
|
||||
"""Return complete documentation for ALL methods across all classes."""
|
||||
return {
|
||||
# Base Drawable methods (inherited by all UI elements)
|
||||
'Drawable': {
|
||||
'get_bounds': {
|
||||
'signature': 'get_bounds()',
|
||||
'description': 'Get the bounding rectangle of this drawable element.',
|
||||
'returns': 'tuple: (x, y, width, height) representing the element\'s bounds',
|
||||
'note': 'The bounds are in screen coordinates and account for current position and size.'
|
||||
},
|
||||
'move': {
|
||||
'signature': 'move(dx, dy)',
|
||||
'description': 'Move the element by a relative offset.',
|
||||
'args': [
|
||||
('dx', 'float', 'Horizontal offset in pixels'),
|
||||
('dy', 'float', 'Vertical offset in pixels')
|
||||
],
|
||||
'note': 'This modifies the x and y position properties by the given amounts.'
|
||||
},
|
||||
'resize': {
|
||||
'signature': 'resize(width, height)',
|
||||
'description': 'Resize the element to new dimensions.',
|
||||
'args': [
|
||||
('width', 'float', 'New width in pixels'),
|
||||
('height', 'float', 'New height in pixels')
|
||||
],
|
||||
'note': 'For Caption and Sprite, this may not change actual size if determined by content.'
|
||||
}
|
||||
},
|
||||
|
||||
# Entity-specific methods
|
||||
'Entity': {
|
||||
'at': {
|
||||
'signature': 'at(x, y)',
|
||||
'description': 'Check if this entity is at the specified grid coordinates.',
|
||||
'args': [
|
||||
('x', 'int', 'Grid x coordinate to check'),
|
||||
('y', 'int', 'Grid y coordinate to check')
|
||||
],
|
||||
'returns': 'bool: True if entity is at position (x, y), False otherwise'
|
||||
},
|
||||
'die': {
|
||||
'signature': 'die()',
|
||||
'description': 'Remove this entity from its parent grid.',
|
||||
'note': 'The entity object remains valid but is no longer rendered or updated.'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index()',
|
||||
'description': 'Get the index of this entity in its parent grid\'s entity list.',
|
||||
'returns': 'int: Index position, or -1 if not in a grid'
|
||||
}
|
||||
},
|
||||
|
||||
# Grid-specific methods
|
||||
'Grid': {
|
||||
'at': {
|
||||
'signature': 'at(x, y)',
|
||||
'description': 'Get the GridPoint at the specified grid coordinates.',
|
||||
'args': [
|
||||
('x', 'int', 'Grid x coordinate'),
|
||||
('y', 'int', 'Grid y coordinate')
|
||||
],
|
||||
'returns': 'GridPoint or None: The grid point at (x, y), or None if out of bounds'
|
||||
}
|
||||
},
|
||||
|
||||
# Collection methods
|
||||
'EntityCollection': {
|
||||
'append': {
|
||||
'signature': 'append(entity)',
|
||||
'description': 'Add an entity to the end of the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to add')]
|
||||
},
|
||||
'remove': {
|
||||
'signature': 'remove(entity)',
|
||||
'description': 'Remove the first occurrence of an entity from the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to remove')],
|
||||
'raises': 'ValueError: If entity is not in collection'
|
||||
},
|
||||
'extend': {
|
||||
'signature': 'extend(iterable)',
|
||||
'description': 'Add all entities from an iterable to the collection.',
|
||||
'args': [('iterable', 'Iterable[Entity]', 'Entities to add')]
|
||||
},
|
||||
'count': {
|
||||
'signature': 'count(entity)',
|
||||
'description': 'Count the number of occurrences of an entity in the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to count')],
|
||||
'returns': 'int: Number of times entity appears in collection'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index(entity)',
|
||||
'description': 'Find the index of the first occurrence of an entity.',
|
||||
'args': [('entity', 'Entity', 'The entity to find')],
|
||||
'returns': 'int: Index of entity in collection',
|
||||
'raises': 'ValueError: If entity is not in collection'
|
||||
}
|
||||
},
|
||||
|
||||
'UICollection': {
|
||||
'append': {
|
||||
'signature': 'append(drawable)',
|
||||
'description': 'Add a drawable element to the end of the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable element to add')]
|
||||
},
|
||||
'remove': {
|
||||
'signature': 'remove(drawable)',
|
||||
'description': 'Remove the first occurrence of a drawable from the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to remove')],
|
||||
'raises': 'ValueError: If drawable is not in collection'
|
||||
},
|
||||
'extend': {
|
||||
'signature': 'extend(iterable)',
|
||||
'description': 'Add all drawables from an iterable to the collection.',
|
||||
'args': [('iterable', 'Iterable[UIDrawable]', 'Drawables to add')]
|
||||
},
|
||||
'count': {
|
||||
'signature': 'count(drawable)',
|
||||
'description': 'Count the number of occurrences of a drawable in the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to count')],
|
||||
'returns': 'int: Number of times drawable appears in collection'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index(drawable)',
|
||||
'description': 'Find the index of the first occurrence of a drawable.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to find')],
|
||||
'returns': 'int: Index of drawable in collection',
|
||||
'raises': 'ValueError: If drawable is not in collection'
|
||||
}
|
||||
},
|
||||
|
||||
# Animation methods
|
||||
'Animation': {
|
||||
'get_current_value': {
|
||||
'signature': 'get_current_value()',
|
||||
'description': 'Get the current interpolated value of the animation.',
|
||||
'returns': 'float: Current animation value between start and end'
|
||||
},
|
||||
'start': {
|
||||
'signature': 'start(target)',
|
||||
'description': 'Start the animation on a target UI element.',
|
||||
'args': [('target', 'UIDrawable', 'The UI element to animate')],
|
||||
'note': 'The target must have the property specified in the animation constructor.'
|
||||
},
|
||||
'update': {
|
||||
'signature': 'update(delta_time)',
|
||||
'description': 'Update the animation by the given time delta.',
|
||||
'args': [('delta_time', 'float', 'Time elapsed since last update in seconds')],
|
||||
'returns': 'bool: True if animation is still running, False if finished'
|
||||
}
|
||||
},
|
||||
|
||||
# Color methods
|
||||
'Color': {
|
||||
'from_hex': {
|
||||
'signature': 'from_hex(hex_string)',
|
||||
'description': 'Create a Color from a hexadecimal color string.',
|
||||
'args': [('hex_string', 'str', 'Hex color string (e.g., "#FF0000" or "FF0000")')],
|
||||
'returns': 'Color: New Color object from hex string',
|
||||
'example': 'red = Color.from_hex("#FF0000")'
|
||||
},
|
||||
'to_hex': {
|
||||
'signature': 'to_hex()',
|
||||
'description': 'Convert this Color to a hexadecimal string.',
|
||||
'returns': 'str: Hex color string in format "#RRGGBB"',
|
||||
'example': 'hex_str = color.to_hex() # Returns "#FF0000"'
|
||||
},
|
||||
'lerp': {
|
||||
'signature': 'lerp(other, t)',
|
||||
'description': 'Linearly interpolate between this color and another.',
|
||||
'args': [
|
||||
('other', 'Color', 'The color to interpolate towards'),
|
||||
('t', 'float', 'Interpolation factor from 0.0 to 1.0')
|
||||
],
|
||||
'returns': 'Color: New interpolated Color object',
|
||||
'example': 'mixed = red.lerp(blue, 0.5) # 50% between red and blue'
|
||||
}
|
||||
},
|
||||
|
||||
# Vector methods
|
||||
'Vector': {
|
||||
'magnitude': {
|
||||
'signature': 'magnitude()',
|
||||
'description': 'Calculate the length/magnitude of this vector.',
|
||||
'returns': 'float: The magnitude of the vector',
|
||||
'example': 'length = vector.magnitude()'
|
||||
},
|
||||
'magnitude_squared': {
|
||||
'signature': 'magnitude_squared()',
|
||||
'description': 'Calculate the squared magnitude of this vector.',
|
||||
'returns': 'float: The squared magnitude (faster than magnitude())',
|
||||
'note': 'Use this for comparisons to avoid expensive square root calculation.'
|
||||
},
|
||||
'normalize': {
|
||||
'signature': 'normalize()',
|
||||
'description': 'Return a unit vector in the same direction.',
|
||||
'returns': 'Vector: New normalized vector with magnitude 1.0',
|
||||
'raises': 'ValueError: If vector has zero magnitude'
|
||||
},
|
||||
'dot': {
|
||||
'signature': 'dot(other)',
|
||||
'description': 'Calculate the dot product with another vector.',
|
||||
'args': [('other', 'Vector', 'The other vector')],
|
||||
'returns': 'float: Dot product of the two vectors'
|
||||
},
|
||||
'distance_to': {
|
||||
'signature': 'distance_to(other)',
|
||||
'description': 'Calculate the distance to another vector.',
|
||||
'args': [('other', 'Vector', 'The other vector')],
|
||||
'returns': 'float: Distance between the two vectors'
|
||||
},
|
||||
'angle': {
|
||||
'signature': 'angle()',
|
||||
'description': 'Get the angle of this vector in radians.',
|
||||
'returns': 'float: Angle in radians from positive x-axis'
|
||||
},
|
||||
'copy': {
|
||||
'signature': 'copy()',
|
||||
'description': 'Create a copy of this vector.',
|
||||
'returns': 'Vector: New Vector object with same x and y values'
|
||||
}
|
||||
},
|
||||
|
||||
# Scene methods
|
||||
'Scene': {
|
||||
'activate': {
|
||||
'signature': 'activate()',
|
||||
'description': 'Make this scene the active scene.',
|
||||
'note': 'Equivalent to calling setScene() with this scene\'s name.'
|
||||
},
|
||||
'get_ui': {
|
||||
'signature': 'get_ui()',
|
||||
'description': 'Get the UI element collection for this scene.',
|
||||
'returns': 'UICollection: Collection of all UI elements in this scene'
|
||||
},
|
||||
'keypress': {
|
||||
'signature': 'keypress(handler)',
|
||||
'description': 'Register a keyboard handler function for this scene.',
|
||||
'args': [('handler', 'callable', 'Function that takes (key_name: str, is_pressed: bool)')],
|
||||
'note': 'Alternative to overriding the on_keypress method.'
|
||||
},
|
||||
'register_keyboard': {
|
||||
'signature': 'register_keyboard(callable)',
|
||||
'description': 'Register a keyboard event handler function for the scene.',
|
||||
'args': [('callable', 'callable', 'Function that takes (key: str, action: str) parameters')],
|
||||
'note': 'Alternative to overriding the on_keypress method when subclassing Scene objects.',
|
||||
'example': '''def handle_keyboard(key, action):
|
||||
print(f"Key '{key}' was {action}")
|
||||
if key == "q" and action == "press":
|
||||
# Handle quit
|
||||
pass
|
||||
scene.register_keyboard(handle_keyboard)'''
|
||||
}
|
||||
},
|
||||
|
||||
# Timer methods
|
||||
'Timer': {
|
||||
'pause': {
|
||||
'signature': 'pause()',
|
||||
'description': 'Pause the timer, stopping its callback execution.',
|
||||
'note': 'Use resume() to continue the timer from where it was paused.'
|
||||
},
|
||||
'resume': {
|
||||
'signature': 'resume()',
|
||||
'description': 'Resume a paused timer.',
|
||||
'note': 'Has no effect if timer is not paused.'
|
||||
},
|
||||
'cancel': {
|
||||
'signature': 'cancel()',
|
||||
'description': 'Cancel the timer and remove it from the system.',
|
||||
'note': 'After cancelling, the timer object cannot be reused.'
|
||||
},
|
||||
'restart': {
|
||||
'signature': 'restart()',
|
||||
'description': 'Restart the timer from the beginning.',
|
||||
'note': 'Resets the timer\'s internal clock to zero.'
|
||||
}
|
||||
},
|
||||
|
||||
# Window methods
|
||||
'Window': {
|
||||
'get': {
|
||||
'signature': 'get()',
|
||||
'description': 'Get the Window singleton instance.',
|
||||
'returns': 'Window: The singleton window object',
|
||||
'note': 'This is a static method that returns the same instance every time.'
|
||||
},
|
||||
'center': {
|
||||
'signature': 'center()',
|
||||
'description': 'Center the window on the screen.',
|
||||
'note': 'Only works if the window is not fullscreen.'
|
||||
},
|
||||
'screenshot': {
|
||||
'signature': 'screenshot(filename)',
|
||||
'description': 'Take a screenshot and save it to a file.',
|
||||
'args': [('filename', 'str', 'Path where to save the screenshot')],
|
||||
'note': 'Supports PNG, JPG, and BMP formats based on file extension.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_complete_function_documentation():
|
||||
"""Return complete documentation for ALL module functions."""
|
||||
return {
|
||||
# Scene Management
|
||||
'createScene': {
|
||||
'signature': 'createScene(name: str) -> None',
|
||||
'description': 'Create a new empty scene with the given name.',
|
||||
'args': [('name', 'str', 'Unique name for the new scene')],
|
||||
'raises': 'ValueError: If a scene with this name already exists',
|
||||
'note': 'The scene is created but not made active. Use setScene() to switch to it.',
|
||||
'example': 'mcrfpy.createScene("game_over")'
|
||||
},
|
||||
'setScene': {
|
||||
'signature': 'setScene(scene: str, transition: str = None, duration: float = 0.0) -> None',
|
||||
'description': 'Switch to a different scene with optional transition effect.',
|
||||
'args': [
|
||||
('scene', 'str', 'Name of the scene to switch to'),
|
||||
('transition', 'str', 'Transition type: "fade", "slide_left", "slide_right", "slide_up", "slide_down"'),
|
||||
('duration', 'float', 'Transition duration in seconds (default: 0.0 for instant)')
|
||||
],
|
||||
'raises': 'KeyError: If the scene doesn\'t exist',
|
||||
'example': 'mcrfpy.setScene("game", "fade", 0.5)'
|
||||
},
|
||||
'currentScene': {
|
||||
'signature': 'currentScene() -> str',
|
||||
'description': 'Get the name of the currently active scene.',
|
||||
'returns': 'str: Name of the current scene',
|
||||
'example': 'scene_name = mcrfpy.currentScene()'
|
||||
},
|
||||
'sceneUI': {
|
||||
'signature': 'sceneUI(scene: str = None) -> UICollection',
|
||||
'description': 'Get all UI elements for a scene.',
|
||||
'args': [('scene', 'str', 'Scene name. If None, uses current scene')],
|
||||
'returns': 'UICollection: All UI elements in the scene',
|
||||
'raises': 'KeyError: If the specified scene doesn\'t exist',
|
||||
'example': 'ui_elements = mcrfpy.sceneUI("game")'
|
||||
},
|
||||
'keypressScene': {
|
||||
'signature': 'keypressScene(handler: callable) -> None',
|
||||
'description': 'Set the keyboard event handler for the current scene.',
|
||||
'args': [('handler', 'callable', 'Function that receives (key_name: str, is_pressed: bool)')],
|
||||
'example': '''def on_key(key, pressed):
|
||||
if key == "SPACE" and pressed:
|
||||
player.jump()
|
||||
mcrfpy.keypressScene(on_key)'''
|
||||
},
|
||||
|
||||
# Audio Functions
|
||||
'createSoundBuffer': {
|
||||
'signature': 'createSoundBuffer(filename: str) -> int',
|
||||
'description': 'Load a sound effect from a file and return its buffer ID.',
|
||||
'args': [('filename', 'str', 'Path to the sound file (WAV, OGG, FLAC)')],
|
||||
'returns': 'int: Buffer ID for use with playSound()',
|
||||
'raises': 'RuntimeError: If the file cannot be loaded',
|
||||
'example': 'jump_sound = mcrfpy.createSoundBuffer("assets/jump.wav")'
|
||||
},
|
||||
'loadMusic': {
|
||||
'signature': 'loadMusic(filename: str, loop: bool = True) -> None',
|
||||
'description': 'Load and immediately play background music from a file.',
|
||||
'args': [
|
||||
('filename', 'str', 'Path to the music file (WAV, OGG, FLAC)'),
|
||||
('loop', 'bool', 'Whether to loop the music (default: True)')
|
||||
],
|
||||
'note': 'Only one music track can play at a time. Loading new music stops the current track.',
|
||||
'example': 'mcrfpy.loadMusic("assets/background.ogg", True)'
|
||||
},
|
||||
'playSound': {
|
||||
'signature': 'playSound(buffer_id: int) -> None',
|
||||
'description': 'Play a sound effect using a previously loaded buffer.',
|
||||
'args': [('buffer_id', 'int', 'Sound buffer ID returned by createSoundBuffer()')],
|
||||
'raises': 'RuntimeError: If the buffer ID is invalid',
|
||||
'example': 'mcrfpy.playSound(jump_sound)'
|
||||
},
|
||||
'getMusicVolume': {
|
||||
'signature': 'getMusicVolume() -> int',
|
||||
'description': 'Get the current music volume level.',
|
||||
'returns': 'int: Current volume (0-100)',
|
||||
'example': 'current_volume = mcrfpy.getMusicVolume()'
|
||||
},
|
||||
'getSoundVolume': {
|
||||
'signature': 'getSoundVolume() -> int',
|
||||
'description': 'Get the current sound effects volume level.',
|
||||
'returns': 'int: Current volume (0-100)',
|
||||
'example': 'current_volume = mcrfpy.getSoundVolume()'
|
||||
},
|
||||
'setMusicVolume': {
|
||||
'signature': 'setMusicVolume(volume: int) -> None',
|
||||
'description': 'Set the global music volume.',
|
||||
'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')],
|
||||
'example': 'mcrfpy.setMusicVolume(50) # Set to 50% volume'
|
||||
},
|
||||
'setSoundVolume': {
|
||||
'signature': 'setSoundVolume(volume: int) -> None',
|
||||
'description': 'Set the global sound effects volume.',
|
||||
'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')],
|
||||
'example': 'mcrfpy.setSoundVolume(75) # Set to 75% volume'
|
||||
},
|
||||
|
||||
# UI Utilities
|
||||
'find': {
|
||||
'signature': 'find(name: str, scene: str = None) -> UIDrawable | None',
|
||||
'description': 'Find the first UI element with the specified name.',
|
||||
'args': [
|
||||
('name', 'str', 'Exact name to search for'),
|
||||
('scene', 'str', 'Scene to search in (default: current scene)')
|
||||
],
|
||||
'returns': 'UIDrawable or None: The found element, or None if not found',
|
||||
'note': 'Searches scene UI elements and entities within grids.',
|
||||
'example': 'button = mcrfpy.find("start_button")'
|
||||
},
|
||||
'findAll': {
|
||||
'signature': 'findAll(pattern: str, scene: str = None) -> list',
|
||||
'description': 'Find all UI elements matching a name pattern.',
|
||||
'args': [
|
||||
('pattern', 'str', 'Name pattern with optional wildcards (* matches any characters)'),
|
||||
('scene', 'str', 'Scene to search in (default: current scene)')
|
||||
],
|
||||
'returns': 'list: All matching UI elements and entities',
|
||||
'example': 'enemies = mcrfpy.findAll("enemy_*")'
|
||||
},
|
||||
|
||||
# System Functions
|
||||
'exit': {
|
||||
'signature': 'exit() -> None',
|
||||
'description': 'Cleanly shut down the game engine and exit the application.',
|
||||
'note': 'This immediately closes the window and terminates the program.',
|
||||
'example': 'mcrfpy.exit()'
|
||||
},
|
||||
'getMetrics': {
|
||||
'signature': 'getMetrics() -> dict',
|
||||
'description': 'Get current performance metrics.',
|
||||
'returns': '''dict: Performance data with keys:
|
||||
- frame_time: Last frame duration in seconds
|
||||
- avg_frame_time: Average frame time
|
||||
- fps: Frames per second
|
||||
- draw_calls: Number of draw calls
|
||||
- ui_elements: Total UI element count
|
||||
- visible_elements: Visible element count
|
||||
- current_frame: Frame counter
|
||||
- runtime: Total runtime in seconds''',
|
||||
'example': 'metrics = mcrfpy.getMetrics()'
|
||||
},
|
||||
'setTimer': {
|
||||
'signature': 'setTimer(name: str, handler: callable, interval: int) -> None',
|
||||
'description': 'Create or update a recurring timer.',
|
||||
'args': [
|
||||
('name', 'str', 'Unique identifier for the timer'),
|
||||
('handler', 'callable', 'Function called with (runtime: float) parameter'),
|
||||
('interval', 'int', 'Time between calls in milliseconds')
|
||||
],
|
||||
'note': 'If a timer with this name exists, it will be replaced.',
|
||||
'example': '''def update_score(runtime):
|
||||
score += 1
|
||||
mcrfpy.setTimer("score_update", update_score, 1000)'''
|
||||
},
|
||||
'delTimer': {
|
||||
'signature': 'delTimer(name: str) -> None',
|
||||
'description': 'Stop and remove a timer.',
|
||||
'args': [('name', 'str', 'Timer identifier to remove')],
|
||||
'note': 'No error is raised if the timer doesn\'t exist.',
|
||||
'example': 'mcrfpy.delTimer("score_update")'
|
||||
},
|
||||
'setScale': {
|
||||
'signature': 'setScale(multiplier: float) -> None',
|
||||
'description': 'Scale the game window size.',
|
||||
'args': [('multiplier', 'float', 'Scale factor (e.g., 2.0 for double size)')],
|
||||
'note': 'The internal resolution remains 1024x768, but the window is scaled.',
|
||||
'example': 'mcrfpy.setScale(2.0) # Double the window size'
|
||||
}
|
||||
}
|
||||
|
||||
def get_complete_property_documentation():
|
||||
"""Return complete documentation for ALL properties."""
|
||||
return {
|
||||
'Animation': {
|
||||
'property': 'str: Name of the property being animated (e.g., "x", "y", "scale")',
|
||||
'duration': 'float: Total duration of the animation in seconds',
|
||||
'elapsed_time': 'float: Time elapsed since animation started (read-only)',
|
||||
'current_value': 'float: Current interpolated value of the animation (read-only)',
|
||||
'is_running': 'bool: True if animation is currently running (read-only)',
|
||||
'is_finished': 'bool: True if animation has completed (read-only)'
|
||||
},
|
||||
'GridPoint': {
|
||||
'x': 'int: Grid x coordinate of this point',
|
||||
'y': 'int: Grid y coordinate of this point',
|
||||
'texture_index': 'int: Index of the texture/sprite to display at this point',
|
||||
'solid': 'bool: Whether this point blocks movement',
|
||||
'transparent': 'bool: Whether this point allows light/vision through',
|
||||
'color': 'Color: Color tint applied to the texture at this point'
|
||||
},
|
||||
'GridPointState': {
|
||||
'visible': 'bool: Whether this point is currently visible to the player',
|
||||
'discovered': 'bool: Whether this point has been discovered/explored',
|
||||
'custom_flags': 'int: Bitfield for custom game-specific flags'
|
||||
}
|
||||
}
|
||||
|
||||
def generate_complete_html_documentation():
|
||||
"""Generate complete HTML documentation with NO missing methods."""
|
||||
|
||||
# Get all documentation data
|
||||
method_docs = get_complete_method_documentation()
|
||||
function_docs = get_complete_function_documentation()
|
||||
property_docs = get_complete_property_documentation()
|
||||
|
||||
html_parts = []
|
||||
|
||||
# HTML header with enhanced styling
|
||||
html_parts.append('''<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>McRogueFace API Reference - Complete Documentation</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #2c3e50;
|
||||
border-bottom: 3px solid #3498db;
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #34495e;
|
||||
border-bottom: 2px solid #ecf0f1;
|
||||
padding-bottom: 10px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #2c3e50;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: #34495e;
|
||||
margin-top: 20px;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: #555;
|
||||
margin-top: 15px;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #f4f4f4;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #e1e4e8;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
font-size: 0.875em;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.class-name {
|
||||
color: #8e44ad;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.property {
|
||||
color: #27ae60;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.method {
|
||||
color: #2980b9;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.function-signature {
|
||||
color: #d73a49;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.method-section {
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #3498db;
|
||||
}
|
||||
|
||||
.arg-list {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.arg-item {
|
||||
margin: 8px 0;
|
||||
padding: 8px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e1e4e8;
|
||||
}
|
||||
|
||||
.arg-name {
|
||||
color: #d73a49;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.arg-type {
|
||||
color: #6f42c1;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.returns {
|
||||
background: #e8f5e8;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #28a745;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.note {
|
||||
background: #fff3cd;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #ffc107;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.example {
|
||||
background: #e7f3ff;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #0366d6;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.toc {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e1e4e8;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.toc ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.toc li {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.toc a {
|
||||
color: #3498db;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.toc a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
''')
|
||||
|
||||
# Title and overview
|
||||
html_parts.append('<h1>McRogueFace API Reference - Complete Documentation</h1>')
|
||||
html_parts.append(f'<p><em>Generated on {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</em></p>')
|
||||
|
||||
# Table of contents
|
||||
html_parts.append('<div class="toc">')
|
||||
html_parts.append('<h2>Table of Contents</h2>')
|
||||
html_parts.append('<ul>')
|
||||
html_parts.append('<li><a href="#functions">Functions</a></li>')
|
||||
html_parts.append('<li><a href="#classes">Classes</a></li>')
|
||||
html_parts.append('<li><a href="#automation">Automation Module</a></li>')
|
||||
html_parts.append('</ul>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Functions section
|
||||
html_parts.append('<h2 id="functions">Functions</h2>')
|
||||
|
||||
# Group functions by category
|
||||
categories = {
|
||||
'Scene Management': ['createScene', 'setScene', 'currentScene', 'sceneUI', 'keypressScene'],
|
||||
'Audio': ['createSoundBuffer', 'loadMusic', 'playSound', 'getMusicVolume', 'getSoundVolume', 'setMusicVolume', 'setSoundVolume'],
|
||||
'UI Utilities': ['find', 'findAll'],
|
||||
'System': ['exit', 'getMetrics', 'setTimer', 'delTimer', 'setScale']
|
||||
}
|
||||
|
||||
for category, functions in categories.items():
|
||||
html_parts.append(f'<h3>{category}</h3>')
|
||||
for func_name in functions:
|
||||
if func_name in function_docs:
|
||||
html_parts.append(format_function_html(func_name, function_docs[func_name]))
|
||||
|
||||
# Classes section
|
||||
html_parts.append('<h2 id="classes">Classes</h2>')
|
||||
|
||||
# Get all classes from mcrfpy
|
||||
classes = []
|
||||
for name in sorted(dir(mcrfpy)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(mcrfpy, name)
|
||||
if isinstance(obj, type):
|
||||
classes.append((name, obj))
|
||||
|
||||
# Generate class documentation
|
||||
for class_name, cls in classes:
|
||||
html_parts.append(format_class_html_complete(class_name, cls, method_docs, property_docs))
|
||||
|
||||
# Automation section
|
||||
if hasattr(mcrfpy, 'automation'):
|
||||
html_parts.append('<h2 id="automation">Automation Module</h2>')
|
||||
html_parts.append('<p>The <code>mcrfpy.automation</code> module provides testing and automation capabilities.</p>')
|
||||
|
||||
automation = mcrfpy.automation
|
||||
for name in sorted(dir(automation)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(automation, name)
|
||||
if callable(obj):
|
||||
html_parts.append(f'<div class="method-section">')
|
||||
html_parts.append(f'<h4><code class="function-signature">automation.{name}</code></h4>')
|
||||
if obj.__doc__:
|
||||
doc_parts = obj.__doc__.split(' - ')
|
||||
if len(doc_parts) > 1:
|
||||
html_parts.append(f'<p>{escape_html(doc_parts[1])}</p>')
|
||||
else:
|
||||
html_parts.append(f'<p>{escape_html(obj.__doc__)}</p>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
html_parts.append('</div>')
|
||||
html_parts.append('</body>')
|
||||
html_parts.append('</html>')
|
||||
|
||||
return '\n'.join(html_parts)
|
||||
|
||||
def format_function_html(func_name, func_doc):
|
||||
"""Format a function with complete documentation."""
|
||||
html_parts = []
|
||||
|
||||
html_parts.append('<div class="method-section">')
|
||||
html_parts.append(f'<h4><code class="function-signature">{func_doc["signature"]}</code></h4>')
|
||||
html_parts.append(f'<p>{escape_html(func_doc["description"])}</p>')
|
||||
|
||||
# Arguments
|
||||
if 'args' in func_doc:
|
||||
html_parts.append('<div class="arg-list">')
|
||||
html_parts.append('<h5>Arguments:</h5>')
|
||||
for arg in func_doc['args']:
|
||||
html_parts.append('<div class="arg-item">')
|
||||
html_parts.append(f'<span class="arg-name">{arg[0]}</span> ')
|
||||
html_parts.append(f'<span class="arg-type">({arg[1]})</span>: ')
|
||||
html_parts.append(f'{escape_html(arg[2])}')
|
||||
html_parts.append('</div>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Returns
|
||||
if 'returns' in func_doc:
|
||||
html_parts.append('<div class="returns">')
|
||||
html_parts.append(f'<strong>Returns:</strong> {escape_html(func_doc["returns"])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Raises
|
||||
if 'raises' in func_doc:
|
||||
html_parts.append('<div class="note">')
|
||||
html_parts.append(f'<strong>Raises:</strong> {escape_html(func_doc["raises"])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Note
|
||||
if 'note' in func_doc:
|
||||
html_parts.append('<div class="note">')
|
||||
html_parts.append(f'<strong>Note:</strong> {escape_html(func_doc["note"])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Example
|
||||
if 'example' in func_doc:
|
||||
html_parts.append('<div class="example">')
|
||||
html_parts.append('<h5>Example:</h5>')
|
||||
html_parts.append('<pre><code>')
|
||||
html_parts.append(escape_html(func_doc['example']))
|
||||
html_parts.append('</code></pre>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
html_parts.append('</div>')
|
||||
|
||||
return '\n'.join(html_parts)
|
||||
|
||||
def format_class_html_complete(class_name, cls, method_docs, property_docs):
|
||||
"""Format a class with complete documentation."""
|
||||
html_parts = []
|
||||
|
||||
html_parts.append('<div class="method-section">')
|
||||
html_parts.append(f'<h3><span class="class-name">{class_name}</span></h3>')
|
||||
|
||||
# Class description
|
||||
if cls.__doc__:
|
||||
html_parts.append(f'<p>{escape_html(cls.__doc__)}</p>')
|
||||
|
||||
# Properties
|
||||
if class_name in property_docs:
|
||||
html_parts.append('<h4>Properties:</h4>')
|
||||
for prop_name, prop_desc in property_docs[class_name].items():
|
||||
html_parts.append(f'<div class="arg-item">')
|
||||
html_parts.append(f'<span class="property">{prop_name}</span>: {escape_html(prop_desc)}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Methods
|
||||
methods_to_document = []
|
||||
|
||||
# Add inherited methods for UI classes
|
||||
if any(base.__name__ == 'Drawable' for base in cls.__bases__ if hasattr(base, '__name__')):
|
||||
methods_to_document.extend(['get_bounds', 'move', 'resize'])
|
||||
|
||||
# Add class-specific methods
|
||||
if class_name in method_docs:
|
||||
methods_to_document.extend(method_docs[class_name].keys())
|
||||
|
||||
# Add methods from introspection
|
||||
for attr_name in dir(cls):
|
||||
if not attr_name.startswith('_') and callable(getattr(cls, attr_name)):
|
||||
if attr_name not in methods_to_document:
|
||||
methods_to_document.append(attr_name)
|
||||
|
||||
if methods_to_document:
|
||||
html_parts.append('<h4>Methods:</h4>')
|
||||
for method_name in set(methods_to_document):
|
||||
# Get method documentation
|
||||
method_doc = None
|
||||
if class_name in method_docs and method_name in method_docs[class_name]:
|
||||
method_doc = method_docs[class_name][method_name]
|
||||
elif method_name in method_docs.get('Drawable', {}):
|
||||
method_doc = method_docs['Drawable'][method_name]
|
||||
|
||||
if method_doc:
|
||||
html_parts.append(format_method_html(method_name, method_doc))
|
||||
else:
|
||||
# Basic method with no documentation
|
||||
html_parts.append(f'<div class="arg-item">')
|
||||
html_parts.append(f'<span class="method">{method_name}(...)</span>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
html_parts.append('</div>')
|
||||
|
||||
return '\n'.join(html_parts)
|
||||
|
||||
def format_method_html(method_name, method_doc):
|
||||
"""Format a method with complete documentation."""
|
||||
html_parts = []
|
||||
|
||||
html_parts.append('<div style="margin-left: 20px; margin-bottom: 15px;">')
|
||||
html_parts.append(f'<h5><code class="method">{method_doc["signature"]}</code></h5>')
|
||||
html_parts.append(f'<p>{escape_html(method_doc["description"])}</p>')
|
||||
|
||||
# Arguments
|
||||
if 'args' in method_doc:
|
||||
for arg in method_doc['args']:
|
||||
html_parts.append(f'<div style="margin-left: 20px;">')
|
||||
html_parts.append(f'<span class="arg-name">{arg[0]}</span> ')
|
||||
html_parts.append(f'<span class="arg-type">({arg[1]})</span>: ')
|
||||
html_parts.append(f'{escape_html(arg[2])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Returns
|
||||
if 'returns' in method_doc:
|
||||
html_parts.append(f'<div style="margin-left: 20px; color: #28a745;">')
|
||||
html_parts.append(f'<strong>Returns:</strong> {escape_html(method_doc["returns"])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Note
|
||||
if 'note' in method_doc:
|
||||
html_parts.append(f'<div style="margin-left: 20px; color: #856404;">')
|
||||
html_parts.append(f'<strong>Note:</strong> {escape_html(method_doc["note"])}')
|
||||
html_parts.append('</div>')
|
||||
|
||||
# Example
|
||||
if 'example' in method_doc:
|
||||
html_parts.append(f'<div style="margin-left: 20px;">')
|
||||
html_parts.append('<strong>Example:</strong>')
|
||||
html_parts.append('<pre><code>')
|
||||
html_parts.append(escape_html(method_doc['example']))
|
||||
html_parts.append('</code></pre>')
|
||||
html_parts.append('</div>')
|
||||
|
||||
html_parts.append('</div>')
|
||||
|
||||
return '\n'.join(html_parts)
|
||||
|
||||
def main():
|
||||
"""Generate complete HTML documentation with zero missing methods."""
|
||||
print("Generating COMPLETE HTML API documentation...")
|
||||
|
||||
# Generate HTML
|
||||
html_content = generate_complete_html_documentation()
|
||||
|
||||
# Write to file
|
||||
output_path = Path("docs/api_reference_complete.html")
|
||||
output_path.parent.mkdir(exist_ok=True)
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(html_content)
|
||||
|
||||
print(f"✓ Generated {output_path}")
|
||||
print(f" File size: {len(html_content):,} bytes")
|
||||
|
||||
# Count "..." instances
|
||||
ellipsis_count = html_content.count('...')
|
||||
print(f" Ellipsis instances: {ellipsis_count}")
|
||||
|
||||
if ellipsis_count == 0:
|
||||
print("✅ SUCCESS: No missing documentation found!")
|
||||
else:
|
||||
print(f"❌ WARNING: {ellipsis_count} methods still need documentation")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,821 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate COMPLETE Markdown API reference documentation for McRogueFace with NO missing methods."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
import mcrfpy
|
||||
|
||||
def get_complete_method_documentation():
|
||||
"""Return complete documentation for ALL methods across all classes."""
|
||||
return {
|
||||
# Base Drawable methods (inherited by all UI elements)
|
||||
'Drawable': {
|
||||
'get_bounds': {
|
||||
'signature': 'get_bounds()',
|
||||
'description': 'Get the bounding rectangle of this drawable element.',
|
||||
'returns': 'tuple: (x, y, width, height) representing the element\'s bounds',
|
||||
'note': 'The bounds are in screen coordinates and account for current position and size.'
|
||||
},
|
||||
'move': {
|
||||
'signature': 'move(dx, dy)',
|
||||
'description': 'Move the element by a relative offset.',
|
||||
'args': [
|
||||
('dx', 'float', 'Horizontal offset in pixels'),
|
||||
('dy', 'float', 'Vertical offset in pixels')
|
||||
],
|
||||
'note': 'This modifies the x and y position properties by the given amounts.'
|
||||
},
|
||||
'resize': {
|
||||
'signature': 'resize(width, height)',
|
||||
'description': 'Resize the element to new dimensions.',
|
||||
'args': [
|
||||
('width', 'float', 'New width in pixels'),
|
||||
('height', 'float', 'New height in pixels')
|
||||
],
|
||||
'note': 'For Caption and Sprite, this may not change actual size if determined by content.'
|
||||
}
|
||||
},
|
||||
|
||||
# Entity-specific methods
|
||||
'Entity': {
|
||||
'at': {
|
||||
'signature': 'at(x, y)',
|
||||
'description': 'Check if this entity is at the specified grid coordinates.',
|
||||
'args': [
|
||||
('x', 'int', 'Grid x coordinate to check'),
|
||||
('y', 'int', 'Grid y coordinate to check')
|
||||
],
|
||||
'returns': 'bool: True if entity is at position (x, y), False otherwise'
|
||||
},
|
||||
'die': {
|
||||
'signature': 'die()',
|
||||
'description': 'Remove this entity from its parent grid.',
|
||||
'note': 'The entity object remains valid but is no longer rendered or updated.'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index()',
|
||||
'description': 'Get the index of this entity in its parent grid\'s entity list.',
|
||||
'returns': 'int: Index position, or -1 if not in a grid'
|
||||
}
|
||||
},
|
||||
|
||||
# Grid-specific methods
|
||||
'Grid': {
|
||||
'at': {
|
||||
'signature': 'at(x, y)',
|
||||
'description': 'Get the GridPoint at the specified grid coordinates.',
|
||||
'args': [
|
||||
('x', 'int', 'Grid x coordinate'),
|
||||
('y', 'int', 'Grid y coordinate')
|
||||
],
|
||||
'returns': 'GridPoint or None: The grid point at (x, y), or None if out of bounds'
|
||||
}
|
||||
},
|
||||
|
||||
# Collection methods
|
||||
'EntityCollection': {
|
||||
'append': {
|
||||
'signature': 'append(entity)',
|
||||
'description': 'Add an entity to the end of the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to add')]
|
||||
},
|
||||
'remove': {
|
||||
'signature': 'remove(entity)',
|
||||
'description': 'Remove the first occurrence of an entity from the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to remove')],
|
||||
'raises': 'ValueError: If entity is not in collection'
|
||||
},
|
||||
'extend': {
|
||||
'signature': 'extend(iterable)',
|
||||
'description': 'Add all entities from an iterable to the collection.',
|
||||
'args': [('iterable', 'Iterable[Entity]', 'Entities to add')]
|
||||
},
|
||||
'count': {
|
||||
'signature': 'count(entity)',
|
||||
'description': 'Count the number of occurrences of an entity in the collection.',
|
||||
'args': [('entity', 'Entity', 'The entity to count')],
|
||||
'returns': 'int: Number of times entity appears in collection'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index(entity)',
|
||||
'description': 'Find the index of the first occurrence of an entity.',
|
||||
'args': [('entity', 'Entity', 'The entity to find')],
|
||||
'returns': 'int: Index of entity in collection',
|
||||
'raises': 'ValueError: If entity is not in collection'
|
||||
}
|
||||
},
|
||||
|
||||
'UICollection': {
|
||||
'append': {
|
||||
'signature': 'append(drawable)',
|
||||
'description': 'Add a drawable element to the end of the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable element to add')]
|
||||
},
|
||||
'remove': {
|
||||
'signature': 'remove(drawable)',
|
||||
'description': 'Remove the first occurrence of a drawable from the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to remove')],
|
||||
'raises': 'ValueError: If drawable is not in collection'
|
||||
},
|
||||
'extend': {
|
||||
'signature': 'extend(iterable)',
|
||||
'description': 'Add all drawables from an iterable to the collection.',
|
||||
'args': [('iterable', 'Iterable[UIDrawable]', 'Drawables to add')]
|
||||
},
|
||||
'count': {
|
||||
'signature': 'count(drawable)',
|
||||
'description': 'Count the number of occurrences of a drawable in the collection.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to count')],
|
||||
'returns': 'int: Number of times drawable appears in collection'
|
||||
},
|
||||
'index': {
|
||||
'signature': 'index(drawable)',
|
||||
'description': 'Find the index of the first occurrence of a drawable.',
|
||||
'args': [('drawable', 'UIDrawable', 'The drawable to find')],
|
||||
'returns': 'int: Index of drawable in collection',
|
||||
'raises': 'ValueError: If drawable is not in collection'
|
||||
}
|
||||
},
|
||||
|
||||
# Animation methods
|
||||
'Animation': {
|
||||
'get_current_value': {
|
||||
'signature': 'get_current_value()',
|
||||
'description': 'Get the current interpolated value of the animation.',
|
||||
'returns': 'float: Current animation value between start and end'
|
||||
},
|
||||
'start': {
|
||||
'signature': 'start(target)',
|
||||
'description': 'Start the animation on a target UI element.',
|
||||
'args': [('target', 'UIDrawable', 'The UI element to animate')],
|
||||
'note': 'The target must have the property specified in the animation constructor.'
|
||||
},
|
||||
'update': {
|
||||
'signature': 'update(delta_time)',
|
||||
'description': 'Update the animation by the given time delta.',
|
||||
'args': [('delta_time', 'float', 'Time elapsed since last update in seconds')],
|
||||
'returns': 'bool: True if animation is still running, False if finished'
|
||||
}
|
||||
},
|
||||
|
||||
# Color methods
|
||||
'Color': {
|
||||
'from_hex': {
|
||||
'signature': 'from_hex(hex_string)',
|
||||
'description': 'Create a Color from a hexadecimal color string.',
|
||||
'args': [('hex_string', 'str', 'Hex color string (e.g., "#FF0000" or "FF0000")')],
|
||||
'returns': 'Color: New Color object from hex string',
|
||||
'example': 'red = Color.from_hex("#FF0000")'
|
||||
},
|
||||
'to_hex': {
|
||||
'signature': 'to_hex()',
|
||||
'description': 'Convert this Color to a hexadecimal string.',
|
||||
'returns': 'str: Hex color string in format "#RRGGBB"',
|
||||
'example': 'hex_str = color.to_hex() # Returns "#FF0000"'
|
||||
},
|
||||
'lerp': {
|
||||
'signature': 'lerp(other, t)',
|
||||
'description': 'Linearly interpolate between this color and another.',
|
||||
'args': [
|
||||
('other', 'Color', 'The color to interpolate towards'),
|
||||
('t', 'float', 'Interpolation factor from 0.0 to 1.0')
|
||||
],
|
||||
'returns': 'Color: New interpolated Color object',
|
||||
'example': 'mixed = red.lerp(blue, 0.5) # 50% between red and blue'
|
||||
}
|
||||
},
|
||||
|
||||
# Vector methods
|
||||
'Vector': {
|
||||
'magnitude': {
|
||||
'signature': 'magnitude()',
|
||||
'description': 'Calculate the length/magnitude of this vector.',
|
||||
'returns': 'float: The magnitude of the vector'
|
||||
},
|
||||
'magnitude_squared': {
|
||||
'signature': 'magnitude_squared()',
|
||||
'description': 'Calculate the squared magnitude of this vector.',
|
||||
'returns': 'float: The squared magnitude (faster than magnitude())',
|
||||
'note': 'Use this for comparisons to avoid expensive square root calculation.'
|
||||
},
|
||||
'normalize': {
|
||||
'signature': 'normalize()',
|
||||
'description': 'Return a unit vector in the same direction.',
|
||||
'returns': 'Vector: New normalized vector with magnitude 1.0',
|
||||
'raises': 'ValueError: If vector has zero magnitude'
|
||||
},
|
||||
'dot': {
|
||||
'signature': 'dot(other)',
|
||||
'description': 'Calculate the dot product with another vector.',
|
||||
'args': [('other', 'Vector', 'The other vector')],
|
||||
'returns': 'float: Dot product of the two vectors'
|
||||
},
|
||||
'distance_to': {
|
||||
'signature': 'distance_to(other)',
|
||||
'description': 'Calculate the distance to another vector.',
|
||||
'args': [('other', 'Vector', 'The other vector')],
|
||||
'returns': 'float: Distance between the two vectors'
|
||||
},
|
||||
'angle': {
|
||||
'signature': 'angle()',
|
||||
'description': 'Get the angle of this vector in radians.',
|
||||
'returns': 'float: Angle in radians from positive x-axis'
|
||||
},
|
||||
'copy': {
|
||||
'signature': 'copy()',
|
||||
'description': 'Create a copy of this vector.',
|
||||
'returns': 'Vector: New Vector object with same x and y values'
|
||||
}
|
||||
},
|
||||
|
||||
# Scene methods
|
||||
'Scene': {
|
||||
'activate': {
|
||||
'signature': 'activate()',
|
||||
'description': 'Make this scene the active scene.',
|
||||
'note': 'Equivalent to calling setScene() with this scene\'s name.'
|
||||
},
|
||||
'get_ui': {
|
||||
'signature': 'get_ui()',
|
||||
'description': 'Get the UI element collection for this scene.',
|
||||
'returns': 'UICollection: Collection of all UI elements in this scene'
|
||||
},
|
||||
'keypress': {
|
||||
'signature': 'keypress(handler)',
|
||||
'description': 'Register a keyboard handler function for this scene.',
|
||||
'args': [('handler', 'callable', 'Function that takes (key_name: str, is_pressed: bool)')],
|
||||
'note': 'Alternative to overriding the on_keypress method.'
|
||||
},
|
||||
'register_keyboard': {
|
||||
'signature': 'register_keyboard(callable)',
|
||||
'description': 'Register a keyboard event handler function for the scene.',
|
||||
'args': [('callable', 'callable', 'Function that takes (key: str, action: str) parameters')],
|
||||
'note': 'Alternative to overriding the on_keypress method when subclassing Scene objects.',
|
||||
'example': '''def handle_keyboard(key, action):
|
||||
print(f"Key '{key}' was {action}")
|
||||
scene.register_keyboard(handle_keyboard)'''
|
||||
}
|
||||
},
|
||||
|
||||
# Timer methods
|
||||
'Timer': {
|
||||
'pause': {
|
||||
'signature': 'pause()',
|
||||
'description': 'Pause the timer, stopping its callback execution.',
|
||||
'note': 'Use resume() to continue the timer from where it was paused.'
|
||||
},
|
||||
'resume': {
|
||||
'signature': 'resume()',
|
||||
'description': 'Resume a paused timer.',
|
||||
'note': 'Has no effect if timer is not paused.'
|
||||
},
|
||||
'cancel': {
|
||||
'signature': 'cancel()',
|
||||
'description': 'Cancel the timer and remove it from the system.',
|
||||
'note': 'After cancelling, the timer object cannot be reused.'
|
||||
},
|
||||
'restart': {
|
||||
'signature': 'restart()',
|
||||
'description': 'Restart the timer from the beginning.',
|
||||
'note': 'Resets the timer\'s internal clock to zero.'
|
||||
}
|
||||
},
|
||||
|
||||
# Window methods
|
||||
'Window': {
|
||||
'get': {
|
||||
'signature': 'get()',
|
||||
'description': 'Get the Window singleton instance.',
|
||||
'returns': 'Window: The singleton window object',
|
||||
'note': 'This is a static method that returns the same instance every time.'
|
||||
},
|
||||
'center': {
|
||||
'signature': 'center()',
|
||||
'description': 'Center the window on the screen.',
|
||||
'note': 'Only works if the window is not fullscreen.'
|
||||
},
|
||||
'screenshot': {
|
||||
'signature': 'screenshot(filename)',
|
||||
'description': 'Take a screenshot and save it to a file.',
|
||||
'args': [('filename', 'str', 'Path where to save the screenshot')],
|
||||
'note': 'Supports PNG, JPG, and BMP formats based on file extension.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def get_complete_function_documentation():
|
||||
"""Return complete documentation for ALL module functions."""
|
||||
return {
|
||||
# Scene Management
|
||||
'createScene': {
|
||||
'signature': 'createScene(name: str) -> None',
|
||||
'description': 'Create a new empty scene with the given name.',
|
||||
'args': [('name', 'str', 'Unique name for the new scene')],
|
||||
'raises': 'ValueError: If a scene with this name already exists',
|
||||
'note': 'The scene is created but not made active. Use setScene() to switch to it.',
|
||||
'example': 'mcrfpy.createScene("game_over")'
|
||||
},
|
||||
'setScene': {
|
||||
'signature': 'setScene(scene: str, transition: str = None, duration: float = 0.0) -> None',
|
||||
'description': 'Switch to a different scene with optional transition effect.',
|
||||
'args': [
|
||||
('scene', 'str', 'Name of the scene to switch to'),
|
||||
('transition', 'str', 'Transition type: "fade", "slide_left", "slide_right", "slide_up", "slide_down"'),
|
||||
('duration', 'float', 'Transition duration in seconds (default: 0.0 for instant)')
|
||||
],
|
||||
'raises': 'KeyError: If the scene doesn\'t exist',
|
||||
'example': 'mcrfpy.setScene("game", "fade", 0.5)'
|
||||
},
|
||||
'currentScene': {
|
||||
'signature': 'currentScene() -> str',
|
||||
'description': 'Get the name of the currently active scene.',
|
||||
'returns': 'str: Name of the current scene',
|
||||
'example': 'scene_name = mcrfpy.currentScene()'
|
||||
},
|
||||
'sceneUI': {
|
||||
'signature': 'sceneUI(scene: str = None) -> UICollection',
|
||||
'description': 'Get all UI elements for a scene.',
|
||||
'args': [('scene', 'str', 'Scene name. If None, uses current scene')],
|
||||
'returns': 'UICollection: All UI elements in the scene',
|
||||
'raises': 'KeyError: If the specified scene doesn\'t exist',
|
||||
'example': 'ui_elements = mcrfpy.sceneUI("game")'
|
||||
},
|
||||
'keypressScene': {
|
||||
'signature': 'keypressScene(handler: callable) -> None',
|
||||
'description': 'Set the keyboard event handler for the current scene.',
|
||||
'args': [('handler', 'callable', 'Function that receives (key_name: str, is_pressed: bool)')],
|
||||
'example': '''def on_key(key, pressed):
|
||||
if key == "SPACE" and pressed:
|
||||
player.jump()
|
||||
mcrfpy.keypressScene(on_key)'''
|
||||
},
|
||||
|
||||
# Audio Functions
|
||||
'createSoundBuffer': {
|
||||
'signature': 'createSoundBuffer(filename: str) -> int',
|
||||
'description': 'Load a sound effect from a file and return its buffer ID.',
|
||||
'args': [('filename', 'str', 'Path to the sound file (WAV, OGG, FLAC)')],
|
||||
'returns': 'int: Buffer ID for use with playSound()',
|
||||
'raises': 'RuntimeError: If the file cannot be loaded',
|
||||
'example': 'jump_sound = mcrfpy.createSoundBuffer("assets/jump.wav")'
|
||||
},
|
||||
'loadMusic': {
|
||||
'signature': 'loadMusic(filename: str, loop: bool = True) -> None',
|
||||
'description': 'Load and immediately play background music from a file.',
|
||||
'args': [
|
||||
('filename', 'str', 'Path to the music file (WAV, OGG, FLAC)'),
|
||||
('loop', 'bool', 'Whether to loop the music (default: True)')
|
||||
],
|
||||
'note': 'Only one music track can play at a time. Loading new music stops the current track.',
|
||||
'example': 'mcrfpy.loadMusic("assets/background.ogg", True)'
|
||||
},
|
||||
'playSound': {
|
||||
'signature': 'playSound(buffer_id: int) -> None',
|
||||
'description': 'Play a sound effect using a previously loaded buffer.',
|
||||
'args': [('buffer_id', 'int', 'Sound buffer ID returned by createSoundBuffer()')],
|
||||
'raises': 'RuntimeError: If the buffer ID is invalid',
|
||||
'example': 'mcrfpy.playSound(jump_sound)'
|
||||
},
|
||||
'getMusicVolume': {
|
||||
'signature': 'getMusicVolume() -> int',
|
||||
'description': 'Get the current music volume level.',
|
||||
'returns': 'int: Current volume (0-100)',
|
||||
'example': 'current_volume = mcrfpy.getMusicVolume()'
|
||||
},
|
||||
'getSoundVolume': {
|
||||
'signature': 'getSoundVolume() -> int',
|
||||
'description': 'Get the current sound effects volume level.',
|
||||
'returns': 'int: Current volume (0-100)',
|
||||
'example': 'current_volume = mcrfpy.getSoundVolume()'
|
||||
},
|
||||
'setMusicVolume': {
|
||||
'signature': 'setMusicVolume(volume: int) -> None',
|
||||
'description': 'Set the global music volume.',
|
||||
'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')],
|
||||
'example': 'mcrfpy.setMusicVolume(50) # Set to 50% volume'
|
||||
},
|
||||
'setSoundVolume': {
|
||||
'signature': 'setSoundVolume(volume: int) -> None',
|
||||
'description': 'Set the global sound effects volume.',
|
||||
'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')],
|
||||
'example': 'mcrfpy.setSoundVolume(75) # Set to 75% volume'
|
||||
},
|
||||
|
||||
# UI Utilities
|
||||
'find': {
|
||||
'signature': 'find(name: str, scene: str = None) -> UIDrawable | None',
|
||||
'description': 'Find the first UI element with the specified name.',
|
||||
'args': [
|
||||
('name', 'str', 'Exact name to search for'),
|
||||
('scene', 'str', 'Scene to search in (default: current scene)')
|
||||
],
|
||||
'returns': 'UIDrawable or None: The found element, or None if not found',
|
||||
'note': 'Searches scene UI elements and entities within grids.',
|
||||
'example': 'button = mcrfpy.find("start_button")'
|
||||
},
|
||||
'findAll': {
|
||||
'signature': 'findAll(pattern: str, scene: str = None) -> list',
|
||||
'description': 'Find all UI elements matching a name pattern.',
|
||||
'args': [
|
||||
('pattern', 'str', 'Name pattern with optional wildcards (* matches any characters)'),
|
||||
('scene', 'str', 'Scene to search in (default: current scene)')
|
||||
],
|
||||
'returns': 'list: All matching UI elements and entities',
|
||||
'example': 'enemies = mcrfpy.findAll("enemy_*")'
|
||||
},
|
||||
|
||||
# System Functions
|
||||
'exit': {
|
||||
'signature': 'exit() -> None',
|
||||
'description': 'Cleanly shut down the game engine and exit the application.',
|
||||
'note': 'This immediately closes the window and terminates the program.',
|
||||
'example': 'mcrfpy.exit()'
|
||||
},
|
||||
'getMetrics': {
|
||||
'signature': 'getMetrics() -> dict',
|
||||
'description': 'Get current performance metrics.',
|
||||
'returns': '''dict: Performance data with keys:
|
||||
- frame_time: Last frame duration in seconds
|
||||
- avg_frame_time: Average frame time
|
||||
- fps: Frames per second
|
||||
- draw_calls: Number of draw calls
|
||||
- ui_elements: Total UI element count
|
||||
- visible_elements: Visible element count
|
||||
- current_frame: Frame counter
|
||||
- runtime: Total runtime in seconds''',
|
||||
'example': 'metrics = mcrfpy.getMetrics()'
|
||||
},
|
||||
'setTimer': {
|
||||
'signature': 'setTimer(name: str, handler: callable, interval: int) -> None',
|
||||
'description': 'Create or update a recurring timer.',
|
||||
'args': [
|
||||
('name', 'str', 'Unique identifier for the timer'),
|
||||
('handler', 'callable', 'Function called with (runtime: float) parameter'),
|
||||
('interval', 'int', 'Time between calls in milliseconds')
|
||||
],
|
||||
'note': 'If a timer with this name exists, it will be replaced.',
|
||||
'example': '''def update_score(runtime):
|
||||
score += 1
|
||||
mcrfpy.setTimer("score_update", update_score, 1000)'''
|
||||
},
|
||||
'delTimer': {
|
||||
'signature': 'delTimer(name: str) -> None',
|
||||
'description': 'Stop and remove a timer.',
|
||||
'args': [('name', 'str', 'Timer identifier to remove')],
|
||||
'note': 'No error is raised if the timer doesn\'t exist.',
|
||||
'example': 'mcrfpy.delTimer("score_update")'
|
||||
},
|
||||
'setScale': {
|
||||
'signature': 'setScale(multiplier: float) -> None',
|
||||
'description': 'Scale the game window size.',
|
||||
'args': [('multiplier', 'float', 'Scale factor (e.g., 2.0 for double size)')],
|
||||
'note': 'The internal resolution remains 1024x768, but the window is scaled.',
|
||||
'example': 'mcrfpy.setScale(2.0) # Double the window size'
|
||||
}
|
||||
}
|
||||
|
||||
def get_complete_property_documentation():
|
||||
"""Return complete documentation for ALL properties."""
|
||||
return {
|
||||
'Animation': {
|
||||
'property': 'str: Name of the property being animated (e.g., "x", "y", "scale")',
|
||||
'duration': 'float: Total duration of the animation in seconds',
|
||||
'elapsed_time': 'float: Time elapsed since animation started (read-only)',
|
||||
'current_value': 'float: Current interpolated value of the animation (read-only)',
|
||||
'is_running': 'bool: True if animation is currently running (read-only)',
|
||||
'is_finished': 'bool: True if animation has completed (read-only)'
|
||||
},
|
||||
'GridPoint': {
|
||||
'x': 'int: Grid x coordinate of this point',
|
||||
'y': 'int: Grid y coordinate of this point',
|
||||
'texture_index': 'int: Index of the texture/sprite to display at this point',
|
||||
'solid': 'bool: Whether this point blocks movement',
|
||||
'transparent': 'bool: Whether this point allows light/vision through',
|
||||
'color': 'Color: Color tint applied to the texture at this point'
|
||||
},
|
||||
'GridPointState': {
|
||||
'visible': 'bool: Whether this point is currently visible to the player',
|
||||
'discovered': 'bool: Whether this point has been discovered/explored',
|
||||
'custom_flags': 'int: Bitfield for custom game-specific flags'
|
||||
}
|
||||
}
|
||||
|
||||
def format_method_markdown(method_name, method_doc):
|
||||
"""Format a method as markdown."""
|
||||
lines = []
|
||||
|
||||
lines.append(f"#### `{method_doc['signature']}`")
|
||||
lines.append("")
|
||||
lines.append(method_doc['description'])
|
||||
lines.append("")
|
||||
|
||||
# Arguments
|
||||
if 'args' in method_doc:
|
||||
lines.append("**Arguments:**")
|
||||
for arg in method_doc['args']:
|
||||
lines.append(f"- `{arg[0]}` (*{arg[1]}*): {arg[2]}")
|
||||
lines.append("")
|
||||
|
||||
# Returns
|
||||
if 'returns' in method_doc:
|
||||
lines.append(f"**Returns:** {method_doc['returns']}")
|
||||
lines.append("")
|
||||
|
||||
# Raises
|
||||
if 'raises' in method_doc:
|
||||
lines.append(f"**Raises:** {method_doc['raises']}")
|
||||
lines.append("")
|
||||
|
||||
# Note
|
||||
if 'note' in method_doc:
|
||||
lines.append(f"**Note:** {method_doc['note']}")
|
||||
lines.append("")
|
||||
|
||||
# Example
|
||||
if 'example' in method_doc:
|
||||
lines.append("**Example:**")
|
||||
lines.append("```python")
|
||||
lines.append(method_doc['example'])
|
||||
lines.append("```")
|
||||
lines.append("")
|
||||
|
||||
return lines
|
||||
|
||||
def format_function_markdown(func_name, func_doc):
|
||||
"""Format a function as markdown."""
|
||||
lines = []
|
||||
|
||||
lines.append(f"### `{func_doc['signature']}`")
|
||||
lines.append("")
|
||||
lines.append(func_doc['description'])
|
||||
lines.append("")
|
||||
|
||||
# Arguments
|
||||
if 'args' in func_doc:
|
||||
lines.append("**Arguments:**")
|
||||
for arg in func_doc['args']:
|
||||
lines.append(f"- `{arg[0]}` (*{arg[1]}*): {arg[2]}")
|
||||
lines.append("")
|
||||
|
||||
# Returns
|
||||
if 'returns' in func_doc:
|
||||
lines.append(f"**Returns:** {func_doc['returns']}")
|
||||
lines.append("")
|
||||
|
||||
# Raises
|
||||
if 'raises' in func_doc:
|
||||
lines.append(f"**Raises:** {func_doc['raises']}")
|
||||
lines.append("")
|
||||
|
||||
# Note
|
||||
if 'note' in func_doc:
|
||||
lines.append(f"**Note:** {func_doc['note']}")
|
||||
lines.append("")
|
||||
|
||||
# Example
|
||||
if 'example' in func_doc:
|
||||
lines.append("**Example:**")
|
||||
lines.append("```python")
|
||||
lines.append(func_doc['example'])
|
||||
lines.append("```")
|
||||
lines.append("")
|
||||
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
return lines
|
||||
|
||||
def generate_complete_markdown_documentation():
|
||||
"""Generate complete markdown documentation with NO missing methods."""
|
||||
|
||||
# Get all documentation data
|
||||
method_docs = get_complete_method_documentation()
|
||||
function_docs = get_complete_function_documentation()
|
||||
property_docs = get_complete_property_documentation()
|
||||
|
||||
lines = []
|
||||
|
||||
# Header
|
||||
lines.append("# McRogueFace API Reference")
|
||||
lines.append("")
|
||||
lines.append(f"*Generated on {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*")
|
||||
lines.append("")
|
||||
|
||||
# Overview
|
||||
if mcrfpy.__doc__:
|
||||
lines.append("## Overview")
|
||||
lines.append("")
|
||||
# Process the docstring properly
|
||||
doc_text = mcrfpy.__doc__.replace('\\n', '\n')
|
||||
lines.append(doc_text)
|
||||
lines.append("")
|
||||
|
||||
# Table of Contents
|
||||
lines.append("## Table of Contents")
|
||||
lines.append("")
|
||||
lines.append("- [Functions](#functions)")
|
||||
lines.append(" - [Scene Management](#scene-management)")
|
||||
lines.append(" - [Audio](#audio)")
|
||||
lines.append(" - [UI Utilities](#ui-utilities)")
|
||||
lines.append(" - [System](#system)")
|
||||
lines.append("- [Classes](#classes)")
|
||||
lines.append(" - [UI Components](#ui-components)")
|
||||
lines.append(" - [Collections](#collections)")
|
||||
lines.append(" - [System Types](#system-types)")
|
||||
lines.append(" - [Other Classes](#other-classes)")
|
||||
lines.append("- [Automation Module](#automation-module)")
|
||||
lines.append("")
|
||||
|
||||
# Functions section
|
||||
lines.append("## Functions")
|
||||
lines.append("")
|
||||
|
||||
# Group functions by category
|
||||
categories = {
|
||||
'Scene Management': ['createScene', 'setScene', 'currentScene', 'sceneUI', 'keypressScene'],
|
||||
'Audio': ['createSoundBuffer', 'loadMusic', 'playSound', 'getMusicVolume', 'getSoundVolume', 'setMusicVolume', 'setSoundVolume'],
|
||||
'UI Utilities': ['find', 'findAll'],
|
||||
'System': ['exit', 'getMetrics', 'setTimer', 'delTimer', 'setScale']
|
||||
}
|
||||
|
||||
for category, functions in categories.items():
|
||||
lines.append(f"### {category}")
|
||||
lines.append("")
|
||||
for func_name in functions:
|
||||
if func_name in function_docs:
|
||||
lines.extend(format_function_markdown(func_name, function_docs[func_name]))
|
||||
|
||||
# Classes section
|
||||
lines.append("## Classes")
|
||||
lines.append("")
|
||||
|
||||
# Get all classes from mcrfpy
|
||||
classes = []
|
||||
for name in sorted(dir(mcrfpy)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(mcrfpy, name)
|
||||
if isinstance(obj, type):
|
||||
classes.append((name, obj))
|
||||
|
||||
# Group classes
|
||||
ui_classes = ['Frame', 'Caption', 'Sprite', 'Grid', 'Entity']
|
||||
collection_classes = ['EntityCollection', 'UICollection', 'UICollectionIter', 'UIEntityCollectionIter']
|
||||
system_classes = ['Color', 'Vector', 'Texture', 'Font']
|
||||
other_classes = [name for name, _ in classes if name not in ui_classes + collection_classes + system_classes]
|
||||
|
||||
# UI Components
|
||||
lines.append("### UI Components")
|
||||
lines.append("")
|
||||
for class_name in ui_classes:
|
||||
if any(name == class_name for name, _ in classes):
|
||||
lines.extend(format_class_markdown(class_name, method_docs, property_docs))
|
||||
|
||||
# Collections
|
||||
lines.append("### Collections")
|
||||
lines.append("")
|
||||
for class_name in collection_classes:
|
||||
if any(name == class_name for name, _ in classes):
|
||||
lines.extend(format_class_markdown(class_name, method_docs, property_docs))
|
||||
|
||||
# System Types
|
||||
lines.append("### System Types")
|
||||
lines.append("")
|
||||
for class_name in system_classes:
|
||||
if any(name == class_name for name, _ in classes):
|
||||
lines.extend(format_class_markdown(class_name, method_docs, property_docs))
|
||||
|
||||
# Other Classes
|
||||
lines.append("### Other Classes")
|
||||
lines.append("")
|
||||
for class_name in other_classes:
|
||||
lines.extend(format_class_markdown(class_name, method_docs, property_docs))
|
||||
|
||||
# Automation section
|
||||
if hasattr(mcrfpy, 'automation'):
|
||||
lines.append("## Automation Module")
|
||||
lines.append("")
|
||||
lines.append("The `mcrfpy.automation` module provides testing and automation capabilities.")
|
||||
lines.append("")
|
||||
|
||||
automation = mcrfpy.automation
|
||||
for name in sorted(dir(automation)):
|
||||
if not name.startswith('_'):
|
||||
obj = getattr(automation, name)
|
||||
if callable(obj):
|
||||
lines.append(f"### `automation.{name}`")
|
||||
lines.append("")
|
||||
if obj.__doc__:
|
||||
doc_parts = obj.__doc__.split(' - ')
|
||||
if len(doc_parts) > 1:
|
||||
lines.append(doc_parts[1])
|
||||
else:
|
||||
lines.append(obj.__doc__)
|
||||
lines.append("")
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def format_class_markdown(class_name, method_docs, property_docs):
|
||||
"""Format a class as markdown."""
|
||||
lines = []
|
||||
|
||||
lines.append(f"### class `{class_name}`")
|
||||
lines.append("")
|
||||
|
||||
# Class description from known info
|
||||
class_descriptions = {
|
||||
'Frame': 'A rectangular frame UI element that can contain other drawable elements.',
|
||||
'Caption': 'A text display UI element with customizable font and styling.',
|
||||
'Sprite': 'A sprite UI element that displays a texture or portion of a texture atlas.',
|
||||
'Grid': 'A grid-based tilemap UI element for rendering tile-based levels and game worlds.',
|
||||
'Entity': 'Game entity that can be placed in a Grid.',
|
||||
'EntityCollection': 'Container for Entity objects in a Grid. Supports iteration and indexing.',
|
||||
'UICollection': 'Container for UI drawable elements. Supports iteration and indexing.',
|
||||
'UICollectionIter': 'Iterator for UICollection. Automatically created when iterating over a UICollection.',
|
||||
'UIEntityCollectionIter': 'Iterator for EntityCollection. Automatically created when iterating over an EntityCollection.',
|
||||
'Color': 'RGBA color representation.',
|
||||
'Vector': '2D vector for positions and directions.',
|
||||
'Font': 'Font object for text rendering.',
|
||||
'Texture': 'Texture object for image data.',
|
||||
'Animation': 'Animate UI element properties over time.',
|
||||
'GridPoint': 'Represents a single tile in a Grid.',
|
||||
'GridPointState': 'State information for a GridPoint.',
|
||||
'Scene': 'Base class for object-oriented scenes.',
|
||||
'Timer': 'Timer object for scheduled callbacks.',
|
||||
'Window': 'Window singleton for accessing and modifying the game window properties.',
|
||||
'Drawable': 'Base class for all drawable UI elements.'
|
||||
}
|
||||
|
||||
if class_name in class_descriptions:
|
||||
lines.append(class_descriptions[class_name])
|
||||
lines.append("")
|
||||
|
||||
# Properties
|
||||
if class_name in property_docs:
|
||||
lines.append("#### Properties")
|
||||
lines.append("")
|
||||
for prop_name, prop_desc in property_docs[class_name].items():
|
||||
lines.append(f"- **`{prop_name}`**: {prop_desc}")
|
||||
lines.append("")
|
||||
|
||||
# Methods
|
||||
methods_to_document = []
|
||||
|
||||
# Add inherited methods for UI classes
|
||||
if class_name in ['Frame', 'Caption', 'Sprite', 'Grid', 'Entity']:
|
||||
methods_to_document.extend(['get_bounds', 'move', 'resize'])
|
||||
|
||||
# Add class-specific methods
|
||||
if class_name in method_docs:
|
||||
methods_to_document.extend(method_docs[class_name].keys())
|
||||
|
||||
if methods_to_document:
|
||||
lines.append("#### Methods")
|
||||
lines.append("")
|
||||
for method_name in set(methods_to_document):
|
||||
# Get method documentation
|
||||
method_doc = None
|
||||
if class_name in method_docs and method_name in method_docs[class_name]:
|
||||
method_doc = method_docs[class_name][method_name]
|
||||
elif method_name in method_docs.get('Drawable', {}):
|
||||
method_doc = method_docs['Drawable'][method_name]
|
||||
|
||||
if method_doc:
|
||||
lines.extend(format_method_markdown(method_name, method_doc))
|
||||
|
||||
lines.append("---")
|
||||
lines.append("")
|
||||
|
||||
return lines
|
||||
|
||||
def main():
|
||||
"""Generate complete markdown documentation with zero missing methods."""
|
||||
print("Generating COMPLETE Markdown API documentation...")
|
||||
|
||||
# Generate markdown
|
||||
markdown_content = generate_complete_markdown_documentation()
|
||||
|
||||
# Write to file
|
||||
output_path = Path("docs/API_REFERENCE_COMPLETE.md")
|
||||
output_path.parent.mkdir(exist_ok=True)
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(markdown_content)
|
||||
|
||||
print(f"✓ Generated {output_path}")
|
||||
print(f" File size: {len(markdown_content):,} bytes")
|
||||
|
||||
# Count "..." instances
|
||||
ellipsis_count = markdown_content.count('...')
|
||||
print(f" Ellipsis instances: {ellipsis_count}")
|
||||
|
||||
if ellipsis_count == 0:
|
||||
print("✅ SUCCESS: No missing documentation found!")
|
||||
else:
|
||||
print(f"❌ WARNING: {ellipsis_count} methods still need documentation")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in New Issue