From b40fbabbada2827140599ce54c55473fb0ff151f Mon Sep 17 00:00:00 2001 From: CyC2018 Date: Thu, 29 Oct 2026 04:54:25 +0800 Subject: [PATCH] Update site_assets.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 计算标题 id 时先按 marked 的规则转义引号等字符,与浏览器中生成的 id 一致,站内搜索的结果能定位到这类标题。 --- website/builder/site_assets.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/website/builder/site_assets.py b/website/builder/site_assets.py index b68af64c..49e5a818 100644 --- a/website/builder/site_assets.py +++ b/website/builder/site_assets.py @@ -29,9 +29,30 @@ def plain_text(text): return re.sub(r'\s+', ' ', html.unescape(text)).strip() +def marked_inline(title): + # Docsify slugs the HTML that marked renders for the heading: backslash escapes are + # resolved, code spans and link text are kept, and text is HTML-escaped, so a quote + # becomes " and leaves "quot" in the slug. + def escape(text): + text = re.sub(r'&(?!#?\w+;)', '&', text) + return text.replace('<', '<').replace('>', '>').replace('"', '"').replace("'", ''') + out = [] + for part in re.split(r'(`+[^`]*`+|<\/?[A-Za-z][^>]*>)', title): + if part.startswith('`'): + out.append(escape(part.strip('`'))) + elif part.startswith('<'): + out.append(part) + else: + part = re.sub(r'!?\[([^\]]*)\]\([^)]*\)', r'\1', part) + part = re.sub(r'\\([!-/:-@\[-`{-~])', r'\1', part) + out.append(escape(part.replace('**', '').replace('__', ''))) + return ''.join(out) + + def heading_slug(title, counts): # Match the pinned Docsify 4.13.1 slugger, including numeric and duplicate headings. title = title.replace('{docsify-ignore}', '').replace('{docsify-ignore-all}', '') + title = marked_inline(title) slug = PUNCTUATION.sub('', re.sub(r'<[^>]+>', '', title.strip()).lower()) slug = re.sub(r'-+', '-', re.sub(r'\s', '-', slug)) slug = re.sub(r'^(\d)', r'_\1', slug)