forked from CrossDark/CrossDown
Merge pull request 'V1' (#1) from V1 into main
Reviewed-on: crossdark/CrossDown#1
This commit is contained in:
commit
f8488570e1
336
CrossDown/Core.py
Normal file
336
CrossDown/Core.py
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
from markdown.extensions import Extension, extra, admonition, meta, sane_lists, toc, wikilinks, codehilite
|
||||||
|
|
||||||
|
from pygments.formatters import HtmlFormatter
|
||||||
|
|
||||||
|
from markdown.treeprocessors import Treeprocessor
|
||||||
|
from markdown.inlinepatterns import Pattern as Pattern_
|
||||||
|
from markdown.preprocessors import Preprocessor
|
||||||
|
from markdown.inlinepatterns import InlineProcessor
|
||||||
|
from markdown.blockprocessors import BlockProcessor
|
||||||
|
from markdown import Markdown
|
||||||
|
from typing import *
|
||||||
|
import re
|
||||||
|
import xml
|
||||||
|
import emoji
|
||||||
|
|
||||||
|
|
||||||
|
try: # 检测当前平台是否支持扩展语法
|
||||||
|
from .Extra import *
|
||||||
|
EXTRA_ABLE = True
|
||||||
|
except ModuleNotFoundError: # 不支持扩展语法
|
||||||
|
EXTRA_ABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
class HighlightHtmlFormatter(HtmlFormatter):
|
||||||
|
def __init__(self, lang_str='', **options):
|
||||||
|
super().__init__(**options)
|
||||||
|
# lang_str has the value {lang_prefix}{lang}
|
||||||
|
# specified by the CodeHilite's options
|
||||||
|
self.lang_str = lang_str.split('-')[-1]
|
||||||
|
|
||||||
|
def _wrap_code(self, source):
|
||||||
|
yield 0, f'<code class="{self.lang_str}">'
|
||||||
|
yield from source
|
||||||
|
yield 0, '</code>'
|
||||||
|
|
||||||
|
|
||||||
|
Extensions = {
|
||||||
|
'基本扩展': extra.ExtraExtension(fenced_code={'lang_prefix': ''}),
|
||||||
|
'警告扩展': admonition.AdmonitionExtension(),
|
||||||
|
'元数据': meta.MetaExtension(),
|
||||||
|
'能列表': sane_lists.SaneListExtension(),
|
||||||
|
'目录': toc.TocExtension(),
|
||||||
|
'内部链接': wikilinks.WikiLinkExtension(),
|
||||||
|
'代码高亮': codehilite.CodeHiliteExtension(guess_lang=False, pygments_formatter=HighlightHtmlFormatter),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Simple(InlineProcessor):
|
||||||
|
"""
|
||||||
|
可通过简单的正则表达式和HTML标签实现的样式
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pattern: str, tag: str):
|
||||||
|
"""
|
||||||
|
初始化
|
||||||
|
:param pattern: 正则表达式
|
||||||
|
:param tag: html标签
|
||||||
|
"""
|
||||||
|
super().__init__(pattern)
|
||||||
|
self.tag = tag
|
||||||
|
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
tag = xml.etree.ElementTree.Element(self.tag) # 创建标签
|
||||||
|
tag.text = match.group(1) # 获取匹配到的文本并设置为标签的内容
|
||||||
|
|
||||||
|
return tag, match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class Nest(InlineProcessor):
|
||||||
|
"""
|
||||||
|
需要嵌套HTML标签实现的样式
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pattern: str, outer_tag: str, inner_tag: str):
|
||||||
|
"""
|
||||||
|
初始化
|
||||||
|
:param pattern: 正则表达式
|
||||||
|
:param outer_tag: 外层html标签
|
||||||
|
:param inner_tag: 内层html标签
|
||||||
|
"""
|
||||||
|
super().__init__(pattern)
|
||||||
|
self.outer_tag = outer_tag
|
||||||
|
self.inner_tag = inner_tag
|
||||||
|
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
outer_tag = xml.etree.ElementTree.Element(self.outer_tag) # 创建外层标签
|
||||||
|
inner_tag = xml.etree.ElementTree.SubElement(outer_tag, self.inner_tag) # 创建内层标签
|
||||||
|
outer_tag.text = match.group(1) # 设置外层标签文本
|
||||||
|
inner_tag.text = match.group(2) # 设置内层标签文本
|
||||||
|
|
||||||
|
return outer_tag, match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class ID(InlineProcessor):
|
||||||
|
"""
|
||||||
|
需要对HTML标签设置ID实现的样式
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pattern: str, tag: str, property_: str, value: Union[str, bool] = None):
|
||||||
|
"""
|
||||||
|
初始化
|
||||||
|
:param pattern: 正则表达式
|
||||||
|
:param tag: html标签
|
||||||
|
:param property_: html标签属性名称
|
||||||
|
:param value: html标签属性的值 不设置时为第二个匹配组,设置为整数时则为指定的匹配组,设置为字符串则为原始字符串
|
||||||
|
"""
|
||||||
|
super().__init__(pattern)
|
||||||
|
self.tag = tag
|
||||||
|
self.property = property_
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
tag = xml.etree.ElementTree.Element(self.tag) # 创建标签
|
||||||
|
tag.text = match.group(1) # 设置标签内容
|
||||||
|
tag.set(self.property, match.group(2) if self.value is None else self.value) # 设置标签属性,属性的值默认为第二个匹配组
|
||||||
|
|
||||||
|
return tag, match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class Emoji(InlineProcessor):
|
||||||
|
"""
|
||||||
|
需要对HTML标签设置ID实现的样式
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pattern: str):
|
||||||
|
"""
|
||||||
|
初始化
|
||||||
|
:param pattern: 正则表达式
|
||||||
|
"""
|
||||||
|
super().__init__(pattern)
|
||||||
|
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
return emoji.emojize(match.group(0)), match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class Syllabus(BlockProcessor):
|
||||||
|
# 定义提纲的正则表达式
|
||||||
|
syllabus_re = r'(\d+(\.\d+)*)\s+(.*)'
|
||||||
|
|
||||||
|
def test(self, parent, block):
|
||||||
|
# 检查当前块是否匹配我们的正则表达式
|
||||||
|
return re.match(self.syllabus_re, block)
|
||||||
|
|
||||||
|
def run(self, parent, blocks):
|
||||||
|
syllabus = re.match(self.syllabus_re, blocks[0]) # 匹配提纲的号和内容
|
||||||
|
header = xml.etree.ElementTree.SubElement(parent, f'h{len(syllabus.group(1).split("."))}') # 按照提纲号等级创建标题
|
||||||
|
header.set('id', syllabus.group(1)) # 设置提纲ID
|
||||||
|
header.text = syllabus.group(1) + ' ' + syllabus.group(3) # 设置提纲内容
|
||||||
|
blocks[0] = ''
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class BoxBlock(BlockProcessor):
|
||||||
|
def __init__(self, parser, re_start, re_end, style):
|
||||||
|
super().__init__(parser)
|
||||||
|
self.re_start = re_start # start line, e.g., ` !!!!
|
||||||
|
self.re_end = re_end # last non-blank line, e.g, '!!!\n \n\n'
|
||||||
|
self.style = style
|
||||||
|
|
||||||
|
def test(self, parent, block):
|
||||||
|
return re.match(self.re_start, block)
|
||||||
|
|
||||||
|
def run(self, parent, blocks):
|
||||||
|
original_block = blocks[0]
|
||||||
|
blocks[0] = re.sub(self.re_start, '', blocks[0])
|
||||||
|
|
||||||
|
# Find block with ending fence
|
||||||
|
for block_num, block in enumerate(blocks):
|
||||||
|
if re.search(self.re_end, block):
|
||||||
|
# remove fence
|
||||||
|
blocks[block_num] = re.sub(self.re_end, '', block)
|
||||||
|
# render fenced area inside a new div
|
||||||
|
e = xml.etree.ElementTree.SubElement(parent, 'div')
|
||||||
|
e.set('style', self.style)
|
||||||
|
self.parser.parseBlocks(e, blocks[0:block_num + 1])
|
||||||
|
# remove used blocks
|
||||||
|
for i in range(0, block_num + 1):
|
||||||
|
blocks.pop(0)
|
||||||
|
return True # or could have had no return statement
|
||||||
|
# No closing marker! Restore and do nothing
|
||||||
|
blocks[0] = original_block
|
||||||
|
return False # equivalent to our test() routine returning False
|
||||||
|
|
||||||
|
|
||||||
|
class _Anchor(InlineProcessor):
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
tag = xml.etree.ElementTree.Element('span') # 创建标签
|
||||||
|
tag.text = match.group(1)
|
||||||
|
tag.set('id', match.group(1)) # 设置id
|
||||||
|
|
||||||
|
return tag, match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class LinkLine(InlineProcessor):
|
||||||
|
def handleMatch(self, match, match_line):
|
||||||
|
tag = xml.etree.ElementTree.Element('a') # 创建标签
|
||||||
|
tag.set('href', '#' + match.group(1)) # 设置id
|
||||||
|
tag.text = match.group(1)
|
||||||
|
|
||||||
|
return tag, match.start(), match.end()
|
||||||
|
|
||||||
|
|
||||||
|
class CodeLine(Treeprocessor):
|
||||||
|
def __init__(self, variable: Dict):
|
||||||
|
super().__init__()
|
||||||
|
self.variable = variable
|
||||||
|
|
||||||
|
def run(self, root):
|
||||||
|
for elem in root.iter('p'): # 在所有段落中查找单行代码
|
||||||
|
if elem.findall('code'): # 找到单行代码
|
||||||
|
for code in elem:
|
||||||
|
if re.match(r'\$[^$]*\$', code.text): # 渲染Latex
|
||||||
|
if isinstance(elem.text, str): # 这个段落还有其它内容
|
||||||
|
elem.text += fr'\({code.text[1:-1]}\){code.tail}' # 插入latex
|
||||||
|
else:
|
||||||
|
elem.text = fr'\({code.text[1:-1]}\)' # latex是段落中唯一的内容
|
||||||
|
elem.remove(code)
|
||||||
|
elif re.match(r'¥[^$]*¥', code.text): # 是数学函数(单行)
|
||||||
|
if EXTRA_ABLE: # 支持扩展语法
|
||||||
|
expression, range_ = re.findall(r'¥([^$]*)¥(€[^$]*€)?', code.text)[0] # 分离表达式与范围(如果有)
|
||||||
|
x_r = (-10, 10)
|
||||||
|
y_r = (-20, 20)
|
||||||
|
if range_ != '': # 定义了范围
|
||||||
|
ranges = range_[1:-1].split('|')
|
||||||
|
if len(ranges) in (1, 2): # 定义的范围正确
|
||||||
|
x_r = tuple(int(i) for i in ranges[0].split(','))
|
||||||
|
if len(ranges) == 2: # 定义了y范围
|
||||||
|
y_r = tuple(int(i) for i in ranges[1].split(','))
|
||||||
|
code.tag = 'img'
|
||||||
|
code.set('src', f"""data:image/png;base64,{(function_drawing(
|
||||||
|
function=lambda x: eval(expression.split('=')[1]), x_range=x_r, y_range=y_r
|
||||||
|
))}""") # 绘制函数图像
|
||||||
|
code.set('alt', 'Base64 函数图片')
|
||||||
|
else: # 不支持扩展语法
|
||||||
|
code.tag = 'span'
|
||||||
|
code.set('class', 'block')
|
||||||
|
code.text = '该平台不支持扩展语法'
|
||||||
|
elif re.match(r'\{[^$]*}', code.text): # 是强调
|
||||||
|
code.tag = 'span'
|
||||||
|
code.set('class', 'block')
|
||||||
|
key = code.text[1:-1] # 去掉两边的{}
|
||||||
|
if key in self.variable:
|
||||||
|
code.text = self.variable[key]
|
||||||
|
else:
|
||||||
|
code.text = key
|
||||||
|
|
||||||
|
|
||||||
|
class CodeBlock(Treeprocessor):
|
||||||
|
def run(self, root):
|
||||||
|
for code in root.findall('p'):
|
||||||
|
# 在这里处理 <pre> 标签
|
||||||
|
# 例如,你可以添加属性或修改内容
|
||||||
|
print(f'{code.text} | {code.tag}')
|
||||||
|
|
||||||
|
|
||||||
|
class Basic(Extension): # TODO InlineProcessor 不能渲染一行中两个以上的元素(内置的扩展斜体和粗体的优先级好像是一样的)
|
||||||
|
"""
|
||||||
|
渲染基本样式
|
||||||
|
"""
|
||||||
|
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
md.registerExtension(self) # 注册扩展
|
||||||
|
md.inlinePatterns.register(Simple(r'~~(.*?)~~', tag='s'), 'strikethrough', 1) # ~~删除线~~
|
||||||
|
md.inlinePatterns.register(Simple(r'~(.*?)~', tag='u'), 'underline', 2) # ~下划线~
|
||||||
|
md.inlinePatterns.register(Simple(r'==(.*?)==', tag='mark'), 'high_light', 3) # ==高亮==
|
||||||
|
md.inlinePatterns.register(Nest(
|
||||||
|
r'\[(.*?)]\^\((.*?)\)', outer_tag='ruby', inner_tag='rt'), 'up', 4
|
||||||
|
) # [在文本的正上方添加一行小文本]^(主要用于标拼音)
|
||||||
|
md.inlinePatterns.register(ID(
|
||||||
|
r'\[(.*?)]-\((.*?)\)', tag='span', property_='title'), 'hide', 5
|
||||||
|
) # [在指定的文本里面隐藏一段文本]-(只有鼠标放在上面才会显示隐藏文本)
|
||||||
|
md.inlinePatterns.register(Emoji(r':(.+?):'), 'emoji', 6) # 将emoji短代码转换为emoji字符
|
||||||
|
md.parser.blockprocessors.register(Syllabus(md.parser), 'syllabus', 11) # 渲染提纲
|
||||||
|
|
||||||
|
|
||||||
|
class Box(Extension):
|
||||||
|
"""
|
||||||
|
渲染外框
|
||||||
|
"""
|
||||||
|
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
md.registerExtension(self) # 注册扩展
|
||||||
|
# 红框警告
|
||||||
|
md.inlinePatterns.register(ID(
|
||||||
|
r'!{3}(.+?)!{3}', tag='div', property_='style', value='display: inline-block; border: 1px solid red;'
|
||||||
|
), 'warning_in_line', 20) # 行内
|
||||||
|
md.parser.blockprocessors.register(BoxBlock(
|
||||||
|
md.parser, r'^ *!{3} *\n', r'\n *!{3}\s*$', 'display: inline-block; border: 1px solid red;'
|
||||||
|
), 'warning_box', 175) # 块
|
||||||
|
|
||||||
|
# 黄框提醒
|
||||||
|
md.inlinePatterns.register(ID(
|
||||||
|
r'!-!(.+?)!-!', tag='div', property_='style', value='display: inline-block; border: 1px solid yellow;'
|
||||||
|
), 'reminding_in_line', 21) # 行内
|
||||||
|
md.parser.blockprocessors.register(BoxBlock(
|
||||||
|
md.parser, r'^ *!-! *\n', r'\n *!-!\s*$', 'display: inline-block; border: 1px solid yellow;'
|
||||||
|
), 'reminding_box', 176) # 块
|
||||||
|
|
||||||
|
# 绿框安心
|
||||||
|
md.inlinePatterns.register(ID(
|
||||||
|
r',{3}(.+?),{3}', tag='div', property_='style', value='display: inline-block; border: 1px solid green;'
|
||||||
|
), 'reminding_in_line', 22) # 行内
|
||||||
|
md.parser.blockprocessors.register(BoxBlock(
|
||||||
|
md.parser, r'^ *,{3} *\n', r'\n *,{3}\s*$', 'display: inline-block; border: 1px solid green;'
|
||||||
|
), 'reminding_box', 177) # 块
|
||||||
|
|
||||||
|
# 蓝框怀疑
|
||||||
|
md.inlinePatterns.register(ID(
|
||||||
|
r',-,(.+?),{2}', tag='div', property_='style', value='display: inline-block; border: 1px solid blue;'
|
||||||
|
), 'reminding_in_line', 23) # 行内
|
||||||
|
md.parser.blockprocessors.register(BoxBlock(
|
||||||
|
md.parser, r'^ *,-, *\n', r'\n *,-,\s*$', 'display: inline-block; border: 1px solid blue;'
|
||||||
|
), 'reminding_box', 178) # 块
|
||||||
|
|
||||||
|
|
||||||
|
class Anchor(Extension):
|
||||||
|
def extendMarkdown(self, md: Markdown):
|
||||||
|
md.registerExtension(self) # 注册扩展
|
||||||
|
md.inlinePatterns.register(_Anchor(r'\{#([^{}#]+)}'), 'anchor', 0) # 定义锚点
|
||||||
|
md.inlinePatterns.register(LinkLine(r'\{([^{}#]+)}'), 'line_link', 0) # 添加页内链接
|
||||||
|
|
||||||
|
|
||||||
|
class Code(Extension):
|
||||||
|
def __init__(self, variable: Dict):
|
||||||
|
super().__init__()
|
||||||
|
self.variable = variable
|
||||||
|
|
||||||
|
def extendMarkdown(self, md: Markdown):
|
||||||
|
md.registerExtension(self) # 注册扩展
|
||||||
|
md.treeprocessors.register(CodeLine(variable=self.variable), 'code_line', 0) # 渲染单行代码块
|
||||||
|
# md.treeprocessors.register(CodeBlock(), 'code_block', 1) # 渲染多行代码块
|
||||||
|
|
||||||
|
|
||||||
|
def main(text: str, variable: Dict) -> Tuple[str, Dict[str, List[str]]]:
|
||||||
|
md = Markdown(extensions=[Basic(), Box(), Anchor()] + list(Extensions.values()) + [Code(variable=variable)])
|
||||||
|
return md.convert(text), md.Meta
|
@ -1,4 +0,0 @@
|
|||||||
from markdown.extensions import Extension
|
|
||||||
from markdown.treeprocessors import Treeprocessor
|
|
||||||
from markdown.inlinepatterns import Pattern
|
|
||||||
from markdown import Markdown
|
|
43
CrossDown/Extra.py
Normal file
43
CrossDown/Extra.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
import base64
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
|
||||||
|
EXTRA = [
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def function_drawing(function, x_range=(-10, 10), y_range=(-20, 20), dpi=100):
|
||||||
|
# 创建一个图像和坐标轴对象
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
|
||||||
|
# 生成x值
|
||||||
|
x = np.linspace(x_range[0], x_range[1], 400)
|
||||||
|
|
||||||
|
# 计算y值
|
||||||
|
y = function(x)
|
||||||
|
|
||||||
|
# 绘制图像
|
||||||
|
ax.plot(x, y)
|
||||||
|
|
||||||
|
# 设置坐标轴范围
|
||||||
|
ax.set_xlim(x_range)
|
||||||
|
ax.set_ylim(y_range)
|
||||||
|
|
||||||
|
# 隐藏坐标轴
|
||||||
|
ax.axis('on')
|
||||||
|
|
||||||
|
# 将图像保存到BytesIO对象
|
||||||
|
buf = BytesIO()
|
||||||
|
fig.savefig(buf, format='png', dpi=dpi)
|
||||||
|
|
||||||
|
# 获取图像数据的Base64编码
|
||||||
|
data = base64.b64encode(buf.getbuffer()).decode("ascii")
|
||||||
|
|
||||||
|
# 关闭图像和坐标轴对象
|
||||||
|
plt.close(fig)
|
||||||
|
|
||||||
|
# 返回Base64编码的字符串
|
||||||
|
return data
|
@ -0,0 +1,60 @@
|
|||||||
|
from typing import *
|
||||||
|
from .Core import main
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'main', # 主函数
|
||||||
|
'indent', # 添加空格
|
||||||
|
'HEAD', #
|
||||||
|
'BODY', #
|
||||||
|
]
|
||||||
|
__version__ = '0.11.2'
|
||||||
|
__author__ = 'CrossDark'
|
||||||
|
__email__ = 'liuhanbo333@icloud.com'
|
||||||
|
__source__ = 'https://crossdark.net/'
|
||||||
|
__license__ = """MIT"""
|
||||||
|
|
||||||
|
|
||||||
|
HEAD = (
|
||||||
|
'<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML"></script>',
|
||||||
|
'<link href="https://cdn.jsdelivr.net/npm/prismjs/themes/prism.css" rel="stylesheet" />',
|
||||||
|
'<script src="https://cdn.jsdelivr.net/npm/prismjs/prism.js"></script>',
|
||||||
|
'<script src="https://cdn.jsdelivr.net/npm/prismjs/components/prism-yaml.min.js"></script>',
|
||||||
|
|
||||||
|
# mermaid
|
||||||
|
'<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>',
|
||||||
|
'<script>',
|
||||||
|
' mermaid.initialize({startOnLoad:true});',
|
||||||
|
'</script>',
|
||||||
|
|
||||||
|
# Highlight.js
|
||||||
|
# '<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/default.min.css">',
|
||||||
|
# '<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>',
|
||||||
|
# '<script>hljs.highlightAll();</script>',
|
||||||
|
|
||||||
|
'<link rel="stylesheet" href="../Static/styles.css">',
|
||||||
|
|
||||||
|
'<style>',
|
||||||
|
' .block {',
|
||||||
|
' background-color: grey; /* 灰色背景 */',
|
||||||
|
' color: white; /* 白色文字 */',
|
||||||
|
'}',
|
||||||
|
'</style>'
|
||||||
|
)
|
||||||
|
|
||||||
|
BODY = (
|
||||||
|
'',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def indent(input_: Union[str, List, Tuple], indent_spaces: int = 4) -> str:
|
||||||
|
"""
|
||||||
|
给字符串中的每一行前面加上缩进。
|
||||||
|
:param input_: 原始字符串,可以包含多行。
|
||||||
|
:param indent_spaces: 每行前面要添加的空格数,默认为4。
|
||||||
|
:return: 带缩进的新字符串。
|
||||||
|
"""
|
||||||
|
# 使用字符串的splitlines()方法分割原始字符串为行列表,如果是可迭代对象则直接遍历
|
||||||
|
# 遍历行列表,给每行前面加上相应的缩进,并重新组合成字符串
|
||||||
|
return "\n".join(
|
||||||
|
f"{' ' * indent_spaces}{line}" for line in (lambda x: x.splitlines() if isinstance(x, str) else x)(input_))
|
@ -6,7 +6,6 @@ import markdown
|
|||||||
|
|
||||||
try: # 检测当前平台是否支持扩展语法
|
try: # 检测当前平台是否支持扩展语法
|
||||||
import CrossMore
|
import CrossMore
|
||||||
|
|
||||||
EXTRA_ABLE = True
|
EXTRA_ABLE = True
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
EXTRA_ABLE = False
|
EXTRA_ABLE = False
|
338
README.html
338
README.html
File diff suppressed because one or more lines are too long
186
README.md
186
README.md
@ -1,13 +1,13 @@
|
|||||||
|
Title: CrossDown示例
|
||||||
|
Summary: 够简洁的了
|
||||||
|
Authors: CrossDark
|
||||||
|
Date: __date__
|
||||||
|
base_url: http://crossdark.net:3000/crossdark/CrossDown
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
---
|
|
||||||
title: "Markdown文档标题"
|
|
||||||
author: "作者姓名"
|
|
||||||
date: "2024-09-26"
|
|
||||||
---
|
|
||||||
|
|
||||||
# CrossDown
|
# CrossDown
|
||||||
自制的markdown,添加了一些自定义的语法
|
自制的markdown,添加了一些自定义的语法
|
||||||
效果请见[README.html](https://github.com/CrossDark/CrossDown/blob/main/README.html)
|
效果请见[README.html](https://github.com/CrossDark/CrossDown/blob/main/README.html)
|
||||||
|
|
||||||
1 基本语法
|
1 基本语法
|
||||||
@ -67,33 +67,39 @@ ___
|
|||||||
|
|
||||||
[变量]: https://crossdark.com
|
[变量]: https://crossdark.com
|
||||||
|
|
||||||
2 变量
|
2 缩写
|
||||||
|
|
||||||
2.1 定义
|
2.1 定义
|
||||||
|
|
||||||
{变量名} = 值
|
*[缩写]: 长的文本
|
||||||
|
|
||||||
2.2 赋值
|
2.2 赋值
|
||||||
|
|
||||||
{变量名} {锚点名}
|
直接在文本中使用 缩写 即可
|
||||||
|
|
||||||
提纲的编号已经自动配置为了锚点,可直接使用{2}
|
3 锚点
|
||||||
|
|
||||||
2.3 添加锚点
|
3.1 定义
|
||||||
|
|
||||||
{#锚点名}
|
{#锚点名}
|
||||||
|
|
||||||
3 代码块
|
3.2 页内链接
|
||||||
|
|
||||||
3.1 `单行`
|
{锚点名}
|
||||||
|
|
||||||
3.1.1 LaTex
|
4 代码块
|
||||||
|
|
||||||
`$CO_2$`
|
4.1 `单行`
|
||||||
|
|
||||||
`$H_2O$`
|
4.1.1 LaTex
|
||||||
|
|
||||||
3.1.2 函数
|
这是`$CO_2$`二氧化碳
|
||||||
|
|
||||||
|
这是`$H_2O$`水
|
||||||
|
|
||||||
|
`$\lg\left(\frac{目标生物的理智值}{稳定折磨型工具人的理智值}\right)$`
|
||||||
|
|
||||||
|
4.1.2 函数
|
||||||
|
|
||||||
`¥y=x*2+1¥` // 不定义范围
|
`¥y=x*2+1¥` // 不定义范围
|
||||||
|
|
||||||
@ -101,11 +107,17 @@ ___
|
|||||||
|
|
||||||
`¥y=x**3¥€-50,50|-100,100€` // 定义了y范围
|
`¥y=x**3¥€-50,50|-100,100€` // 定义了y范围
|
||||||
|
|
||||||
3.2 多行
|
4.1.3 强调
|
||||||
|
|
||||||
3.2.1 YAML
|
`{强调文本}`
|
||||||
|
|
||||||
`
|
`{强调变量}`
|
||||||
|
|
||||||
|
4.2 多行
|
||||||
|
|
||||||
|
4.2.1 YAML
|
||||||
|
|
||||||
|
```yaml
|
||||||
A:
|
A:
|
||||||
1. a
|
1. a
|
||||||
2. b
|
2. b
|
||||||
@ -114,25 +126,32 @@ B:
|
|||||||
- a
|
- a
|
||||||
- b
|
- b
|
||||||
- c
|
- c
|
||||||
`
|
```
|
||||||
|
|
||||||
3.2.2 Python
|
4.2.2 Python
|
||||||
|
|
||||||
`python
|
```python
|
||||||
|
def main():
|
||||||
print('CrossDown')
|
print('CrossDown')
|
||||||
`
|
```
|
||||||
|
|
||||||
3.2.3 Mermaid
|
4.2.3 Mermaid
|
||||||
|
|
||||||
`mermaid
|
```mermaid
|
||||||
graph LR
|
graph TD
|
||||||
A-->B
|
A[开始]-->B[流程]
|
||||||
A-->C
|
B-->C{判断}
|
||||||
B-->D
|
C-->|结果1|D[结束1]
|
||||||
C-->D
|
C-->|结果2|E[结束2]
|
||||||
`
|
```
|
||||||
|
|
||||||
4 转义
|
4.2.4 shell
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
5 转义
|
||||||
|
|
||||||
\\
|
\\
|
||||||
|
|
||||||
@ -140,7 +159,7 @@ graph LR
|
|||||||
|
|
||||||
\*
|
\*
|
||||||
|
|
||||||
5 引用
|
6 引用
|
||||||
|
|
||||||
> 一级引用
|
> 一级引用
|
||||||
>> 二级引用
|
>> 二级引用
|
||||||
@ -151,68 +170,129 @@ graph LR
|
|||||||
>
|
>
|
||||||
> 引文内添加*斜体***粗体**~下划线~~~删除线~~==高亮==
|
> 引文内添加*斜体***粗体**~下划线~~~删除线~~==高亮==
|
||||||
|
|
||||||
6 提纲
|
7 提纲
|
||||||
|
|
||||||
6.1 提纲号
|
7.1 提纲号
|
||||||
|
|
||||||
以数字和点组成,通过空格与提纲名分隔,例如:
|
以数字和点组成,通过空格与提纲名分隔,例如:
|
||||||
|
|
||||||
6.1.1 提纲号示例
|
7.1.1 提纲号示例
|
||||||
|
|
||||||
点不能出现在开头或结尾,例如
|
点不能出现在开头或结尾,例如
|
||||||
|
|
||||||
.6.1.2 错误示范
|
.7.1.2 错误示范
|
||||||
|
|
||||||
6.1.3. 错误示范
|
7.1.3. 错误示范
|
||||||
|
|
||||||
不能出现两个及以上连续的点,例如:
|
不能出现两个及以上连续的点,例如:
|
||||||
|
|
||||||
6..1...4 错误示范
|
7..1...4 错误示范
|
||||||
|
|
||||||
提纲号会被自动配置为锚点,可直接使用{6}{6.1}
|
提纲号会被自动配置为锚点,可直接使用{7}{7.1}
|
||||||
|
|
||||||
7 注释
|
8 注释
|
||||||
|
|
||||||
7.1 强注释
|
8.1 强注释
|
||||||
|
|
||||||
|=
|
|=
|
||||||
无论如何都会被移除
|
无论如何都会被移除
|
||||||
`放在代码块里也没用`
|
`放在代码块里也没用`
|
||||||
=|
|
=|
|
||||||
|
|
||||||
7.2 弱注释
|
8.2 弱注释
|
||||||
|
|
||||||
|
<!-- 这是注释 -->
|
||||||
|
|
||||||
只有在 // 后面才会被移除
|
只有在 // 后面才会被移除
|
||||||
|
|
||||||
`// 代码中的注释弱不会被移除`
|
`// 代码中的注释弱不会被移除`
|
||||||
|
|
||||||
8 列表
|
9 列表
|
||||||
|
|
||||||
|
9.1 有序列表
|
||||||
|
|
||||||
8.1 有序列表
|
|
||||||
1. a
|
1. a
|
||||||
2. b
|
2. b
|
||||||
3. c
|
3. c
|
||||||
4. d
|
4. d
|
||||||
|
|
||||||
8.2 无序列表
|
9.2 无序列表
|
||||||
|
|
||||||
- A
|
- A
|
||||||
- B
|
- B
|
||||||
- C
|
- C
|
||||||
- D
|
- D
|
||||||
|
|
||||||
9 表格
|
10 表格
|
||||||
|
|
||||||
| 表头1 | 表头2 | 表头3 |
|
| 表头1 | 表头2 | 表头3 |
|
||||||
|:----:|:----:|:----:|
|
|:----:|:----:|:----:|
|
||||||
| 单元格1 | 单元格2 | 单元格3 |
|
| 单元格1 | 单元格2 | 单元格3 |
|
||||||
| 单元格4 | 单元格5 | 单元格6 |
|
| 单元格4 | 单元格5 | 单元格6 |
|
||||||
|
|
||||||
10 警告
|
11 警告
|
||||||
|
|
||||||
!!! 这是一条警告
|
!!! warning "警告标题"
|
||||||
|
警告内容
|
||||||
|
|
||||||
11 Emoji
|
12 Emoji
|
||||||
|
|
||||||
:person_biking:
|
:person_biking:
|
||||||
|
|
||||||
:grinning_face_with_big_eyes:
|
这是一个笑脸:grinning_face_with_big_eyes:图案
|
||||||
|
|
||||||
|
13 脚注
|
||||||
|
|
||||||
|
13.1 使用
|
||||||
|
|
||||||
|
这是一个[^脚注]
|
||||||
|
|
||||||
|
13.2 定义
|
||||||
|
|
||||||
|
[^脚注]: 一段长的文本用于说明
|
||||||
|
|
||||||
|
13.3 放置
|
||||||
|
|
||||||
|
通过一下代码可以将文章中所有的脚注定义集中于一处
|
||||||
|
|
||||||
|
///Footnotes Go Here///
|
||||||
|
|
||||||
|
否则所有定义将被集中在文章末尾
|
||||||
|
|
||||||
|
14 外框
|
||||||
|
|
||||||
|
14.1 警告
|
||||||
|
|
||||||
|
这是一个!!!警告!!!……
|
||||||
|
|
||||||
|
!!!
|
||||||
|
这是一条警告
|
||||||
|
!!!
|
||||||
|
|
||||||
|
14.2 提醒
|
||||||
|
|
||||||
|
这是一个!-!提醒!-!……
|
||||||
|
|
||||||
|
!-!
|
||||||
|
这是一条提醒
|
||||||
|
!-!
|
||||||
|
|
||||||
|
14.3 安心
|
||||||
|
|
||||||
|
这是一个,,,安心,,,……
|
||||||
|
|
||||||
|
,,,
|
||||||
|
这是一条安心
|
||||||
|
,,,
|
||||||
|
|
||||||
|
14.4 怀疑
|
||||||
|
|
||||||
|
这是一个,-,怀疑,-,……
|
||||||
|
|
||||||
|
,-,
|
||||||
|
这是一条怀疑
|
||||||
|
,-,
|
||||||
|
|
||||||
|
15 内部链接
|
||||||
|
|
||||||
|
[[Bracketed]]
|
||||||
|
75
Static/styles.css
Normal file
75
Static/styles.css
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
pre { line-height: 125%; }
|
||||||
|
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||||
|
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
|
||||||
|
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||||
|
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
|
||||||
|
.codehilite .hll { background-color: #ffffcc }
|
||||||
|
.codehilite { background: #f8f8f8; }
|
||||||
|
.codehilite .c { color: #3D7B7B; font-style: italic } /* Comment */
|
||||||
|
.codehilite .err { border: 1px solid #FF0000 } /* Error */
|
||||||
|
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
|
||||||
|
.codehilite .o { color: #666666 } /* Operator */
|
||||||
|
.codehilite .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
|
||||||
|
.codehilite .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
|
||||||
|
.codehilite .cp { color: #9C6500 } /* Comment.Preproc */
|
||||||
|
.codehilite .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
|
||||||
|
.codehilite .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
|
||||||
|
.codehilite .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
|
||||||
|
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
|
||||||
|
.codehilite .ge { font-style: italic } /* Generic.Emph */
|
||||||
|
.codehilite .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
||||||
|
.codehilite .gr { color: #E40000 } /* Generic.Error */
|
||||||
|
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||||
|
.codehilite .gi { color: #008400 } /* Generic.Inserted */
|
||||||
|
.codehilite .go { color: #717171 } /* Generic.Output */
|
||||||
|
.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||||
|
.codehilite .gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||||
|
.codehilite .gt { color: #0044DD } /* Generic.Traceback */
|
||||||
|
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
||||||
|
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
||||||
|
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
||||||
|
.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
|
||||||
|
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
||||||
|
.codehilite .kt { color: #B00040 } /* Keyword.Type */
|
||||||
|
.codehilite .m { color: #666666 } /* Literal.Number */
|
||||||
|
.codehilite .s { color: #BA2121 } /* Literal.String */
|
||||||
|
.codehilite .na { color: #687822 } /* Name.Attribute */
|
||||||
|
.codehilite .nb { color: #008000 } /* Name.Builtin */
|
||||||
|
.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||||
|
.codehilite .no { color: #880000 } /* Name.Constant */
|
||||||
|
.codehilite .nd { color: #AA22FF } /* Name.Decorator */
|
||||||
|
.codehilite .ni { color: #717171; font-weight: bold } /* Name.Entity */
|
||||||
|
.codehilite .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
|
||||||
|
.codehilite .nf { color: #0000FF } /* Name.Function */
|
||||||
|
.codehilite .nl { color: #767600 } /* Name.Label */
|
||||||
|
.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||||
|
.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
|
||||||
|
.codehilite .nv { color: #19177C } /* Name.Variable */
|
||||||
|
.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||||
|
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
|
||||||
|
.codehilite .mb { color: #666666 } /* Literal.Number.Bin */
|
||||||
|
.codehilite .mf { color: #666666 } /* Literal.Number.Float */
|
||||||
|
.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
|
||||||
|
.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
|
||||||
|
.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
|
||||||
|
.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
|
||||||
|
.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
|
||||||
|
.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
|
||||||
|
.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
|
||||||
|
.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
||||||
|
.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
|
||||||
|
.codehilite .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
|
||||||
|
.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
|
||||||
|
.codehilite .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
|
||||||
|
.codehilite .sx { color: #008000 } /* Literal.String.Other */
|
||||||
|
.codehilite .sr { color: #A45A77 } /* Literal.String.Regex */
|
||||||
|
.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
|
||||||
|
.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
|
||||||
|
.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
|
||||||
|
.codehilite .fm { color: #0000FF } /* Name.Function.Magic */
|
||||||
|
.codehilite .vc { color: #19177C } /* Name.Variable.Class */
|
||||||
|
.codehilite .vg { color: #19177C } /* Name.Variable.Global */
|
||||||
|
.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
|
||||||
|
.codehilite .vm { color: #19177C } /* Name.Variable.Magic */
|
||||||
|
.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
|
@ -1,3 +1,4 @@
|
|||||||
Markdown>=3.7
|
Markdown>=3.7
|
||||||
matplotlib>=3.9.2
|
matplotlib>=3.9.2
|
||||||
numpy>=2.1.1
|
numpy>=2.1.1
|
||||||
|
pygments>=2.18.0
|
35
run.py
Normal file
35
run.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from CrossDown import *
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# 开始计时
|
||||||
|
start_time = time.perf_counter_ns()
|
||||||
|
# 主程序
|
||||||
|
with open('README.md', encoding='utf-8') as test:
|
||||||
|
cd, meta = main(test.read(), variable={
|
||||||
|
'a': 'b',
|
||||||
|
'强调变量': '强调值'
|
||||||
|
})
|
||||||
|
print(meta)
|
||||||
|
with open('README.html', 'w', encoding='utf-8') as html:
|
||||||
|
html.write(f"""<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>UTF-8编码示例</title>
|
||||||
|
{indent(HEAD)}
|
||||||
|
<!-- 可以在这里添加其他元数据和CSS链接 -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{indent(BODY)}
|
||||||
|
{indent(cd, 4)}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""")
|
||||||
|
# 停止计时
|
||||||
|
end_time = time.perf_counter_ns()
|
||||||
|
# 输出用时
|
||||||
|
print("运行时间: {:.9f} 秒".format((end_time - start_time) / 1e9))
|
7
setup.py
7
setup.py
@ -5,17 +5,14 @@ with open("README.md", "r") as fh:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="CrossDown",
|
name="CrossDown",
|
||||||
version="0.11.2",
|
version="1.0.1",
|
||||||
author="CrossDark",
|
author="CrossDark",
|
||||||
author_email="liuhanbo333@icloud.com",
|
author_email="liuhanbo333@icloud.com",
|
||||||
description="CrossDark's MarkDown",
|
description="CrossDark's MarkDown",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
url="https://github.com/CrossDark/CrossDown",
|
url="https://github.com/CrossDark/CrossDown",
|
||||||
py_modules=[
|
packages=setuptools.find_packages(),
|
||||||
'CrossDown',
|
|
||||||
'CrossMore',
|
|
||||||
],
|
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'markdown',
|
'markdown',
|
||||||
'matplotlib',
|
'matplotlib',
|
||||||
|
Loading…
Reference in New Issue
Block a user