Skip to content

Commit 0f3031a

Browse files
committed
implement strikethrough
1 parent 50b23ad commit 0f3031a

File tree

6 files changed

+148
-135
lines changed

6 files changed

+148
-135
lines changed

markdown_it/parser_inline.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
["newline", rules_inline.newline],
1414
["escape", rules_inline.escape],
1515
["backticks", rules_inline.backtick],
16-
# [ 'strikethrough', require('./rules_inline/strikethrough').tokenize ],
16+
["strikethrough", rules_inline.strikethrough.tokenize],
1717
["emphasis", rules_inline.emphasis.tokenize],
1818
["link", rules_inline.link],
1919
["image", rules_inline.image],
@@ -24,7 +24,7 @@
2424

2525
_rules2 = [
2626
["balance_pairs", rules_inline.link_pairs],
27-
# [ 'strikethrough', require('./rules_inline/strikethrough').postProcess ],
27+
["strikethrough", rules_inline.strikethrough.postProcess],
2828
["emphasis", rules_inline.emphasis.postProcess],
2929
["text_collapse", rules_inline.text_collapse],
3030
]

markdown_it/rules_inline/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@
1111
from .autolink import autolink # noqa: F401
1212
from .entity import entity # noqa: F401
1313
from .html_inline import html_inline # noqa: F401
14+
from . import strikethrough # noqa: F401

markdown_it/rules_inline/strikethrough.js

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# ~~strike through~~
2+
from typing import List
3+
from .state_inline import StateInline, Delimiter
4+
from ..common.utils import charCodeAt
5+
6+
7+
def tokenize(state: StateInline, silent: bool):
8+
"""Insert each marker as a separate text token, and add it to delimiter list"""
9+
start = state.pos
10+
marker = charCodeAt(state.src, start)
11+
12+
if silent:
13+
return False
14+
15+
if marker != 0x7E: # /* ~ */
16+
return False
17+
18+
scanned = state.scanDelims(state.pos, True)
19+
length = scanned.length
20+
ch = chr(marker)
21+
22+
if length < 2:
23+
return False
24+
25+
if length % 2:
26+
token = state.push("text", "", 0)
27+
token.content = ch
28+
length -= 1
29+
30+
i = 0
31+
while i < length:
32+
token = state.push("text", "", 0)
33+
token.content = ch + ch
34+
state.delimiters.append(
35+
Delimiter(
36+
**{
37+
"marker": marker,
38+
"length": 0, # disable "rule of 3" length checks meant for emphasis
39+
"jump": i,
40+
"token": len(state.tokens) - 1,
41+
"end": -1,
42+
"open": scanned.can_open,
43+
"close": scanned.can_close,
44+
}
45+
)
46+
)
47+
48+
i += 2
49+
50+
state.pos += scanned.length
51+
52+
return True
53+
54+
55+
def _postProcess(state: StateInline, delimiters: List[Delimiter]):
56+
57+
loneMarkers = []
58+
maximum = len(delimiters)
59+
60+
i = 0
61+
while i < maximum:
62+
startDelim = delimiters[i]
63+
64+
if startDelim.marker != 0x7E: # /* ~ */
65+
i += 1
66+
continue
67+
68+
if startDelim.end == -1:
69+
i += 1
70+
continue
71+
72+
endDelim = delimiters[startDelim.end]
73+
74+
token = state.tokens[startDelim.token]
75+
token.type = "s_open"
76+
token.tag = "s"
77+
token.nesting = 1
78+
token.markup = "~~"
79+
token.content = ""
80+
81+
token = state.tokens[endDelim.token]
82+
token.type = "s_close"
83+
token.tag = "s"
84+
token.nesting = -1
85+
token.markup = "~~"
86+
token.content = ""
87+
88+
if (
89+
state.tokens[endDelim.token - 1].type == "text"
90+
and state.tokens[endDelim.token - 1].content == "~"
91+
):
92+
93+
loneMarkers.append(endDelim.token - 1)
94+
95+
i += 1
96+
97+
# If a marker sequence has an odd number of characters, it's splitted
98+
# like this: `~~~~~` -> `~` + `~~` + `~~`, leaving one marker at the
99+
# start of the sequence.
100+
#
101+
# So, we have to move all those markers after subsequent s_close tags.
102+
#
103+
while loneMarkers:
104+
i = loneMarkers.pop()
105+
j = i + 1
106+
107+
while (j < len(state.tokens)) and (state.tokens[j].type == "s_close"):
108+
j += 1
109+
110+
j -= 1
111+
112+
if i != j:
113+
token = state.tokens[j]
114+
state.tokens[j] = state.tokens[i]
115+
state.tokens[i] = token
116+
117+
118+
def postProcess(state: StateInline):
119+
"""Walk through delimiter list and replace text tokens with tags."""
120+
tokens_meta = state.tokens_meta
121+
maximum = len(state.tokens_meta)
122+
_postProcess(state, state.delimiters)
123+
124+
curr = 0
125+
while curr < maximum:
126+
try:
127+
tokens_meta[curr]
128+
except IndexError:
129+
pass
130+
else:
131+
if tokens_meta[curr] and "delimiters" in tokens_meta[curr]:
132+
_postProcess(state, tokens_meta[curr]["delimiters"])
133+
curr += 1

tests/test_port/fixtures/strikethrough.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ From CommonMark test suite, replacing `**` with our marker:
118118
.
119119
a~~"foo"~~
120120
.
121-
<p>a~~foo~~</p>
121+
<p>a~~&quot;foo&quot;~~</p>
122122
.
123123

124124
Coverage: single tilde

tests/test_port/test_fixtures.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"line,title,input,expected", read_fixture_file(FIXTURE_PATH.joinpath("tables.md"))
1313
)
1414
def test_title(line, title, input, expected):
15-
md = MarkdownIt("working")
15+
md = MarkdownIt().enable("table")
1616
text = md.render(input)
1717
assert text.rstrip() == expected.rstrip()
1818

@@ -40,3 +40,13 @@ def test_fatal(line, title, input, expected):
4040
md = MarkdownIt("commonmark")
4141
text = md.render(input)
4242
assert text.rstrip() == expected.rstrip()
43+
44+
45+
@pytest.mark.parametrize(
46+
"line,title,input,expected",
47+
read_fixture_file(FIXTURE_PATH.joinpath("strikethrough.md")),
48+
)
49+
def test_strikethrough(line, title, input, expected):
50+
md = MarkdownIt().enable("strikethrough")
51+
text = md.render(input)
52+
assert text.rstrip() == expected.rstrip()

0 commit comments

Comments
 (0)