Created
June 9, 2020 03:25
-
-
Save ctrlcctrlv/74d5c5ac9599f8000394490c1ed45a83 to your computer and use it in GitHub Desktop.
FontForge "Community guidelines" authoring script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# This program outputs the "Link to this section" links, and also a table of | |
# contents for the "Community guidelines" wiki FontForge page. | |
# | |
# Warning: pretty hacky... | |
# | |
# Original author: Fredrick R. Brennan | |
# License: FontForge original BSD license | |
# | |
# Run as e.g.: | |
# ./manage_guidelines.py < cgs.md > /tmp/cgs.md | |
# | |
# "Never spend 6 minutes doing something by hand when you can spend 6 hours failing to automate it." ~ Zhuowei Zhang (σ╝╡σìôσüë) | |
import re | |
import sys | |
cg = sys.stdin.read() | |
lines = cg.splitlines() | |
# Find our generated TOC and delete it if applicable. | |
TOCSTART = '# Table of Contents <a name="toc"/><!-- TOCSTART -->' | |
TOCEND = '<!-- TOCEND -->\n' | |
TOCi = None | |
ntoc = 0 | |
for i, line in enumerate(lines): | |
if not TOCSTART in line: | |
continue | |
else: | |
TOCi = i | |
j = 0 | |
while lines[i+j+1].lstrip().startswith('*'): | |
ntoc+=1 | |
j +=1 | |
if TOCEND[:-1] in lines[i+j+1]: | |
ntoc+=2 | |
if ntoc!=0: | |
ntoc+=1 | |
break | |
if TOCi is not None: | |
for i in range(TOCi, TOCi+ntoc): | |
del lines[TOCi] | |
# HTML parser to find anchors and remember the last found. | |
from html.parser import HTMLParser | |
class AnchorParser(HTMLParser): | |
@staticmethod | |
def attrs_to_dict(attrs): | |
ret = dict() | |
for k, v in attrs: | |
if k in ret: | |
raise ValueError("Double attribute in tag") | |
ret.setdefault(k, v) | |
return ret | |
curanchor = None | |
parsed = 0 | |
def handle_starttag(self, tag, attrs): | |
attrs = AnchorParser.attrs_to_dict(attrs) | |
if tag == "a" and "name" in attrs: | |
self.parsed+=1 | |
self.curanchor = attrs["name"] | |
parser = AnchorParser() | |
# Write out the "quick links" and populate the TOC "tree" (which is really not a tree data structure per se) | |
anchors = list() | |
outlines = list() # We don't want to output in the loop as it might error. | |
tree = list() | |
firstheading = None | |
QUICKLINK = '<!-- QUICKLINK -->' | |
for i, line in enumerate(lines): | |
if not QUICKLINK in line: outlines.append(line) | |
if not re.match(r'^#', line) or TOCSTART in line: | |
continue | |
parsedb4 = parser.parsed | |
parser.feed(line) | |
if parser.parsed == parsedb4 or parser.curanchor == None: | |
raise ValueError("No anchor in heading `{}`, add one.".format(line[line.index(' ')+1:])) | |
if parser.curanchor in anchors: | |
raise ValueError("Document has two anchors with name `{}`, cannot continue. Rename one of them.".format(parser.curanchor)) | |
outlines.append("<sup>[Quick link to section](#{})</sup>".format(parser.curanchor)+QUICKLINK) | |
# Add a blank line after link if one isn't already there, and doing so is "appropriate" | |
if (i+1 <= len(lines)-1) and ((len(lines[i+1].strip()) > 0 and lines[i+1][0] == '<') ^ \ | |
(len(lines[i+1].strip()) > 0)): | |
outlines.append("") | |
tree.append((line.count('#', 0, line.index(' ')), parser.curanchor, line[line.index(' ')+1:line.index('<')])) | |
if firstheading is None: firstheading = i | |
anchors.append(parser.curanchor) | |
# Write our TOC | |
toc = list() | |
toc.append(TOCSTART) | |
for level, anchor, name in tree: | |
toc.append("""{} <a href="#{}">{}</a>""".format(' '*2*(level-1)+'*', anchor, name)) | |
toc.append(TOCEND) | |
if firstheading is None: | |
raise ValueError("No headings, add one.") | |
outlines = outlines[:firstheading] + toc + outlines[firstheading:] | |
for line in outlines: | |
print(line) | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment