nixos/make-options-doc: reuse markdown instance in mergeJSON
this doesn't construct a new (expensive) parser for every option, making rendering about 30x faster.
This commit is contained in:
@@ -3,6 +3,11 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List
|
||||||
|
|
||||||
|
# for MD conversion
|
||||||
|
import mistune
|
||||||
|
import re
|
||||||
|
from xml.sax.saxutils import escape, quoteattr
|
||||||
|
|
||||||
JSON = Dict[str, Any]
|
JSON = Dict[str, Any]
|
||||||
|
|
||||||
class Key:
|
class Key:
|
||||||
@@ -41,26 +46,18 @@ def unpivot(options: Dict[Key, Option]) -> Dict[str, JSON]:
|
|||||||
result[opt.name] = opt.value
|
result[opt.name] = opt.value
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# converts in-place!
|
admonitions = {
|
||||||
def convertMD(options: Dict[str, Any]) -> str:
|
|
||||||
import mistune
|
|
||||||
import re
|
|
||||||
from xml.sax.saxutils import escape, quoteattr
|
|
||||||
|
|
||||||
admonitions = {
|
|
||||||
'.warning': 'warning',
|
'.warning': 'warning',
|
||||||
'.important': 'important',
|
'.important': 'important',
|
||||||
'.note': 'note'
|
'.note': 'note'
|
||||||
}
|
}
|
||||||
class Renderer(mistune.renderers.BaseRenderer):
|
class Renderer(mistune.renderers.BaseRenderer):
|
||||||
def __init__(self, path):
|
|
||||||
self.path = path
|
|
||||||
def _get_method(self, name):
|
def _get_method(self, name):
|
||||||
try:
|
try:
|
||||||
return super(Renderer, self)._get_method(name)
|
return super(Renderer, self)._get_method(name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
def not_supported(*args, **kwargs):
|
def not_supported(*args, **kwargs):
|
||||||
raise NotImplementedError("md node not supported yet", self.path, name, args, **kwargs)
|
raise NotImplementedError("md node not supported yet", name, args, **kwargs)
|
||||||
return not_supported
|
return not_supported
|
||||||
|
|
||||||
def text(self, text):
|
def text(self, text):
|
||||||
@@ -122,42 +119,36 @@ def convertMD(options: Dict[str, Any]) -> str:
|
|||||||
def finalize(self, data):
|
def finalize(self, data):
|
||||||
return "".join(data)
|
return "".join(data)
|
||||||
|
|
||||||
plugins = []
|
def p_command(md):
|
||||||
|
|
||||||
COMMAND_PATTERN = r'\{command\}`(.*?)`'
|
COMMAND_PATTERN = r'\{command\}`(.*?)`'
|
||||||
def command(md):
|
|
||||||
def parse(self, m, state):
|
def parse(self, m, state):
|
||||||
return ('command', m.group(1))
|
return ('command', m.group(1))
|
||||||
md.inline.register_rule('command', COMMAND_PATTERN, parse)
|
md.inline.register_rule('command', COMMAND_PATTERN, parse)
|
||||||
md.inline.rules.append('command')
|
md.inline.rules.append('command')
|
||||||
plugins.append(command)
|
|
||||||
|
|
||||||
|
def p_file(md):
|
||||||
FILE_PATTERN = r'\{file\}`(.*?)`'
|
FILE_PATTERN = r'\{file\}`(.*?)`'
|
||||||
def file(md):
|
|
||||||
def parse(self, m, state):
|
def parse(self, m, state):
|
||||||
return ('file', m.group(1))
|
return ('file', m.group(1))
|
||||||
md.inline.register_rule('file', FILE_PATTERN, parse)
|
md.inline.register_rule('file', FILE_PATTERN, parse)
|
||||||
md.inline.rules.append('file')
|
md.inline.rules.append('file')
|
||||||
plugins.append(file)
|
|
||||||
|
|
||||||
|
def p_option(md):
|
||||||
OPTION_PATTERN = r'\{option\}`(.*?)`'
|
OPTION_PATTERN = r'\{option\}`(.*?)`'
|
||||||
def option(md):
|
|
||||||
def parse(self, m, state):
|
def parse(self, m, state):
|
||||||
return ('option', m.group(1))
|
return ('option', m.group(1))
|
||||||
md.inline.register_rule('option', OPTION_PATTERN, parse)
|
md.inline.register_rule('option', OPTION_PATTERN, parse)
|
||||||
md.inline.rules.append('option')
|
md.inline.rules.append('option')
|
||||||
plugins.append(option)
|
|
||||||
|
|
||||||
|
def p_manpage(md):
|
||||||
MANPAGE_PATTERN = r'\{manpage\}`(.*?)\((.+?)\)`'
|
MANPAGE_PATTERN = r'\{manpage\}`(.*?)\((.+?)\)`'
|
||||||
def manpage(md):
|
|
||||||
def parse(self, m, state):
|
def parse(self, m, state):
|
||||||
return ('manpage', m.group(1), m.group(2))
|
return ('manpage', m.group(1), m.group(2))
|
||||||
md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
|
md.inline.register_rule('manpage', MANPAGE_PATTERN, parse)
|
||||||
md.inline.rules.append('manpage')
|
md.inline.rules.append('manpage')
|
||||||
plugins.append(manpage)
|
|
||||||
|
|
||||||
|
def p_admonition(md):
|
||||||
ADMONITION_PATTERN = re.compile(r'^::: \{([^\n]*?)\}\n(.*?)^:::\n', flags=re.MULTILINE|re.DOTALL)
|
ADMONITION_PATTERN = re.compile(r'^::: \{([^\n]*?)\}\n(.*?)^:::\n', flags=re.MULTILINE|re.DOTALL)
|
||||||
def admonition(md):
|
|
||||||
def parse(self, m, state):
|
def parse(self, m, state):
|
||||||
return {
|
return {
|
||||||
'type': 'admonition',
|
'type': 'admonition',
|
||||||
@@ -166,12 +157,21 @@ def convertMD(options: Dict[str, Any]) -> str:
|
|||||||
}
|
}
|
||||||
md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
|
md.block.register_rule('admonition', ADMONITION_PATTERN, parse)
|
||||||
md.block.rules.append('admonition')
|
md.block.rules.append('admonition')
|
||||||
plugins.append(admonition)
|
|
||||||
|
|
||||||
|
md = mistune.create_markdown(renderer=Renderer(), plugins=[
|
||||||
|
p_command, p_file, p_option, p_manpage, p_admonition
|
||||||
|
])
|
||||||
|
|
||||||
|
# converts in-place!
|
||||||
|
def convertMD(options: Dict[str, Any]) -> str:
|
||||||
def convertString(path: str, text: str) -> str:
|
def convertString(path: str, text: str) -> str:
|
||||||
rendered = mistune.markdown(text, renderer=Renderer(path), plugins=plugins)
|
try:
|
||||||
|
rendered = md(text)
|
||||||
# keep trailing spaces so we can diff the generated XML to check for conversion bugs.
|
# keep trailing spaces so we can diff the generated XML to check for conversion bugs.
|
||||||
return rendered.rstrip() + text[len(text.rstrip()):]
|
return rendered.rstrip() + text[len(text.rstrip()):]
|
||||||
|
except:
|
||||||
|
print(f"error in {path}")
|
||||||
|
raise
|
||||||
|
|
||||||
def optionIs(option: Dict[str, Any], key: str, typ: str) -> bool:
|
def optionIs(option: Dict[str, Any], key: str, typ: str) -> bool:
|
||||||
if key not in option: return False
|
if key not in option: return False
|
||||||
|
|||||||
Reference in New Issue
Block a user