From 54c2584b0fb9029a8de22d63624dda4c1bddd4a6 Mon Sep 17 00:00:00 2001 From: crossdark Date: Sat, 5 Oct 2024 18:25:00 +0800 Subject: [PATCH] =?UTF-8?q?1.5=E6=8F=90=E7=BA=B2=E5=A4=B4=E7=96=BC?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CrossDown/Core.py | 143 +++++++++++++++++-------------------------- README.html | 150 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 179 insertions(+), 114 deletions(-) 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 @@
-

CrossDown

+

CrossDown

自制的markdown,添加了一些自定义的语法klzzwxh:0001效果请见klzzwxh:0000

+

1 基本语法

+

+

1.1 标题

-

一级标题

-

二级标题

-

三级标题

-

四级标题

-
五级标题
-
六级标题
+

+

一级标题

+

二级标题

+

三级标题

+

四级标题

+
五级标题
+
六级标题
+

1.2 样式

+

+

1.2.1 斜体

+

+

1.2.2 粗体

+

+

1.2.3 粗斜体

+

+

1.2.4 下划线

+

+

1.2.5 删除线

+

+

1.2.6 高亮

+

+

1.2.7 在文本的正上方添加一行小文本主要用于标拼音

+

+

1.2.8 在指定的文本里面隐藏一段文本

+

+

1.2.9 分割线

+




+

1.3 链接

+

+

1.3.1 普通链接

+

链接文本

CrossDark

https://crossdark.net/

+

1.3.2 图片

+

链接图片

sea

+

1.3.3 变量链接

+

链接文本

+

2 缩写

+

+

2.1 定义

+

+

2.2 赋值

+

直接在文本中使用 缩写 即可

+

3 锚点

-

klzzwxh:0017klzzwxh:0018

+

+

{#锚点名}

+

4 代码块

+

+

4.1 单行

+

+

4.1.1 LaTex

+

$CO_2$

$H_2O$

+

4.1.2 函数

+

¥y=x*2+1¥ // 不定义范围

¥y=x**2¥€-50,50€ // 定义了x范围

¥y=x**3¥€-50,50|-100,100€ // 定义了y范围

+

4.1.3 强调

+

{强调文本}

+

4.2 多行

+

+

4.2.1 YAML

+

A:
         1. a
         2. b
@@ -182,11 +238,15 @@
         - c
     
+

4.2.2 Python

+

print('CrossDown')
     
+

4.2.3 Mermaid

+

graph LR
         A-->B
         A-->C
@@ -194,11 +254,15 @@
         C-->D
     
+

5 转义

+

\

\a

*

+

6 引用

+

一级引用

@@ -216,42 +280,58 @@
-

引文内添加klzzwxhklzzwxhklzzwxh:00450042klzzwxh:0043

+

引文内添加klzzwxhklzzwxhklzzwxh:00990096klzzwxh:0097

+

7 提纲

+

+

7.1 提纲号

+

以数字和点组成,通过空格与提纲名分隔,例如:

+

7.1.1 提纲号示例

+

点不能出现在开头或结尾,例如

-

.7.1.2 错误示范

+

.

7.1.2 错误示范

+

7.1.3. 错误示范

不能出现两个及以上连续的点,例如:

-

7..1…4 错误示范

+

7..1…

4 错误示范

+

提纲号会被自动配置为锚点,可直接使用{7}76.1}

+

8 注释

+

+

8.1 强注释

-

|=klzzwxhklzzwxhklzzwxh:00340029klzzwxh:0032=|

+

+

|=klzzwxhklzzwxhklzzwxh:00690064klzzwxh:0067=|

+

8.2 弱注释

+

只有在 // 后面才会被移除

// 代码中的注释弱不会被移除

+

9 列表

+

+

9.1 有序列表

+

  1. a
  2. b
  3. c
  4. d
-

9.2 无序列表

- +

+

9.2 无序列表klzzwxhklzzwxhklzzwxh:00800077- Cklzzwxh:0078- D

+

+

10 表格

+

@@ -273,19 +353,32 @@
+

11 警告

+

警告标题

警告内容

+

12 Emoji

+

🚴

这是一个笑脸😃图案

+

13 脚注

+

+

13.1 使用

+

这是一个1

+

13.2 定义

+

+

13.3 放置

+

+

通过一下代码可以将文章中所有的脚注定义集中于一处


    @@ -294,6 +387,9 @@
+

否则所有定义将被集中在文章末尾

+

14 扩展

+