Skip to content

Commit e0dc45c

Browse files
Add superscript plugin
Plugin ported from https://github.com/markdown-it/markdown-it-sup
1 parent 93fbf64 commit e0dc45c

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Superscript tag plugin, ported from Markdown-It."""
2+
3+
from .index import superscript_plugin
4+
5+
__all__ = ("superscript_plugin",)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""Superscript tag plugin.
2+
3+
Ported by Elijah Greenstein from https://github.com/markdown-it/markdown-it-sup
4+
cf. Subscript tag plugin, https://mdit-py-plugins.readthedocs.io/en/latest/#subscripts
5+
6+
MIT License
7+
Copyright (c) 2014-2015 Vitaly Puzrin, Alex Kocharin.
8+
9+
Permission is hereby granted, free of charge, to any person
10+
obtaining a copy of this software and associated documentation
11+
files (the "Software"), to deal in the Software without
12+
restriction, including without limitation the rights to use,
13+
copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
copies of the Software, and to permit persons to whom the
15+
Software is furnished to do so, subject to the following
16+
conditions:
17+
18+
The above copyright notice and this permission notice shall be
19+
included in all copies or substantial portions of the Software.
20+
21+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28+
OTHER DEALINGS IN THE SOFTWARE.
29+
from __future__ import annotations
30+
"""
31+
32+
from collections.abc import Sequence
33+
import re
34+
from typing import TYPE_CHECKING
35+
36+
from markdown_it import MarkdownIt
37+
from markdown_it.rules_inline import StateInline
38+
39+
40+
UNESCAPE_RE = re.compile(r"\\([ \\!\"#$%&'()*+,./:;<=>?@[\]^_`{|}~-])")
41+
WHITESPACE_RE = re.compile(r"(^|[^\\])(\\\\)*\s")
42+
43+
44+
def superscript_plugin(md: MarkdownIt) -> None:
45+
"""Superscript (``<sup>``) tag plugin for Markdown-It-Py.
46+
47+
This plugin is ported from `markdown-it-sup <https://github.com/markdown-it/markdown-it-sup>`_. Markup is based on the `Pandoc superscript extension <https://pandoc.org/MANUAL.html#superscripts-and-subscripts>`_.
48+
49+
Surround superscripted text with caret ``^`` characters. Superscripted text cannot contain whitespace characters. Nested markup is not supported.
50+
51+
Example usage:
52+
53+
>>> from markdown_it import MarkdownIt
54+
>>> from mdit_py_plugins.superscript import superscript_plugin
55+
>>> md = MarkdownIt().use(superscript_plugin)
56+
>>> md.render("1^st^")
57+
'<p>1<sup>st</sup></p>\\n'
58+
>>> md.render("2^nd^")
59+
'<p>2<sup>nd</sup></p>\\n'
60+
"""
61+
62+
def superscript(state: StateInline, silent: bool) -> bool:
63+
"""Parse inline text for superscripted text between caret ``^`` characters."""
64+
maximum = state.posMax
65+
start = state.pos
66+
67+
if ord(state.src[start]) != 0x5E: # Check if char is `^`
68+
return False
69+
if silent: # Do not run any pairs in validation mode
70+
return False
71+
if start + 2 >= maximum:
72+
return False
73+
74+
state.pos = start + 1
75+
found = False
76+
77+
while state.pos < maximum:
78+
if ord(state.src[state.pos]) == 0x5E: # Check if char is `^`
79+
found = True
80+
break
81+
state.md.inline.skipToken(state)
82+
83+
if (not found) or (start + 1 == state.pos):
84+
state.pos = start
85+
return False
86+
87+
content = state.src[start + 1 : state.pos]
88+
89+
# Do not allow unescaped spaces/newlines inside
90+
if WHITESPACE_RE.search(content) is not None:
91+
state.pos = start
92+
return False
93+
94+
# Found!
95+
state.posMax = state.pos
96+
state.pos = start + 1
97+
98+
# Earlier we checked !silent, but this implementation does not need it
99+
token_so = state.push("sup_open", "sup", 1)
100+
token_so.markup = "^"
101+
102+
token_t = state.push("text", "", 0)
103+
token_t.content = UNESCAPE_RE.sub(r"\1", content)
104+
105+
token_sc = state.push("sup_close", "sup", -1)
106+
token_sc.markup = "^"
107+
108+
state.pos = state.posMax + 1
109+
state.posMax = maximum
110+
return True
111+
112+
md.inline.ruler.after("emphasis", "sup", superscript)

0 commit comments

Comments
 (0)