def main(idir, odir): for path, name in findall_files(idir, 'zip', '.css'): lk.logax(name) ifile, ofile = path, f'{odir}/{name}' rdata = read_file(ifile) wdata = rdata.replace('.highlight', '.codehilite') write_file(wdata, ofile)
def compose_html( title: str, md: str, css=f'{_STYLES_DIR}/github-markdown.css', syntax_highlight=f'{_STYLES_DIR}/syntax_highlight/richleland-pygments' f'-css/default.css'): """ Convert markdown to pure html, then rendered by github-markdown-css. Args: title: Suggest passing filename (without suffix) or the first line of `md` as title. md: The markdown text. css: For now (2020-11-26) we only support Github flavored markdown theme (see https://github.com/sindresorhus/github-markdown-css), in theoretically, any class-less markdown stylesheets can also be available (thus Typora themes not meet the requirements.) syntax_highlight: You can download syntax highlight css from http://richleland.github.io/pygments-css/, and put it in 'assets/ syntax_highlight' folder. References: https://github.com/trentm/python-markdown2 https://github.com/sindresorhus/github-markdown-css """ import markdown2 import textwrap # https://google.github.io/styleguide/pyguide.html#310-strings # 1/3: Templates html = textwrap.dedent('''\ <!doctype html> <html> {__head__} {__body__} </html> ''') head = textwrap.dedent('''\ <head> <meta charset='UTF-8'> <meta name='viewport' content='width=device-width initial-scale=1'> {__title__} {__style__} </head> ''') title = f'<title>{title}</title>' style = textwrap.dedent('''\ <style> /* GitHub theme uses 980px width and 45px padding, and 15px padding for mobile. */ .markdown-body {{ box-sizing: border-box; min-width: 200px; max-width: 980px; margin: 0 auto; padding: 45px; }} @media (max-width: 767px) {{ .markdown-body {{ padding: 15px; }} }} {__main_style__} {__syntax_highlight__} </style> ''') body = textwrap.dedent('''\ <body> <div id='write' class='markdown-body'> {__content__} </div> </body> ''') content = markdown2.markdown( md, extras=[ # https://github.com/trentm/python-markdown2/wiki/Extras 'code-friendly', 'cuddled-lists', 'fenced-code-blocks', 'header-ids', 'numbering', 'strike', 'tables', 'task_list', 'toc', ]) content = re.sub( # Remove 'disabled' from checkbox elements. r'<(input type="checkbox" class="task-list-item-checkbox"(?: checked)?)' r' disabled>', r'<\1>', content) # 2/3: Interpolates body = body.format(__content__=content) style = style.format(__main_style__=read_file(css), __syntax_highlight__=read_file(syntax_highlight)) head = head.format(__title__=title, __style__=style) html = html.format(__head__=head, __body__=body) # 3/3: Return full html return html
def main(pyml_file: str): compile_pyml_code(read_file(pyml_file))
def main(file_i: str, file_o): """ Args: file_i: "~/blueprint/resources/no1_all_qml_modules.html". 该文件被我事先 从 "{YourQtProgram}/Docs/Qt-{version}/qtdoc/modules-qml.html" 拷贝过 来. file_o: '~/blueprint/resources/no2_all_qml_modules.json' "~/resources/all_qml_modules.json" 格式: { 'module_group': {raw_module_group: formatted_name, ...}, raw_module_group: see `Notes:no1` formatted_name: see `Notes:no3` 'module': {raw_module: formatted_name, ...} raw_module: see `Notes:no2` } 示例: { 'module_group': { 'qtquick': 'QtQuick', 'qtquickcontrols': 'QtQuickControls', ... }, 'module': { 'qtquick-windows': 'QtQuick.Windows', ... }, } Notes: 1. `raw_module_group` 的键是没有空格或连接符的, 只有纯小写字母和 数字组成 2. `raw_module` 的键是由纯小写字母和连接符组成 (例如 'qtquick -windows') 3. `formatted_name` 是由首字母大写的单词和点号组成 (例如 'QtQuick.Windows') 1. 但是有一个特例: 'QtQuick.labs.xxx' 从 'lab' 开始全部都是 小写(例如 'Qt.labs.folderlistmodel') 4. 该生成文件可被直接用于 `no2_all_qml_types.py.py:_correct _module_lettercase` """ file_i = file_i.replace('\\', '/') soup = BeautifulSoup(read_and_write.read_file(file_i), 'html.parser') container = soup.find('table', 'annotated') writer = { 'module_group': {}, # value: {raw_module_group: formatted_name, ...} 'module': {}, # value: {raw_module: formatted_name, ...} } extra_words = ['Qt', 'Quick', 'Qml', 'Win', 'Labs'] for e in container.find_all('td', 'tblName'): """ <td class="tblName"> <p> <a href="../qtcharts/qtcharts-qmlmodule.html"> ^--1---^ ^--2---^ Qt Charts QML Types ^---3---^ </a> </p> </td> -> 1. module_group: 'qtcharts' 2. module: 'qtcharts' 3. name: 'Qt Charts' """ link = e.a['href'].split('/') # -> ['..', 'qtquickcontrols1', 'qtquick-controls-qmlmodule.html'] module_group_raw = link[1] # type: str # -> 'qtquickcontrols1' module_raw = link[2].replace('-qmlmodule.html', '') # type: str # -> 'qtquick-controls' """ 针对 QtQuick Controls 的处理 背景: Qt 对 QtQuick.Controls 的命名关系有点乱, 如下所示: QtQuick.Controls v1: module_group = 'qtquickcontrols1' module = 'qtquick-controls' QtQuick.Controls v2: module_group = 'qtquickcontrols' module = 'qtquick-controls2' 我将 v1 舍弃, 只处理 v2, 并将 v2 的命名改为: module_group = 'qtquickcontrols' module = 'qtquick-controls' (注意去掉了尾部的数字 2) 为什么这样做: 以 Button 为例, v1 的 Button 继承于 FocusScope, v2 的 Button 继承于 AbstractButton. 我的设计的前提是只使用 'qtquickcontrols' 和 'qtquick-controls', 那么在这种情况下, 二者就只能保留其中一个模组. 因 此我保留了 v2, 后续解析和分析继承关系也都基于 v2 继续. """ if module_group_raw == 'qtquickcontrols1': continue if module_raw == 'qtquick-controls2': module_raw = 'qtquick-controls' mini_lexicon = (e.a.text.replace(' QML Types', '').replace( 'Qt Quick', 'QtQuick').replace('Qt3DAnimation', 'Animation').replace('Web', 'Web ').title() ) # type: str """ 解释一下上面的 mini_lexicon 的处理逻辑. mini_lexicon 为 module_group 和 module 提供一个小型词典, 该词典可用 于帮助调整 module_group 和 module 的大小写格式. 例如: 调整前: module_group: 'qtcharts' module: 'qtcharts' 调整后: module_group: 'QtCharts' module: 'QtCharts' mini_lexicon 来源于 `e.a.text`, 在考虑到实际情况中, 有许多细节需要重 新调整, 所以我们才要对 mini_lexicon 进行诸多处理, 才能为 module_group 和 module 所用: 1. `replace(' QML Types', '')`: 把不必要的词尾去掉 2. `replace('Qt Quick', 'QtQuick')`: 遵循模块的写法规范 3. `replace('Qt3DAnimation', 'Animation')`: 针对 'Qt 3D Qt3DAnimation' 的处理. 这个貌似是官方的写法有点问题, 所以我 把 'Qt3DAnimation' 改成了 'Animation' 4. `replace('Web', 'Web ')`: 为了将 'WebEngine' 拆分成 'Web Engine', 需要 `mini_lexicon` 提供这两个独立的单词 5. `title()`: 将首字母大写, 非首字母小写. 例如: 1. 'Qt NFS' -> 'Qt Nfc' 2. 'Qt QML' -> 'Qt Qml' 此外还有一些其他问题: 1. module_group = 'qtwinextras' 的 `e.a.text` 是 'Qt Windows Extras', 该问题不属于 mini_lexicon 的处理范畴. 我使用 `extra_words` 变量解决这个问题, 见 extra_words 的定义 """ words = [x.title() for x in mini_lexicon.split(' ') if len(x) > 1] # -> ['QtQuick', 'Controls'] module_group_fmt = _correct_module_lettercase(module_group_raw, extra_words + words) module_fmt = _correct_module_lettercase(module_raw, extra_words + words) writer['module_group'][module_group_raw] = module_group_fmt writer['module'][module_raw] = module_fmt read_and_write.dumps(writer, file_o)
def main(file_i, file_o): """ Args: file_i: '~/blueprint/resources/no2_all_qml_types.html'. 该文件被我事先从 "{YourQtProgram}/Docs/Qt-{version}/qtdoc/qmltypes.html" 拷贝过来. file_o: 生成文件. "~/blueprint/resources/no3_all_qml_types.json" {module_group: {module: {type_name: path}, ...}, ...} # {模组: {模块: {类型: 路径}}} e.g. { 'qtquick': { 'qtquick': { 'Rectangle': 'qtquick/qml-qtquick-rectangle.html', 'Text': 'qtquick/qml-qtquick-text.html', ... }, 'qtquick-window': { 'Window': 'qtquick/qml-qtquick-window-window.html', ... }, ... }, ... } 思路: 1. 我们安装了 Qt 主程序以后, 在软件安装目录下的 'Docs/Qt-{version}' 中有 它的 API 文档 2. 其中 "~/Docs/Qt-{version}/qtdoc/qmltypes.html" 列出了全部的 qml types 3. 我们对 "qmltypes.html" 用 BeautifulSoup 解析, 从中获取每个 qml types 和它的链接, 最终我们将得到这些信息: 模组, 模块, 类型, 路径等 4. 将这些信息保存到本项目下的 "~/resources/qmltypes.json" 文件中 """ soup = BeautifulSoup(read_and_write.read_file(file_i), 'html.parser') # https://www.itranslater.com/qa/details/2325827141935563776 data = defaultdict(lambda: defaultdict(dict)) # {module_group: {module: {type_name: filename, ...}, ...}, ...} container = soup.find('div', 'flowListDiv') for e in container.find_all('dd'): link = e.a['href'] # type: str # e.g. "../qtdatavisualization/qml-qtdatavisualization- # abstract3dseries.html" match = re.search(r'\.\./(\w+)/([-\w]+)\.html', link) # | ^-1-^ ^--2---^ | # ^-------- group(0) -------^ # match.group(0): '../qtdatavisualization/qml-qtdatavisualization # -abstract3dseries.html' # match.group(1): 'qtdatavisualization' # match.group(2): 'qml-qtdatavisualization-abstract3dseries' assert match, e module_group = match.group(1) module = match.group(2) # see `blueprint/qml_modules_indexing/no1_all_qml_modules.py:comments # :针对 QtQuick Controls 的处理` if module_group == 'qtquickcontrols1': continue if 'qtquick-controls2' in module: # e.g. 'qml-qtquick-controls2-label' module = module.replace('controls2', 'controls') path = match.group(0).lstrip('../') # -> 'qtdatavisualization/qml-qtdatavisualization-abstract3dseries # .html' module_group = _correct_module_lettercase(module_group) # 'qtdatavisualization' -> 'QtDataVisualization' module = _correct_module_lettercase('-'.join(module.split('-')[1:-1])) # eg1: 'qml-qtdatavisualization-abstract3dseries' -> ['qml', # 'qtdatavisualization', 'abstract3dseries'] -> [ # 'qtdatavisualization'] -> 'qtdatavisualization' # -> 'QtDataVisualization' # eg2: 'qml-qt3d-input-abstractactioninput' -> ['qml', 'qt3d', # 'input', 'abstractactioninput'] -> ['qt3d', 'input', # 'abstractactioninput'] -> 'qt3d-input' -> 'Qt3D.Input' # 注: 为什么要舍去末尾的元素? 因为末尾的那个是 `type_name`, 不是 # `module`. 接下来我们会抽取 `type_name`. type_name = e.text.split(':', 1)[0] # 注意我们不使用 `correct_module_lettercase(match.group(2).split('-') # [-1])`, 是因为 `correct_module_lettercase` 的词库范围比较小, 仅对 # `module_group` 和 `module` 做了覆盖, 不能保证对 `type_name` 的处理正 # 确; 而 `soup` 是可以比较轻松地通过 tag 提取到它的, 所以通过 html 元 # 素获取. # e.g. 'RadioButton: QtQuickControls' -> 'RadioButton' lk.loga(module_group, module, type_name) data[module_group][module][type_name] = path read_and_write.dumps(data, file_o)