diff --git a/CrossDown/Core.py b/CrossDown/Core.py index 6c33d28..2bd158d 100644 --- a/CrossDown/Core.py +++ b/CrossDown/Core.py @@ -1,13 +1,14 @@ -import xml -import emoji from markdown.extensions import Extension 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 Extensions = { "Extra": "markdown.extensions.extra", @@ -120,6 +121,56 @@ class Emoji(InlineProcessor): return emoji.emojize(match.group(0)), match.start(), match.end() +class Syllabus_(InlineProcessor): + """ + 需要对HTML标签设置ID实现的样式 + """ + + def __init__(self, pattern: str): + """ + 初始化 + :param pattern: 正则表达式 + """ + super().__init__(pattern) + + def handleMatch(self, match, match_line): + tag = xml.etree.ElementTree.Element(f'h{len(match.group(1).split("."))}') # 创建标签 + tag.text = match.group(1) + ' ' + match.group(3) # 设置标签内容 + tag.set('id', match.group(1)) # 设置标签属性 + + return tag, match.start(), match.end() + + +class Syllabus(BlockProcessor): + # 定义提纲的正则表达式 + ALERT_RE = r'(\d+(\.\d+)*)\s+(.*)' + + def test(self, parent, block): + # 检查当前块是否匹配我们的正则表达式 + return bool(self.ALERT_RE.match(block)) + + def run(self, parent, blocks): + # 处理匹配的块 + block = blocks.pop(0) + m = self.ALERT_RE.search(block) + if m: + before = block[:m.start()] # 匹配之前的文本 + after = block[m.end():] # 匹配之后的文本 + if before: + # 如果匹配之前有文本,则创建一个新的段落来包含它 + p = etree.SubElement(parent, 'p') + p.text = before.strip() + # 创建包含警告内容的 div 元素 + div = etree.SubElement(parent, 'div', {'class': 'alert'}) + div.text = m.group(1).strip() + # 如果匹配之后还有文本,则将其重新添加到块列表中以便后续处理 + if after.strip(): + blocks.insert(0, after) + else: + # 如果没有匹配,则保留原始块以便后续处理器处理 + return False + + class Basic(Extension): """ 渲染基本样式 @@ -136,92 +187,10 @@ class Basic(Extension): md.inlinePatterns.register(ID( r'\[(.*?)]-\((.*?)\)', tag='span', property_='title'), 'hide', 0 ) # [在指定的文本里面隐藏一段文本]-(只有鼠标放在上面才会显示隐藏文本) - md.inlinePatterns.register(Emoji( - r':(.+?):'), 'emoji', 0 - ) # 将emoji短代码转换为emoji字符 - - -class Syllabus(Preprocessor): - def run(self, lines: List[str]) -> List[str]: - return [ - (lambda match, origen: - re.sub(f'^({match.groups()[0]})', # 按照提纲等级添加#和锚点 - fr'{"#" * len(match.groups()[0].split("."))} \1', origen) - if match is not None else origen) # 对于不是提纲的行,直接返回原始字符 - ((lambda x: re.match(r'^([\d.]+) ', x) # 判断是否是提纲 - if not any((x.startswith('.'), # 以.开头 - re.search('\. ', x) is not None, # 存在.+空格 - re.search('\.{2,}', x), # 存在连续的. - )) - else None)(line), line) # 排除.在提纲号开头或结尾的情况 - for line in lines # 分割并遍历文本的每一行 - ] - - -class Value(Preprocessor): - def run(self, lines: List[str]) -> List[str]: - values = { - key: value.strip() # 去除值两侧的空白字符 - for line in lines - for match in [re.match(r'\{([^{}#]+)} ?= ?(.+?)(?=\n|$)', line)] - if match - for key, value in [match.groups()] - } # 识别变量定义 - anchors = re.findall(r'\{#([^{}#]+)}', '\n'.join(lines)) # 识别锚点定义 - text = '\n'.join(lines) # 先合并成一行 - for item in anchors: - text = re.sub(r'\{#(' + item + ')}', r'', text) # 添加锚点 - text = re.sub(r'\{' + item + '}', fr'{item}', text) # 添加页内链接 - for k, v in values.items(): - text = re.sub(r'\{' + k + '} ?= ?(.+?)(?=\n|$)', '', text) # 移除变量的定义 - text = re.sub(r'\{' + k + '}', fr'{v}', text) # 给变量赋值 - return text.split('\n') # 再分割为列表 - - -class Tag(Treeprocessor): - def run(self, root): - """ - 通过修改AST来给标题添加锚点 - """ - for header in root.iter(): - if header.tag in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6'): # 查找标题 - header.set('id', header.text.split(' ')[0]) # 给标题添加锚点 - elif header.tag == 'ul': # 是无序列表 - for i in header: # 遍历列表内容 - try: - i[0].set('href', '#' + i[0].text.split(' ')[0]) # 是目录,更改链接为标准格式 - except IndexError: - pass # 是普通的无序列表 - - -class Basic_(Extension): - """ - 基本扩展 - """ - - def extendMarkdown(self, md): - md.registerExtension(self) # 注册扩展 - md.preprocessors.register(Syllabus(md), 'syllabus', 0) - - -class More(Extension): - """ - 高级扩展 - """ - - def extendMarkdown(self, md): - md.preprocessors.register(Value(md), 'values', 0) - - -class Decorate(Extension): - """ - 修饰扩展,最后处理 - """ - - def extendMarkdown(self, md): - md.treeprocessors.register(Tag(md), 'header', 0) + md.inlinePatterns.register(Emoji(r':(.+?):'), 'emoji', 0) # 将emoji短代码转换为emoji字符 + md.inlinePatterns.register(Syllabus(r'(\d+(\.\d+)*)\s+(.*)'), 'syllabus', 0) # 渲染提纲 def main(text: str) -> Tuple[str, Dict[str, List[str]]]: - md = Markdown(extensions=[Basic(), Basic_(), More()] + list(Extensions.values()) + [Decorate()], safe_mode=False) + md = Markdown(extensions=[Basic()] + list(Extensions.values()), safe_mode=False) return md.convert(text), md.Meta diff --git a/README.html b/README.html index 6881a3b..c4f3dfb 100644 --- a/README.html +++ b/README.html @@ -29,17 +29,17 @@
-自制的markdown,添加了一些自定义的语法klzzwxh:0001效果请见klzzwxh:0000
+
直接在文本中使用 缩写 即可
+
klzzwxh:0017klzzwxh:0018
+ +{#锚点名}
+
单行
$CO_2$
$H_2O$
¥y=x*2+1¥
// 不定义范围
¥y=x**2¥€-50,50€
// 定义了x范围
¥y=x**3¥€-50,50|-100,100€
// 定义了y范围
{强调文本}
A:
1. a
2. b
@@ -182,11 +238,15 @@
- c
print('CrossDown')
graph LR
A-->B
A-->C
@@ -194,11 +254,15 @@
C-->D
\
\a
*
+
-一级引用
@@ -216,42 +280,58 @@
引文内添加klzzwxhklzzwxhklzzwxh:00450042klzzwxh:0043
+引文内添加klzzwxhklzzwxhklzzwxh:00990096klzzwxh:0097
+
以数字和点组成,通过空格与提纲名分隔,例如:
+
点不能出现在开头或结尾,例如
-.7.1.2 错误示范
+.
7.1.3. 错误示范
不能出现两个及以上连续的点,例如:
-7..1…4 错误示范
+7..1…
提纲号会被自动配置为锚点,可直接使用{7}76.1}
+
|=klzzwxhklzzwxhklzzwxh:00340029klzzwxh:0032=|
+ +|=klzzwxhklzzwxhklzzwxh:00690064klzzwxh:0067=|
+
只有在 // 后面才会被移除
// 代码中的注释弱不会被移除
+
警告标题
警告内容
🚴
这是一个笑脸😃图案
+
这是一个1
+
通过一下代码可以将文章中所有的脚注定义集中于一处
否则所有定义将被集中在文章末尾
+