Files
docs/inline_badges.py
2026-07-16 12:07:22 +08:00

86 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# https://github.com/squidfunk/mkdocs-material/blob/master/src/overrides/hooks/shortcodes.py
from __future__ import annotations
import re
import unicodedata
from html import escape
from markdown.extensions import Extension
from markdown.preprocessors import Preprocessor
SHORTCODE_RE = re.compile(r"<!--\s*md:(env|arg|config|version|default|beta)\s*(.*?)\s*-->", re.I)
# Страница с описанием конфигурации. Указана явно, потому что в проекте
# нет страницы `/iptvc/config` — соответствующий раздел живёт в
# `content/common/config/config.md`. С `use_directory_urls = false` конечные
# ссылки должны включать `.html`.
CONFIG_PAGE = "/common/config/config.html"
class BadgePreprocessor(Preprocessor):
def run(self, lines: list[str]) -> list[str]:
return [SHORTCODE_RE.sub(self._replace, line) for line in lines]
def _replace(self, match: re.Match[str]) -> str:
kind, args = match.groups()
args = args.strip()
if kind == "env":
value = args or "(нет)"
return _badge(":vscode-symbol-variable:", f"`{value}`", 'Переменная окружения')
if kind == "arg":
value = args or "(нет)"
return _badge(":vscode-terminal:", f"`{value}`", 'Аргумент командной строки')
if kind == "config":
value = args or "(нет)"
anchor = _slugify(args)
return _badge(":material-cog-outline:", f"[`{value}`]({CONFIG_PAGE}#{anchor})", 'Параметр файла конфигурации')
if kind == "version":
return _badge(":material-tag-outline:", escape(args), 'Версия, в которой появился этот функционал')
if kind == "default":
value = escape(args or "null")
return _badge(":material-water-outline:", f"`{value}`", 'Значение по умолчанию')
if kind == "beta":
return _badge(":material-beta:", '', 'Экспериментальный функционал')
return match.group(0)
# Slugify, совместимый с дефолтным slugify в pymdownx.slugs:
# NFKD-нормализация → отбрасывание не-ASCII → замена не-alphanumeric на дефис →
# склейка дефисов → trim → lowercase. Позволяет заранее предсказать якорь,
# не дожидаясь обработки Markdown
def _slugify(value: str) -> str:
if not value:
return ""
normalized = unicodedata.normalize("NFKD", value)
ascii_only = normalized.encode("ascii", "ignore").decode("ascii")
slug = re.sub(r"[^a-zA-Z0-9]+", "-", ascii_only)
return slug.strip("-").lower()
# Формирует HTML-разметку бейджа. Иконки остаются Zensical-шорткодами
# и рендерятся штатным `pymdownx.emoji` на следующем этапе обработки Markdown.
def _badge(icon: str, text: str = "", title: str = "") -> str:
return "".join([
f'<span class="mdx-badge" title="{title}">',
f'<span class="mdx-badge__icon">{icon}</span>',
*([f'<span class="mdx-badge__text">{text}</span>'] if text else []),
'</span>',
])
class InlineBadgeExtension(Extension):
def extendMarkdown(self, md):
md.preprocessors.register(BadgePreprocessor(md), "inline_badges", 175)
def makeExtension(**kwargs):
return InlineBadgeExtension(**kwargs)