Add github pages site with in-browser renderer
virtuald opened this issue · 5 comments
Would be a neat stunt, maybe using https://brython.info?
I took a crack at this tonight, it works fine except that the dataclasses formatting is basically unreadable without using black.
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/brython@3.10/brython.min.js">
</script>
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/brython@3.10/brython_stdlib.js">
</script>
<style>
.row {
display: flex;
}
.column {
flex: 50%;
}
</style>
</head>
<body onload="brython()">
<div class="row">
<div class="column">
C++ code<br/>
<textarea id="cxxinput" rows="40" cols="80">
// comments are ignored
std::vector<int> x;
</textarea>
</div>
<div class="column">
cxxheaderparser output<br/>
<textarea id="cxxoutput" rows="40" cols="80" readonly="true"></textarea>
</div>
</div>
<script type="text/python">
from cxxheaderparser.simple import parse_string
from browser import bind, document, console
cxxinput = document["cxxinput"]
cxxoutput = document["cxxoutput"]
@bind("#cxxinput", "input")
def on_input(evt):
# TODO: probably should only run this every 200ms or so
try:
data = parse_string(cxxinput.value)
except Exception as e:
cxxoutput.value = "Exception:\n" + str(e)
else:
# TODO: the formatting is terrible
cxxoutput.value = repr(data)
on_input(None)
</script>
</body>
</html>
Ok, I played with this a bit more tonight and wrote a simple 'webrepr' dataclasses formatter that has output very similar to black. WIth this formatter, the web interface is a bit more usable:
def webrepr(data: ParsedData, defaults: bool = False, mxlen: int = 88) -> str:
"""
A dumb black-like formatter for use on the cxxheaderparser webpage, which cannot
use black.
No guarantees are provided for this dumper. It probably generates valid python
most of the time.
"""
fp = io.StringIO()
def _format(item, curlen: int, indent: str):
# see if the default representation fits
r = repr(item)
if len(r) + curlen <= mxlen:
fp.write(r)
return
# got to expand the item. Depends on what it is
newindent = indent + " "
if isinstance(item, list):
fp.write("[\n")
curlen = len(newindent)
for li in item:
fp.write(newindent)
_format(li, curlen, newindent)
fp.write(",\n")
fp.write(f"{indent}]")
elif isinstance(item, dict):
fp.write("{\n")
curlen = len(newindent)
for k, v in item.items():
curlen = fp.write(f"{newindent}{k!r}:")
_format(v, curlen, newindent)
fp.write(",\n")
fp.write(f"{indent}}}")
elif dataclasses.is_dataclass(item):
# always write the name, then process like a dict
fp.write(f"{item.__class__.__qualname__}(\n")
fields = dataclasses.fields(item)
written = False
for field in fields:
# check to see if this is a default value, exclude those
v = getattr(item, field.name)
if not defaults and field.repr and field.compare:
if field.default_factory is not dataclasses.MISSING:
default = field.default_factory()
else:
default = field.default
if v == default:
continue
curlen = fp.write(f"{newindent}{field.name}=")
_format(v, curlen, newindent)
fp.write(",\n")
written = True
if written:
fp.write(indent)
fp.write(")")
else:
# I give up, just write it. It's probably fine.
fp.write(r)
_format(data, 0, "")
return fp.getvalue()
There is a bug with functions that have a 'constructor' argument, so this is blocked on brython-dev/brython#1830
Additionally, it looks like there's something else wonky going on too (maybe a PLY issue?). When parsing this simple code in the web editor:
class Fx {
public:
int z(int x);
int x;
};
I get a parsing error, but I don't get one when running the cpython version.
Edit: turns out, the parsing error is for the exact same reason -- because the 'Method' object takes a keyword argument named 'constructor'. So hopefully once they fix that bug then this might be doable?
The brython bug was fixed, but since I'd like to use a CDN for this, we'll have to wait for a new release. Their release schedule appears to be fairly irregular.
Brython has a 3.10.4 release, but it now has a dataclasses-only bug with arguments that have the name "constructor" in them (brython-dev/brython#1859)
Brython is just too buggy, went with pyodide instead.