Skip to content

Commit

Permalink
Implement tables in documentation parser
Browse files Browse the repository at this point in the history
Much cleaner way to present enums instead of code blocks.
  • Loading branch information
Foereaper committed Sep 20, 2024
1 parent 9bdef8c commit 71ddf6c
Show file tree
Hide file tree
Showing 4 changed files with 406 additions and 441 deletions.
60 changes: 51 additions & 9 deletions docs/ElunaDoc/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import typing
import markdown
from typedecorator import params, returns, Nullable
from typing import Any, List, TypedDict

class TableDict(TypedDict):
columns: List[str]
values: List[List[Any]]

class ParameterDoc(object):
"""The documentation data of a parameter or return value for an Eluna method."""
Expand Down Expand Up @@ -64,13 +68,24 @@ def __init__(self, name, data_type, description, default_value=None):

class MethodDoc(object):
"""The documentation data of an Eluna method."""
@params(self=object, name=str, description=str, prototypes=[str], parameters=[ParameterDoc], returned=[ParameterDoc])
def __init__(self, name, description, prototypes, parameters, returned):
@params(self=object, name=str, description=str, table=TableDict, prototypes=[str], parameters=[ParameterDoc], returned=[ParameterDoc])
def __init__(self, name, description, table, prototypes, parameters, returned):
self.name = name
self.prototypes = prototypes
self.table = table
self.parameters = parameters
self.returned = returned


if table:
# Generate Markdown Table
md_table = '| ' + ' | '.join(table['columns']) + ' |\n' # Header
md_table += '| ' + ' | '.join(['---'] * len(table['columns'])) + ' |\n' # Separator

for row in table['values']:
md_table += '| ' + ' | '.join(row) + ' |\n' # Rows

self.table = markdown.markdown(md_table, extensions=['tables'])

# Parse the description as Markdown.
self.description = markdown.markdown(description)
# Pull the first paragraph out of the description as the short description.
Expand Down Expand Up @@ -121,7 +136,12 @@ class ClassParser(object):
start_regex = re.compile(r"\s*/\*\*") # The start of documentation, i.e. /**
body_regex = re.compile(r"\s*\s?\*\s?(.*)") # The "body", i.e. a * and optionally some descriptive text.
# An extra optional space (\s?) was thrown in to make it different from `class_body_regex`.


# Regular expressions for parsing a table.
table_regex = re.compile(r"\s*\*\s@table")
table_columns_regex = re.compile(r"\s*\*\s@columns\s*\[(.+)\]")
table_values_regex = re.compile(r"\s*\*\s@values\s*\[(.+)\]")

param_regex = re.compile(r"""\s*\*\s@param\s # The @param tag starts with opt. whitespace followed by "* @param ".
([^\s]+)\s(\w+)? # The data type, a space, and the name of the param.
(?:\s=\s(\w+))? # The default value: a = surrounded by spaces, followed by text.
Expand Down Expand Up @@ -162,6 +182,7 @@ def reset(self):
self.returned = []
self.method_name = None
self.prototypes = []
self.table = {}

def handle_class_body(self, match):
text = match.group(1)
Expand All @@ -171,6 +192,21 @@ def handle_body(self, match):
text = match.group(1)
self.description += text + '\n'

def handle_table(self, line):
self.table = {
"columns": [],
"values": []
}

def handle_table_columns(self, match):
if self.table:
self.table["columns"] = match.group(1).split(", ")

def handle_table_values(self, match):
if self.table:
values = re.findall(r'(?:[^,"]|"(?:\\.|[^"])*")+', match.group(1))
self.table["values"].append([v.strip(' "') for v in values])

def handle_param(self, match):
data_type, name, default, description = match.group(1), match.group(2), match.group(3), match.group(4)
self.params.append(ParameterDoc(name, data_type, description, default))
Expand Down Expand Up @@ -246,7 +282,7 @@ def make_prototype(parameters):
# Format the method name into each prototype.
self.prototypes = [proto.format(self.method_name) for proto in self.prototypes]

self.methods.append(MethodDoc(self.method_name, self.description, self.prototypes, self.params, self.returned))
self.methods.append(MethodDoc(self.method_name, self.description, self.table, self.prototypes, self.params, self.returned))

# Table of which handler is used to handle each regular expressions.
regex_handlers = {
Expand All @@ -255,6 +291,9 @@ def make_prototype(parameters):
class_end_regex: None,
start_regex: None,
body_regex: handle_body,
table_regex: handle_table,
table_columns_regex: handle_table_columns,
table_values_regex: handle_table_values,
param_regex: handle_param,
return_regex: handle_return,
proto_regex: handle_proto,
Expand All @@ -269,10 +308,13 @@ def make_prototype(parameters):
class_start_regex: [class_end_regex, class_body_regex],
class_body_regex: [class_end_regex, class_body_regex],
class_end_regex: [],
start_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
body_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
proto_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
param_regex: [param_regex, return_regex, comment_end_regex, body_regex],
start_regex: [table_regex, param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
body_regex: [table_regex, param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
proto_regex: [table_regex, param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
table_regex: [table_regex, table_columns_regex, param_regex, return_regex, comment_end_regex, body_regex],
table_columns_regex: [table_values_regex, param_regex, return_regex, comment_end_regex, body_regex],
table_values_regex: [table_values_regex, param_regex, return_regex, comment_end_regex, body_regex],
param_regex: [table_regex, param_regex, return_regex, comment_end_regex, body_regex],
return_regex: [return_regex, comment_end_regex],
comment_end_regex: [end_regex],
end_regex: [],
Expand Down
36 changes: 35 additions & 1 deletion docs/ElunaDoc/static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,41 @@ nav.sub {
min-height: 100%;
}

.content, nav { max-width: 960px; }
.content, nav { max-width: 80vw; }

.docblock .table-container {
width: 100%;
overflow-x: auto;
margin-bottom: 20px;
}

.docblock table {
max-width: 50vw;
border-collapse: collapse !important;
table-layout: auto;
margin-bottom: 20px;
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace;
}

.docblock th, .docblock td {
padding: 10px;
text-align: left;
border: 1px solid #ddd;
white-space: nowrap;
}

.docblock th {
background-color: #f5f5f5;
font-weight: bold;
}

.docblock tr:nth-child(even) {
background-color: #f9f9f9;
}

.docblock table {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/* Everything else */

Expand Down
11 changes: 10 additions & 1 deletion docs/ElunaDoc/templates/method.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,16 @@ <h2>{{ current_class.name }} Methods</h2>
<p>This method is <em>undocumented</em>. <strong>Use at your own risk.</strong></p>
<p>For temporary documentation, please check the <a href="https://github.com/ElunaLuaEngine/Eluna/blob/master/LuaFunctions.cpp">LuaFunctions</a> source file.</p>
{%- endif %}


{%- if current_method.table %}
<div class="table-container">
<p>
{{ current_method.table }}
</p>
</div>
{%- endif %}


<h2 id="synopsis" class='section-header'>
<a href="#synopsis">Synopsis</a>
</h2>
Expand Down
Loading

0 comments on commit 71ddf6c

Please sign in to comment.