Skip to content

Commit 8ad2f97

Browse files
committed
chatgpt rewrote the whole thing into single pass
1 parent a24cf32 commit 8ad2f97

File tree

2 files changed

+100
-118
lines changed

2 files changed

+100
-118
lines changed

scripts/doc8_redown.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
def new_setattr(self, name, value):
1313
if name == "_raw_content" and value is not None:
14-
value = redown(value.decode("utf-8").replace("\r", "")).encode("utf-8")
15-
# Path(self.filename).with_suffix(".rd").write_text(value.decode("utf-8"))
14+
value = redown(value.decode("utf-8").replace("\r", ""))[0].encode("utf-8")
15+
Path(self.filename).with_suffix(".rd").write_text(value.decode("utf-8"))
16+
1617
old_setattr(self, name, value)
1718

1819

source/_extensions/redown.py

Lines changed: 97 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
"""
1111

1212
import re
13-
1413
from pathlib import Path
1514
from sphinx.application import Sphinx
1615
from dataclasses import dataclass
1716

18-
1917
LINK_CORE = r"""
2018
\[ (?P<text>[^\[\]]*?) \] # link brackets + text w/o brackets - allows spaces in text
2119
\(
@@ -49,127 +47,110 @@
4947
re.VERBOSE, # whitespace and comments are ignored
5048
)
5149

52-
53-
def redown(text: str) -> str:
50+
def redown(text: str):
5451
"""21"""
55-
56-
# replace md code blocks with reST code blocks
57-
"redown, redown, redown, redown"
58-
find = r"(?P<start>^|\n)(?P<btindent> *?)(?P<ticks>```+)(?P<lang>\S+) *?(?:\n\s*?)+(?P<cindent> *?)(?P<code>.*?)(?P=ticks) *?(?P<end>\n|$|\Z)"
59-
60-
def replace(match: re.Match) -> str:
61-
start = match.group("start")
62-
btindent = match.group("btindent")
63-
lang: str = match.group("lang")
64-
cindent = match.group("cindent")
65-
code = match.group("code")
66-
end = match.group("end")
67-
68-
ret = ""
69-
ret += start
70-
ret += btindent + f".. code-block:: {lang}\n"
71-
cindent = 3 * " "
72-
73-
in_args = True
74-
75-
for line in code.splitlines(keepends=True):
76-
if in_args and re.search(r"^\s*:.+:", line) and not re.match(r"re?st", lang.lower()):
77-
ret += cindent + line
78-
continue
79-
elif in_args:
80-
in_args = False
81-
ret += "\n"
82-
83-
if line.strip() == "":
84-
ret += "\n"
52+
"""Transforms markdown-like syntax into reStructuredText and maps input to output line numbers."""
53+
input_lines = text.splitlines(keepends=True)
54+
output_lines = []
55+
line_mapping = [] # List of input line numbers for each output line
56+
i = 0 # Input line index
57+
while i < len(input_lines):
58+
line = input_lines[i]
59+
# Check for code block start
60+
code_block_match = re.match(r'^( *)(`{3,})(\S+)?\s*$', line)
61+
if code_block_match:
62+
# Start of code block
63+
btindent = code_block_match.group(1) or ''
64+
lang = code_block_match.group(3) or ''
65+
is_rst: bool = re.search(r"re?st", lang.lower()) is not None
66+
67+
params_lines = []
68+
params_input_line_numbers = []
69+
code_content_lines = []
70+
code_content_input_line_numbers = []
71+
i += 1
72+
while i < len(input_lines) and not re.match(r'^( *)`{3,}\s*$', input_lines[i]):
73+
code_line = input_lines[i]
74+
if not is_rst and not code_content_lines and re.match(r'^\s*:.*:', code_line):
75+
# Parameter line
76+
params_lines.append(code_line)
77+
params_input_line_numbers.append(i)
78+
else:
79+
# Code content line
80+
code_content_lines.append(code_line)
81+
code_content_input_line_numbers.append(i)
82+
i += 1
83+
if i < len(input_lines):
84+
# Closing ```
85+
i += 1
86+
# Now process the code block
87+
code_block_directive = f'{btindent}.. code-block::{" " + lang if lang else ""}\n'
88+
output_lines.append(code_block_directive)
89+
line_mapping.append(i - len(code_content_lines) - len(params_lines) - 1) # Map to the opening ```
90+
# Add parameter lines immediately after the directive (bug 3)
91+
option_indent = btindent + ' '
92+
for idx, param_line in enumerate(params_lines):
93+
output_lines.append(option_indent + param_line)
94+
line_mapping.append(params_input_line_numbers[idx])
95+
# Add a blank line before the code content
96+
output_lines.append('\n')
97+
if params_input_line_numbers:
98+
line_mapping.append(params_input_line_numbers[-1]) # Map to last param line
8599
else:
86-
ret += cindent + line
87-
88-
return ret
89-
90-
code = lambda: re.sub(find, replace, text, flags=re.DOTALL)
91-
text = code()
92-
93-
# find rst code block ranges
94-
"redown, redown, redown, redown"
95-
96-
@dataclass
97-
class Chunk:
98-
is_code: bool
99-
text: str = ""
100-
101-
chunks: list[Chunk] = []
102-
103-
for line in text.splitlines(keepends=True):
104-
in_code_block = chunks and chunks[-1].is_code
105-
is_code_block_directive = re.match(r"^\s*\.\. code-block::", line)
106-
107-
if not in_code_block and is_code_block_directive:
108-
chunks.append(Chunk(is_code=True))
109-
elif in_code_block:
110-
indent = len(re.match(r"^(\s*)", line).group(1).rstrip("\n"))
111-
code_block_indent = len(
112-
re.match(r"^(\s*)", chunks[-1].text).group(1).rstrip("\n")
113-
)
114-
if len(line.strip()) and indent <= code_block_indent:
115-
if is_code_block_directive:
116-
chunks.append(Chunk(is_code=True))
100+
line_mapping.append(i - len(code_content_lines) - 1) # Map to the opening ```
101+
# Add code content lines
102+
for idx, code_line in enumerate(code_content_lines):
103+
# Handle bug 2: Don't indent empty lines
104+
if code_line.strip():
105+
output_lines.append(' ' + code_line)
117106
else:
118-
chunks.append(Chunk(is_code=False))
119-
120-
if not chunks:
121-
chunks.append(Chunk(is_code=False))
122-
chunks[-1].text += line # existing block
123-
124-
# dont operate on code blocks
125-
for chunk in chunks:
126-
if chunk.is_code:
127-
continue
128-
text = chunk.text
129-
130-
"redown, redown, redown, redown"
131-
heading = lambda prefix, underfix: re.sub(
132-
rf"(^|\n){prefix} +(.+?)(?:$|\n|\Z)",
133-
lambda m: f"{m.group(1)}{m.group(2)}\n{underfix * len(m.group(2))}\n",
134-
text,
135-
)
136-
137-
text = heading("#", "=")
138-
text = heading("##", "-")
139-
text = heading("###", "^")
140-
text = heading("####", "~")
141-
142-
"redown, redown, redown, redown"
143-
role_links = lambda: ROLE_LINK_RE.sub(
144-
lambda m: f"{m.group('role')}`{(t:=m.group('text'))}{' ' if len(t) else ''}<{m.group('link')}>`",
145-
text,
146-
)
147-
text = role_links()
148-
149-
"redown, redown, redown, redown"
150-
links = lambda: LINK_RE.sub(
151-
lambda m: f"`{(t:=m.group('text'))}{' ' if len(t) else ''}<{m.group('link')}>`__",
152-
text,
153-
)
154-
text = links()
155-
156-
"redown, redown, redown, redown"
157-
math = lambda: re.sub(
158-
r"(\b|\s|^)\$([^$\n]+)\$(\b|\s|[^\w]|$)", r"\1:math:`\2`\3", text
159-
)
160-
text = math()
161-
162-
chunk.text = text
163-
164-
text = "".join(chunk.text for chunk in chunks)
165-
166-
return text
167-
107+
output_lines.append('\n')
108+
line_mapping.append(code_content_input_line_numbers[idx])
109+
# Add a blank line after the code content
110+
if code_content_lines:
111+
output_lines.append('\n')
112+
line_mapping.append(code_content_input_line_numbers[idx])
113+
else:
114+
# Process headings
115+
heading_match = re.match(r'^(#+) (.+)$', line)
116+
if heading_match:
117+
level = len(heading_match.group(1))
118+
heading_text = heading_match.group(2).strip()
119+
if level == 1:
120+
underline = '=' * len(heading_text)
121+
elif level == 2:
122+
underline = '-' * len(heading_text)
123+
elif level == 3:
124+
underline = '^' * len(heading_text)
125+
elif level == 4:
126+
underline = '~' * len(heading_text)
127+
else:
128+
underline = '"' * len(heading_text)
129+
output_lines.append(heading_text + '\n')
130+
line_mapping.append(i)
131+
output_lines.append(underline + '\n')
132+
line_mapping.extend([i, i]) # Underline and extra newline map to the same input line
133+
else:
134+
# Process role links, regular links, and inline math
135+
line_processed = ROLE_LINK_RE.sub(
136+
lambda m: f"{m.group('role')}`{(t:=m.group('text'))}{' ' if len(t) else ''}<{m.group('link')}>`",
137+
line)
138+
line_processed = LINK_RE.sub(
139+
lambda m: f"`{(t:=m.group('text'))}{' ' if len(t) else ''}<{m.group('link')}>`__",
140+
line_processed)
141+
line_processed = re.sub(
142+
r"(\b|\s|^)\$([^$\n]+)\$(\b|\s|[^\w]|$)", r"\1:math:`\2`\3", line_processed)
143+
output_lines.append(line_processed)
144+
line_mapping.append(i)
145+
i += 1
146+
output_text = ''.join(output_lines)
147+
return output_text, line_mapping
148+
"redown, redown, redown, redown"
168149

169150
def setup(app: Sphinx):
170151
@(lambda breadcrumb: app.connect("source-read", breadcrumb))
171152
def _(app, docname, content):
172-
content[0] = redown(content[0])
153+
content[0] = redown(content[0])[0]
173154
# Path(app.srcdir, docname).with_suffix(".rd").write_text(content[0], encoding="utf8")
174155

175156
return {

0 commit comments

Comments
 (0)