add markdown module

This commit is contained in:
Yusur 2025-06-11 14:38:22 +02:00
parent 38eac17109
commit d6e54f192f
5 changed files with 99 additions and 7 deletions

View file

@ -2,10 +2,13 @@
## 0.3.0 ## 0.3.0
- Add auth loaders i.e. `sqlalchemy.require_auth_base()`, `flask_sqlalchemy` - Add SQLAlchemy auth loaders i.e. `sqlalchemy.require_auth_base()`, `flask_sqlalchemy`.
What auth loaders do is loading user token and signature into app
- Implement `UserSigner()`
- Improve JSON handling in `flask_restx` - Improve JSON handling in `flask_restx`
- Add base2048 (i.e. BIP-39) codec - Add base2048 (i.e. [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)) codec
- Add `split_bits()` and `join_bits()` - Add `split_bits()`, `join_bits()`, `ltuple()`, `rtuple()`
- Add `markdown` extensions
## 0.2.3 ## 0.2.3

View file

@ -44,7 +44,9 @@ flask_sqlalchemy = [
peewee = [ peewee = [
"peewee>=3.0.0, <4.0" "peewee>=3.0.0, <4.0"
] ]
markdown = [
"markdown>=3.0.0"
]
[tool.setuptools.dynamic] [tool.setuptools.dynamic]
version = { attr = "suou.__version__" } version = { attr = "suou.__version__" }

View file

@ -25,7 +25,7 @@ from .classtools import Wanted, Incomplete
from .itertools import makelist, kwargs_prefix, ltuple, rtuple from .itertools import makelist, kwargs_prefix, ltuple, rtuple
from .i18n import I18n, JsonI18n, TomlI18n from .i18n import I18n, JsonI18n, TomlI18n
__version__ = "0.3.0-dev21" __version__ = "0.3.0-dev22"
__all__ = ( __all__ = (
'Siq', 'SiqCache', 'SiqType', 'SiqGen', 'StringCase', 'Siq', 'SiqCache', 'SiqType', 'SiqGen', 'StringCase',

View file

@ -50,8 +50,6 @@ def count_ones(n: int) -> int:
def split_bits(buf: bytes, nbits: int) -> list[int]: def split_bits(buf: bytes, nbits: int) -> list[int]:
''' '''
Split a bytestring into chunks of equal size, and interpret each chunk as an unsigned integer. Split a bytestring into chunks of equal size, and interpret each chunk as an unsigned integer.
XXX DOES NOT WORK DO NOT USE!!!!!!!!
''' '''
mem = memoryview(buf) mem = memoryview(buf)
chunk_size = nbits // math.gcd(nbits, 8) chunk_size = nbits // math.gcd(nbits, 8)

89
src/suou/markdown.py Normal file
View file

@ -0,0 +1,89 @@
"""
Plugins for markdown.
---
Copyright (c) 2025 Sakuragasaki46.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
See LICENSE for the specific language governing permissions and
limitations under the License.
This software is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import re
import markdown
from markdown.inlinepatterns import InlineProcessor, SimpleTagInlineProcessor
import xml.etree.ElementTree as etree
class StrikethroughExtension(markdown.extensions.Extension):
"""
Turn ~~crossed out~~ (with double tilde) text into HTML strikethrough
well, markdown-strikethrough is a trivial dependency lol
"""
def extendMarkdown(self, md: markdown.Markdown, md_globals=None):
postprocessor = StrikethroughPostprocessor(md)
md.postprocessors.register(postprocessor, 'strikethrough', 0)
class StrikethroughPostprocessor(markdown.postprocessors.Postprocessor):
PATTERN = re.compile(r"~~(((?!~~).)+)~~", re.DOTALL)
def run(self, html):
return re.sub(self.PATTERN, self.convert, html)
def convert(self, match: re.Match):
return '<del>' + match.group(1) + '</del>'
class SpoilerExtension(markdown.extensions.Extension):
"""
Add spoiler tags to text, using >!Reddit syntax!<.
XXX remember to call SpoilerExtension.patch_blockquote_processor()
to clear conflicts with the blockquote processor and allow
spoiler tags to start at beginning of line.
"""
def extendMarkdown(self, md: markdown.Markdown, md_globals=None):
md.inlinePatterns.register(SimpleTagInlineProcessor(r'()>!(.*?)!<', 'span class="spoiler"'), 'spoiler', 14)
@classmethod
def patch_blockquote_processor(cls):
"""Patch BlockquoteProcessor to make Spoiler prevail over blockquotes."""
from markdown.blockprocessors import BlockQuoteProcessor
BlockQuoteProcessor.RE = re.compile(r'(^|\n)[ ]{0,3}>(?!!)[ ]?(.*)')
class MentionPattern(InlineProcessor):
def __init__(self, regex, url_prefix: str):
super().__init__(regex)
self.url_prefix = url_prefix
def handleMatch(self, m, data):
el = etree.Element('a')
el.attrib['href'] = self.url_prefix + m.group(1)
el.text = m.group(0)
return el, m.start(0), m.end(0)
class PingExtension(markdown.extensions.Extension):
"""
Convert @mentions into profile links.
Customizable by passing a dict as mappings= argument, where
the key is the first character, and the value is the URL prefix.
"""
mappings: dict[str, str]
DEFAULT_MAPPINGS = {'@': '/@'}
CHARACTERS = r'[a-zA-Z0-9_-]{2,32}'
def __init__(self, /, mappings: dict | None = None, **kwargs):
super().__init__(**kwargs)
self.mappings = mappings or self.DEFAULT_MAPPINGS.copy()
def extendMarkdown(self, md: markdown.Markdown, md_globals=None):
for at, url_prefix in self.mappings.items():
md.inlinePatterns.register(MentionPattern(re.escape(at) + r'(' + self.CHARACTERS + ')', url_prefix), 'ping_mention', 14)
__all__ = ('PingExtension', 'SpoilerExtension', 'StrikethroughExtension')