flowmark 0.4.0__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flowmark-0.4.0 → flowmark-0.4.2}/.copier-answers.yml +1 -1
- {flowmark-0.4.0 → flowmark-0.4.2}/.github/workflows/ci.yml +2 -1
- {flowmark-0.4.0 → flowmark-0.4.2}/.github/workflows/publish.yml +1 -1
- {flowmark-0.4.0 → flowmark-0.4.2}/Makefile +2 -1
- flowmark-0.4.0/README.md → flowmark-0.4.2/PKG-INFO +49 -4
- flowmark-0.4.0/PKG-INFO → flowmark-0.4.2/README.md +25 -19
- {flowmark-0.4.0 → flowmark-0.4.2}/devtools/lint.py +7 -3
- flowmark-0.4.2/installation.md +27 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/pyproject.toml +44 -7
- flowmark-0.4.2/src/flowmark/cleanups.py +76 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/cli.py +10 -0
- flowmark-0.4.0/src/flowmark/markdown_filling.py → flowmark-0.4.2/src/flowmark/custom_marko.py +76 -134
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/line_wrappers.py +4 -0
- flowmark-0.4.2/src/flowmark/markdown_filling.py +133 -0
- flowmark-0.4.2/src/flowmark/py.typed +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/text_wrapping.py +43 -2
- flowmark-0.4.2/tests/test_cleanups.py +62 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/test_ref_docs.py +8 -4
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/test_wrapping.py +93 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/testdocs/testdoc.orig.md +3 -0
- flowmark-0.4.2/tests/testdocs/testdoc.out.cleaned.md +943 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/testdocs/testdoc.out.plain.md +15 -14
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/testdocs/testdoc.out.semantic.md +19 -20
- {flowmark-0.4.0 → flowmark-0.4.2}/.gitignore +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/LICENSE +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/development.md +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/poetry.lock +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/publishing.md +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/__init__.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/frontmatter.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/sentence_split_regex.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/src/flowmark/text_filling.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/test_filling.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/test_frontmatter.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/tests/test_sentences.py +0 -0
- {flowmark-0.4.0 → flowmark-0.4.2}/uv.lock +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flowmark
|
|
3
|
+
Version: 0.4.2
|
|
4
|
+
Summary: Better line wrapping and formatting for plaintext and Markdown
|
|
5
|
+
Project-URL: Repository, https://github.com/jlevy/flowmark
|
|
6
|
+
Author-email: Joshua Levy <joshua@cal.berkeley.edu>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: <4.0,>=3.10
|
|
19
|
+
Requires-Dist: marko>=2.1.2
|
|
20
|
+
Requires-Dist: regex>=2024.11.6
|
|
21
|
+
Requires-Dist: strif>=2.0.0
|
|
22
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
1
25
|
# flowmark
|
|
2
26
|
|
|
3
27
|
Flowmark is a new Python implementation of **text and Markdown line wrapping and
|
|
@@ -129,8 +153,7 @@ experience.
|
|
|
129
153
|
Flowmark can be used as a library or as a CLI.
|
|
130
154
|
|
|
131
155
|
```
|
|
132
|
-
|
|
133
|
-
usage: flowmark [-h] [-o OUTPUT] [-w WIDTH] [-p] [-s] [-i] [--nobackup] [file]
|
|
156
|
+
usage: flowmark [-h] [-o OUTPUT] [-w WIDTH] [-p] [-s] [-i] [--nobackup] [--auto] [--version] [file]
|
|
134
157
|
|
|
135
158
|
Flowmark: Better line wrapping and formatting for plaintext and Markdown
|
|
136
159
|
|
|
@@ -142,9 +165,11 @@ options:
|
|
|
142
165
|
-o, --output OUTPUT Output file (use '-' for stdout)
|
|
143
166
|
-w, --width WIDTH Line width to wrap to
|
|
144
167
|
-p, --plaintext Process as plaintext (no Markdown parsing)
|
|
145
|
-
-s, --semantic Enable sentence-based line breaks (only applies to Markdown mode)
|
|
168
|
+
-s, --semantic Enable semantic (sentence-based) line breaks (only applies to Markdown mode)
|
|
146
169
|
-i, --inplace Edit the file in place (ignores --output)
|
|
147
170
|
--nobackup Do not make a backup of the original file when using --inplace
|
|
171
|
+
--auto Same as `--inplace --nobackup --semantic`, as a convenience for auto-formatting files
|
|
172
|
+
--version Show version information and exit
|
|
148
173
|
|
|
149
174
|
Flowmark provides enhanced text wrapping capabilities with special handling for
|
|
150
175
|
Markdown content. It can:
|
|
@@ -173,12 +198,32 @@ Command-line usage examples:
|
|
|
173
198
|
# Process plaintext instead of Markdown
|
|
174
199
|
flowmark --plaintext text.txt
|
|
175
200
|
|
|
176
|
-
# Use
|
|
201
|
+
# Use semantic line breaks (based on sentences, which is helpful to reduce
|
|
202
|
+
# irrelevant line wrap diffs in git history)
|
|
177
203
|
flowmark --semantic README.md
|
|
178
204
|
|
|
179
205
|
For more details, see: https://github.com/jlevy/flowmark
|
|
180
206
|
```
|
|
181
207
|
|
|
208
|
+
## Other Notes
|
|
209
|
+
|
|
210
|
+
- This enables
|
|
211
|
+
[GitHub-flavored Markdown support](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)
|
|
212
|
+
using
|
|
213
|
+
[Marko's extension](https://github.com/frostming/marko/blob/master/marko/ext/footnote.py).
|
|
214
|
+
|
|
215
|
+
- GFM-style tables are supported and also auto-formatted.
|
|
216
|
+
|
|
217
|
+
- GFM-style footnotes are supported.
|
|
218
|
+
But note these aren't actually in the GFM spec, but we follow
|
|
219
|
+
[micromark's conventions](https://github.com/frostming/marko/blob/master/marko/ext/footnote.py).
|
|
220
|
+
|
|
221
|
+
## Project Docs
|
|
222
|
+
|
|
223
|
+
For how to install uv and Python, see [installation.md](installation.md).
|
|
224
|
+
|
|
225
|
+
For development workflows, see [development.md](development.md).
|
|
226
|
+
|
|
182
227
|
For instructions on publishing to PyPI, see [publishing.md](publishing.md).
|
|
183
228
|
|
|
184
229
|
* * *
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: flowmark
|
|
3
|
-
Version: 0.4.0
|
|
4
|
-
Summary: Better line wrapping and formatting for plaintext and Markdown
|
|
5
|
-
Project-URL: Repository, https://github.com/jlevy/flowmark
|
|
6
|
-
Author-email: Joshua Levy <joshua@cal.berkeley.edu>
|
|
7
|
-
License-Expression: MIT
|
|
8
|
-
License-File: LICENSE
|
|
9
|
-
Requires-Python: <4.0,>=3.10
|
|
10
|
-
Requires-Dist: marko>=2.1.2
|
|
11
|
-
Requires-Dist: regex>=2024.11.6
|
|
12
|
-
Requires-Dist: strif>=2.0.0
|
|
13
|
-
Requires-Dist: typing-extensions>=4.12.2
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
|
|
16
1
|
# flowmark
|
|
17
2
|
|
|
18
3
|
Flowmark is a new Python implementation of **text and Markdown line wrapping and
|
|
@@ -144,8 +129,7 @@ experience.
|
|
|
144
129
|
Flowmark can be used as a library or as a CLI.
|
|
145
130
|
|
|
146
131
|
```
|
|
147
|
-
|
|
148
|
-
usage: flowmark [-h] [-o OUTPUT] [-w WIDTH] [-p] [-s] [-i] [--nobackup] [file]
|
|
132
|
+
usage: flowmark [-h] [-o OUTPUT] [-w WIDTH] [-p] [-s] [-i] [--nobackup] [--auto] [--version] [file]
|
|
149
133
|
|
|
150
134
|
Flowmark: Better line wrapping and formatting for plaintext and Markdown
|
|
151
135
|
|
|
@@ -157,9 +141,11 @@ options:
|
|
|
157
141
|
-o, --output OUTPUT Output file (use '-' for stdout)
|
|
158
142
|
-w, --width WIDTH Line width to wrap to
|
|
159
143
|
-p, --plaintext Process as plaintext (no Markdown parsing)
|
|
160
|
-
-s, --semantic Enable sentence-based line breaks (only applies to Markdown mode)
|
|
144
|
+
-s, --semantic Enable semantic (sentence-based) line breaks (only applies to Markdown mode)
|
|
161
145
|
-i, --inplace Edit the file in place (ignores --output)
|
|
162
146
|
--nobackup Do not make a backup of the original file when using --inplace
|
|
147
|
+
--auto Same as `--inplace --nobackup --semantic`, as a convenience for auto-formatting files
|
|
148
|
+
--version Show version information and exit
|
|
163
149
|
|
|
164
150
|
Flowmark provides enhanced text wrapping capabilities with special handling for
|
|
165
151
|
Markdown content. It can:
|
|
@@ -188,12 +174,32 @@ Command-line usage examples:
|
|
|
188
174
|
# Process plaintext instead of Markdown
|
|
189
175
|
flowmark --plaintext text.txt
|
|
190
176
|
|
|
191
|
-
# Use
|
|
177
|
+
# Use semantic line breaks (based on sentences, which is helpful to reduce
|
|
178
|
+
# irrelevant line wrap diffs in git history)
|
|
192
179
|
flowmark --semantic README.md
|
|
193
180
|
|
|
194
181
|
For more details, see: https://github.com/jlevy/flowmark
|
|
195
182
|
```
|
|
196
183
|
|
|
184
|
+
## Other Notes
|
|
185
|
+
|
|
186
|
+
- This enables
|
|
187
|
+
[GitHub-flavored Markdown support](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)
|
|
188
|
+
using
|
|
189
|
+
[Marko's extension](https://github.com/frostming/marko/blob/master/marko/ext/footnote.py).
|
|
190
|
+
|
|
191
|
+
- GFM-style tables are supported and also auto-formatted.
|
|
192
|
+
|
|
193
|
+
- GFM-style footnotes are supported.
|
|
194
|
+
But note these aren't actually in the GFM spec, but we follow
|
|
195
|
+
[micromark's conventions](https://github.com/frostming/marko/blob/master/marko/ext/footnote.py).
|
|
196
|
+
|
|
197
|
+
## Project Docs
|
|
198
|
+
|
|
199
|
+
For how to install uv and Python, see [installation.md](installation.md).
|
|
200
|
+
|
|
201
|
+
For development workflows, see [development.md](development.md).
|
|
202
|
+
|
|
197
203
|
For instructions on publishing to PyPI, see [publishing.md](publishing.md).
|
|
198
204
|
|
|
199
205
|
* * *
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import subprocess
|
|
2
2
|
|
|
3
3
|
from funlog import log_calls
|
|
4
|
+
from rich import get_console, reconfigure
|
|
4
5
|
from rich import print as rprint
|
|
5
6
|
|
|
6
7
|
# Update as needed.
|
|
@@ -8,6 +9,9 @@ SRC_PATHS = ["src", "tests", "devtools"]
|
|
|
8
9
|
DOC_PATHS = ["README.md"]
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
reconfigure(emoji=not get_console().options.legacy_windows) # No emojis on legacy windows.
|
|
13
|
+
|
|
14
|
+
|
|
11
15
|
def main():
|
|
12
16
|
rprint()
|
|
13
17
|
|
|
@@ -20,9 +24,9 @@ def main():
|
|
|
20
24
|
rprint()
|
|
21
25
|
|
|
22
26
|
if errcount != 0:
|
|
23
|
-
rprint(f"[bold red]
|
|
27
|
+
rprint(f"[bold red]:x: Lint failed with {errcount} errors.[/bold red]")
|
|
24
28
|
else:
|
|
25
|
-
rprint("[bold green]
|
|
29
|
+
rprint("[bold green]:white_check_mark: Lint passed![/bold green]")
|
|
26
30
|
rprint()
|
|
27
31
|
|
|
28
32
|
return errcount
|
|
@@ -31,7 +35,7 @@ def main():
|
|
|
31
35
|
@log_calls(level="warning", show_timing_only=True)
|
|
32
36
|
def run(cmd: list[str]) -> int:
|
|
33
37
|
rprint()
|
|
34
|
-
rprint(f"[bold green]
|
|
38
|
+
rprint(f"[bold green]:arrow_forward: {' '.join(cmd)}[/bold green]")
|
|
35
39
|
errcount = 0
|
|
36
40
|
try:
|
|
37
41
|
subprocess.run(cmd, text=True, check=True)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## Installing uv and Python
|
|
2
|
+
|
|
3
|
+
This project is set up to use [**uv**](https://docs.astral.sh/uv/), the new package
|
|
4
|
+
manager for Python. `uv` replaces traditional use of `pyenv`, `pipx`, `poetry`, `pip`,
|
|
5
|
+
etc. This is a quick cheat sheet on that:
|
|
6
|
+
|
|
7
|
+
On macOS or Linux, if you don't have `uv` installed, a quick way to install it:
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For macOS, you prefer [brew](https://brew.sh/) you can install or upgrade uv with:
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
brew update
|
|
17
|
+
brew install uv
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
See [uv's docs](https://docs.astral.sh/uv/getting-started/installation/) for more
|
|
21
|
+
installation methods and platforms.
|
|
22
|
+
|
|
23
|
+
Now you can use uv to install a current Python environment:
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
uv python install 3.13 # Or pick another version.
|
|
27
|
+
```
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[project.urls]
|
|
4
4
|
Repository = "https://github.com/jlevy/flowmark"
|
|
5
5
|
# Homepage = "https://..."
|
|
6
|
+
# Documentation = "https://..."
|
|
6
7
|
|
|
7
8
|
[project]
|
|
8
9
|
name = "flowmark"
|
|
@@ -15,6 +16,24 @@ license = "MIT"
|
|
|
15
16
|
requires-python = ">=3.10,<4.0"
|
|
16
17
|
dynamic = ["version"]
|
|
17
18
|
|
|
19
|
+
# https://pypi.org/classifiers/
|
|
20
|
+
# Adjust as needed:
|
|
21
|
+
classifiers = [
|
|
22
|
+
# Adjust as needed:
|
|
23
|
+
"Development Status :: 4 - Beta",
|
|
24
|
+
# "Development Status :: 5 - Production/Stable",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
"Programming Language :: Python",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Typing :: Typed",
|
|
33
|
+
# Include this to avoid accidentally publishing to PyPI:
|
|
34
|
+
# "Private :: Do Not Upload",
|
|
35
|
+
]
|
|
36
|
+
|
|
18
37
|
dependencies = [
|
|
19
38
|
"marko>=2.1.2",
|
|
20
39
|
"regex>=2024.11.6",
|
|
@@ -22,6 +41,7 @@ dependencies = [
|
|
|
22
41
|
"typing-extensions>=4.12.2",
|
|
23
42
|
]
|
|
24
43
|
|
|
44
|
+
|
|
25
45
|
[dependency-groups]
|
|
26
46
|
dev = [
|
|
27
47
|
"pytest>=8.3.5",
|
|
@@ -38,6 +58,7 @@ dev = [
|
|
|
38
58
|
flowmark = "flowmark.cli:main"
|
|
39
59
|
|
|
40
60
|
|
|
61
|
+
|
|
41
62
|
# ---- Build system ----
|
|
42
63
|
|
|
43
64
|
# Dynamic versioning from:
|
|
@@ -58,6 +79,11 @@ vcs = "git"
|
|
|
58
79
|
style = "pep440"
|
|
59
80
|
bump = "true"
|
|
60
81
|
|
|
82
|
+
[tool.hatch.build.targets.wheel]
|
|
83
|
+
# The source location for the package.
|
|
84
|
+
packages = ["src/flowmark"]
|
|
85
|
+
|
|
86
|
+
|
|
61
87
|
# ---- Settings ----
|
|
62
88
|
|
|
63
89
|
[tool.ruff]
|
|
@@ -65,8 +91,8 @@ bump = "true"
|
|
|
65
91
|
line-length = 100
|
|
66
92
|
|
|
67
93
|
[tool.ruff.lint]
|
|
68
|
-
# See: https://docs.astral.sh/ruff/rules/
|
|
69
94
|
select = [
|
|
95
|
+
# See: https://docs.astral.sh/ruff/rules/
|
|
70
96
|
# Basic list from: https://docs.astral.sh/ruff/linter/#rule-selection
|
|
71
97
|
"E", # https://docs.astral.sh/ruff/rules/#error-e
|
|
72
98
|
"F", # https://docs.astral.sh/ruff/rules/#pyflakes-f
|
|
@@ -81,6 +107,7 @@ select = [
|
|
|
81
107
|
|
|
82
108
|
]
|
|
83
109
|
ignore = [
|
|
110
|
+
# Disable some rules that are overly pedantic. Add/remove as desired:
|
|
84
111
|
"E501", # https://docs.astral.sh/ruff/rules/line-too-long/
|
|
85
112
|
"E402", # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file/
|
|
86
113
|
"E731", # https://docs.astral.sh/ruff/rules/lambda-assignment/
|
|
@@ -101,28 +128,38 @@ ignore = [
|
|
|
101
128
|
"ISC002", # https://docs.astral.sh/ruff/rules/multi-line-implicit-string-concatenation/
|
|
102
129
|
]
|
|
103
130
|
|
|
131
|
+
[tool.basedpyright]
|
|
104
132
|
# BasedPyright currently seems like the best type checker option, much faster
|
|
105
133
|
# than mypy and with a good extension for VSCode/Cursor.
|
|
106
134
|
# https://marketplace.visualstudio.com/items?itemName=detachhead.basedpyright
|
|
107
135
|
# https://docs.basedpyright.com/latest/configuration/config-files/#sample-pyprojecttoml-file
|
|
108
|
-
[tool.basedpyright]
|
|
109
136
|
include = ["src", "tests", "devtools"]
|
|
110
|
-
|
|
137
|
+
|
|
138
|
+
# By default BasedPyright is very strict, so you almost certainly want to disable
|
|
139
|
+
# some of the rules.
|
|
140
|
+
# First, these turn off warnings about (yes) how you ignore warnings:
|
|
111
141
|
reportIgnoreCommentWithoutRule = false
|
|
112
142
|
reportUnnecessaryTypeIgnoreComment = false
|
|
113
|
-
#
|
|
143
|
+
# A few typically noisy warnings are next.
|
|
144
|
+
# How many you enable is up to you. The first few are off by default, but you can
|
|
145
|
+
# comment/uncomment these as desired:
|
|
114
146
|
reportMissingTypeStubs = false
|
|
115
147
|
reportUnusedCallResult = false
|
|
148
|
+
reportAny = false
|
|
149
|
+
reportExplicitAny = false
|
|
150
|
+
reportImplicitStringConcatenation = false
|
|
151
|
+
# reportUnreachable = false
|
|
152
|
+
# reportUnusedParameter = false
|
|
153
|
+
# reportPrivateImportUsage = false
|
|
154
|
+
# reportPrivateLocalImportUsage = false
|
|
116
155
|
# reportMissingImports = false
|
|
117
156
|
# reportUnnecessaryIsInstance = false
|
|
118
157
|
# reportUnreachable = false
|
|
119
|
-
reportAny = false
|
|
120
|
-
reportExplicitAny = false
|
|
121
|
-
reportUnusedParameter = false
|
|
122
158
|
# reportUnknownVariableType = false
|
|
123
159
|
# reportUnknownArgumentType = false
|
|
124
160
|
|
|
125
161
|
[tool.codespell]
|
|
162
|
+
# Add here as needed:
|
|
126
163
|
# ignore-words-list = "foo,bar"
|
|
127
164
|
skip = "tests/testdocs/*.md"
|
|
128
165
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
|
|
5
|
+
from marko import block, inline
|
|
6
|
+
from marko.block import Document
|
|
7
|
+
from marko.element import Element
|
|
8
|
+
|
|
9
|
+
ContainerElement = (
|
|
10
|
+
block.Document,
|
|
11
|
+
block.Quote,
|
|
12
|
+
block.List,
|
|
13
|
+
block.ListItem,
|
|
14
|
+
block.Paragraph, # Paragraphs contain inline elements
|
|
15
|
+
block.Heading, # Already handled, but include for completeness if structure changes
|
|
16
|
+
inline.Emphasis,
|
|
17
|
+
inline.StrongEmphasis,
|
|
18
|
+
inline.Link,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def transform_tree(element: Element, transformer: Callable[[Element], None]) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Recursively traverse the element tree and apply a transformer function to each node.
|
|
25
|
+
"""
|
|
26
|
+
transformer(element)
|
|
27
|
+
|
|
28
|
+
# Recursively process children for known container types
|
|
29
|
+
if isinstance(element, ContainerElement):
|
|
30
|
+
# Now we know element has a .children attribute that's a Sequence[Element] or str
|
|
31
|
+
# We only care about processing Element children
|
|
32
|
+
if isinstance(element.children, list):
|
|
33
|
+
# Create a copy for safe iteration if modification occurs
|
|
34
|
+
current_children = list(element.children)
|
|
35
|
+
for child in current_children:
|
|
36
|
+
transform_tree(child, transformer)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _unbold_heading_transformer(element: Element) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Transformer function to unbold headings where the entire text is bold.
|
|
42
|
+
"""
|
|
43
|
+
if isinstance(element, block.Heading):
|
|
44
|
+
# Check if the heading consists *only* of a single StrongEmphasis element
|
|
45
|
+
if len(element.children) == 1 and isinstance(element.children[0], inline.StrongEmphasis):
|
|
46
|
+
# Replace the heading's children with the children of the StrongEmphasis element
|
|
47
|
+
strong_emphasis_node = element.children[0]
|
|
48
|
+
# Type checker struggles here, but StrongEmphasis children should be Elements.
|
|
49
|
+
element.children = strong_emphasis_node.children # pyright: ignore
|
|
50
|
+
|
|
51
|
+
# Handle the case where the heading is bold and italic (StrongEmphasis inside Emphasis or vice versa)
|
|
52
|
+
# ***text*** -> *text*
|
|
53
|
+
elif len(element.children) == 1 and isinstance(element.children[0], inline.Emphasis):
|
|
54
|
+
emphasis_node = element.children[0]
|
|
55
|
+
if len(emphasis_node.children) == 1 and isinstance(
|
|
56
|
+
emphasis_node.children[0], inline.StrongEmphasis
|
|
57
|
+
):
|
|
58
|
+
strong_node = emphasis_node.children[0]
|
|
59
|
+
emphasis_node.children = strong_node.children
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def unbold_headings(doc: Document) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Find headings where the entire text is bold and remove the bold.
|
|
65
|
+
|
|
66
|
+
Modifies the Marko document tree in place using a general transformer.
|
|
67
|
+
Example: `## **My Heading**` -> `## My Heading`
|
|
68
|
+
"""
|
|
69
|
+
transform_tree(doc, _unbold_heading_transformer)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def doc_cleanups(doc: Document):
|
|
73
|
+
"""
|
|
74
|
+
Apply (ideally quite safe) cleanups to the document.
|
|
75
|
+
"""
|
|
76
|
+
unbold_headings(doc)
|
|
@@ -55,6 +55,7 @@ class Options:
|
|
|
55
55
|
width: int
|
|
56
56
|
plaintext: bool
|
|
57
57
|
semantic: bool
|
|
58
|
+
cleanups: bool
|
|
58
59
|
inplace: bool
|
|
59
60
|
nobackup: bool
|
|
60
61
|
version: bool
|
|
@@ -98,6 +99,13 @@ def _parse_args(args: list[str] | None = None) -> Options:
|
|
|
98
99
|
default=False,
|
|
99
100
|
help="Enable semantic (sentence-based) line breaks (only applies to Markdown mode)",
|
|
100
101
|
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"-c",
|
|
104
|
+
"--cleanups",
|
|
105
|
+
action="store_true",
|
|
106
|
+
default=False,
|
|
107
|
+
help="Enable (safe) cleanups for common issues (only applies to Markdown mode)",
|
|
108
|
+
)
|
|
101
109
|
parser.add_argument(
|
|
102
110
|
"-i", "--inplace", action="store_true", help="Edit the file in place (ignores --output)"
|
|
103
111
|
)
|
|
@@ -129,6 +137,7 @@ def _parse_args(args: list[str] | None = None) -> Options:
|
|
|
129
137
|
width=opts.width,
|
|
130
138
|
plaintext=opts.plaintext,
|
|
131
139
|
semantic=opts.semantic,
|
|
140
|
+
cleanups=opts.cleanups,
|
|
132
141
|
inplace=opts.inplace,
|
|
133
142
|
nobackup=opts.nobackup,
|
|
134
143
|
version=opts.version,
|
|
@@ -177,6 +186,7 @@ def main(args: list[str] | None = None) -> int:
|
|
|
177
186
|
text,
|
|
178
187
|
width=options.width,
|
|
179
188
|
semantic=options.semantic,
|
|
189
|
+
cleanups=options.cleanups,
|
|
180
190
|
dedent_input=True,
|
|
181
191
|
)
|
|
182
192
|
|