ctrl-kd 4.0.0__tar.gz → 4.5.0__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.
- ctrl_kd-4.5.0/PKG-INFO +106 -0
- ctrl_kd-4.5.0/README.md +87 -0
- ctrl_kd-4.5.0/pyproject.toml +61 -0
- ctrl_kd-4.5.0/src/ctrl_kd.egg-info/PKG-INFO +106 -0
- ctrl_kd-4.5.0/src/ctrl_kd.egg-info/SOURCES.txt +63 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/__init__.py +1 -1
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/cli.py +150 -6
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/core.py +1642 -92
- ctrl_kd-4.5.0/src/ctrlkd/emit.py +3002 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/fontmap.py +98 -8
- ctrl_kd-4.5.0/src/ctrlkd/info.py +176 -0
- ctrl_kd-4.5.0/src/ctrlkd/layout.py +652 -0
- ctrl_kd-4.5.0/src/ctrlkd/pdf.py +5700 -0
- ctrl_kd-4.5.0/src/ctrlkd/pictures.py +180 -0
- ctrl_kd-4.5.0/src/ctrlkd/pix.py +600 -0
- ctrl_kd-4.5.0/src/ctrlkd/piximg.py +194 -0
- ctrl_kd-4.5.0/src/ctrlkd/samples/LYING.WS +0 -0
- ctrl_kd-4.5.0/src/ctrlkd/samples/OCAPTAIN.WS +38 -0
- ctrl_kd-4.5.0/src/ctrlkd/samples/TWAINLET.WS +56 -0
- ctrl_kd-4.5.0/src/ctrlkd/samples/WARPRAYR.WS +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/wschange.py +1 -2
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/tests/test_ctrlkd.py +1826 -98
- ctrl_kd-4.5.0/tests/test_endnote_leading_gap.py +107 -0
- ctrl_kd-4.5.0/tests/test_fidelity_gate.py +231 -0
- ctrl_kd-4.5.0/tests/test_flags_toc_inline.py +307 -0
- ctrl_kd-4.5.0/tests/test_glyph_aspect.py +186 -0
- ctrl_kd-4.5.0/tests/test_layout_marks.py +221 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_bullet_glyph.py +79 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_char_substitution.py +184 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_colour_restore.py +77 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_heading_face.py +276 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_hp_patterns.py +115 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_legend_line_spacing.py +68 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_pcl_rectangles.py +221 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_shading_table_rules.py +73 -0
- ctrl_kd-4.5.0/tests/test_lj6dtp_table_rule_weight.py +82 -0
- ctrl_kd-4.5.0/tests/test_modern_box_regions.py +197 -0
- ctrl_kd-4.5.0/tests/test_modern_line_spacing.py +234 -0
- ctrl_kd-4.5.0/tests/test_modern_lint.py +1857 -0
- ctrl_kd-4.5.0/tests/test_note_rulings_20260824.py +266 -0
- ctrl_kd-4.5.0/tests/test_pictures.py +812 -0
- ctrl_kd-4.5.0/tests/test_pix.py +583 -0
- ctrl_kd-4.5.0/tests/test_polarity_gate.py +197 -0
- ctrl_kd-4.5.0/tests/test_printed_fidelity.py +824 -0
- ctrl_kd-4.5.0/tests/test_samples.py +117 -0
- ctrl_kd-4.5.0/tests/test_sawyer_corpus.py +209 -0
- ctrl_kd-4.5.0/tests/test_screenplay_detection.py +191 -0
- ctrl_kd-4.5.0/tests/test_screenplay_pdf.py +232 -0
- ctrl_kd-4.5.0/tests/test_screenplay_rendering.py +145 -0
- ctrl_kd-4.5.0/tests/test_sentence_spacing_n9.py +299 -0
- ctrl_kd-4.5.0/tests/test_style_leading.py +451 -0
- ctrl_kd-4.5.0/tests/test_verse_quote_couplet.py +109 -0
- ctrl_kd-4.5.0/tests/test_verse_spacing.py +95 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/tests/test_writer.py +6 -78
- ctrl_kd-4.5.0/tests/test_wschange.py +77 -0
- ctrl_kd-4.0.0/PKG-INFO +0 -170
- ctrl_kd-4.0.0/README.md +0 -151
- ctrl_kd-4.0.0/pyproject.toml +0 -36
- ctrl_kd-4.0.0/src/ctrl_kd.egg-info/PKG-INFO +0 -170
- ctrl_kd-4.0.0/src/ctrl_kd.egg-info/SOURCES.txt +0 -25
- ctrl_kd-4.0.0/src/ctrlkd/emit.py +0 -1085
- ctrl_kd-4.0.0/src/ctrlkd/info.py +0 -59
- ctrl_kd-4.0.0/src/ctrlkd/layout.py +0 -341
- ctrl_kd-4.0.0/src/ctrlkd/pdf.py +0 -1938
- ctrl_kd-4.0.0/tests/test_wschange.py +0 -194
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/LICENSE +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/setup.cfg +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrl_kd.egg-info/dependency_links.txt +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrl_kd.egg-info/entry_points.txt +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrl_kd.egg-info/top_level.txt +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/afm.py +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/convert.py +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/symbolmap.py +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/typestyles.py +0 -0
- {ctrl_kd-4.0.0 → ctrl_kd-4.5.0}/src/ctrlkd/writer.py +0 -0
ctrl_kd-4.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctrl-kd
|
|
3
|
+
Version: 4.5.0
|
|
4
|
+
Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
|
|
5
|
+
Author: Jon Michaels
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jonmichaels/ctrl-kd
|
|
8
|
+
Keywords: wordstar,converter,retrocomputing,archive,dos
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Text Processing :: Filters
|
|
14
|
+
Classifier: Topic :: System :: Archiving
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
__ __ __ __
|
|
22
|
+
_____/ /______/ / / /______/ /
|
|
23
|
+
/ ___/ __/ ___/ /_____/ //_/ __ /
|
|
24
|
+
/ /__/ /_/ / / /_____/ ,< / /_/ /
|
|
25
|
+
\___/\__/_/ /_/ /_/|_|\__,_/
|
|
26
|
+
```
|
|
27
|
+
# ctrl-kd
|
|
28
|
+
|
|
29
|
+
Convert WordStar for DOS v4-v7 files to modern formats. **^KD: save and done.**
|
|
30
|
+
|
|
31
|
+
`ctrl-kd` reads WordStar for DOS documents, and WordStar print stream files,
|
|
32
|
+
and writes plain text, Markdown, HTML, RTF, or PDF (set on a viewer's
|
|
33
|
+
built-in base-14 fonts — no dependencies, nothing embedded, the page as it
|
|
34
|
+
would have printed: printed mode follows the document's own font blocks and
|
|
35
|
+
its own layout arithmetic, while modern mode is the same document reflowed
|
|
36
|
+
for today: its fonts, headers, and footnotes all carried.
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
$ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
|
|
40
|
+
# document's own fonts carried
|
|
41
|
+
$ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
|
|
42
|
+
$ ctrl-kd ESSAY.WS -t md # modern markdown instead
|
|
43
|
+
$ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
|
|
44
|
+
$ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
|
|
45
|
+
$ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
|
|
46
|
+
$ ctrl-kd --comments MEMO.WS # include the author's hidden comments
|
|
47
|
+
$ ctrl-kd --no-notes PAPER.WS # body text only, no notes
|
|
48
|
+
$ ctrl-kd --samples DIR # write 4 bundled public-domain sample .WS files into DIR
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Modes
|
|
52
|
+
|
|
53
|
+
* `--mode modern` (default; bare runs produce RTF): the document brought to a
|
|
54
|
+
modern audience — reflowed, its own fonts and styles carried, footnotes at
|
|
55
|
+
the page bottom, gaps the file never specified filled with today's
|
|
56
|
+
conventions (a comfortable serif at reading size, one-inch margins).
|
|
57
|
+
* `--mode printed` (bare runs produce PDF): every line as laid out, on the
|
|
58
|
+
era's own page — how it came off the printer. Gaps are filled with 1990's
|
|
59
|
+
conventions instead; `--page-settings` supplies a particular machine's.
|
|
60
|
+
|
|
61
|
+
More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```console
|
|
66
|
+
$ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
|
|
67
|
+
$ pipx install ctrl-kd # or: pip install ctrl-kd
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
|
|
71
|
+
|
|
72
|
+
## Adding an output format
|
|
73
|
+
|
|
74
|
+
An output format is one function over the parsed document — register it with the
|
|
75
|
+
`@ctrlkd.emitter` decorator, or ship it as a pip-installable plugin via the
|
|
76
|
+
`ctrlkd.emitters` entry-point group and it appears in the CLI automatically.
|
|
77
|
+
**[EXTENDING.md](EXTENDING.md)** has the IR contract, a complete worked example
|
|
78
|
+
(BBCode in ~40 lines), and a checklist.
|
|
79
|
+
|
|
80
|
+
## Siblings
|
|
81
|
+
|
|
82
|
+
**[Soft Return](https://github.com/jonmichaels/soft-return)** — macOS viewer and converter plus QuickLook extension.
|
|
83
|
+
Includes a Swift command line utility.
|
|
84
|
+
|
|
85
|
+
## Lineage
|
|
86
|
+
|
|
87
|
+
I wanted to be able to see the 70-some WordStar 4 files I had from junior high
|
|
88
|
+
and high school. In about an hour and half my agent had my files looking
|
|
89
|
+
pretty good. And then I fell down the research rabbit hole...
|
|
90
|
+
|
|
91
|
+
`ctrl-kd` wouldn't have been possible without the tools and documentation that
|
|
92
|
+
kept WordStar readable: Yohanes Nugroho's WS-CON, Michael Petrie's English port,
|
|
93
|
+
the `wsconvert`project, Robert J. Sawyer's WordStar archive, and the WordStar
|
|
94
|
+
format documentation community.
|
|
95
|
+
|
|
96
|
+
My own test files are personal and are not distributed — this repo's tests use
|
|
97
|
+
synthetic fixtures and some public domain docs I retyped in WordStar 4 and
|
|
98
|
+
WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
|
|
99
|
+
`pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
|
|
100
|
+
against that if you have a copy.
|
|
101
|
+
|
|
102
|
+
## Credits
|
|
103
|
+
|
|
104
|
+
Written by Jon Michaels — whose 1987–1992 WordStar files, and the need to read
|
|
105
|
+
them again, are the reason this exists — with Athena (Claude, Anthropic) as
|
|
106
|
+
co-author.
|
ctrl_kd-4.5.0/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
```
|
|
2
|
+
__ __ __ __
|
|
3
|
+
_____/ /______/ / / /______/ /
|
|
4
|
+
/ ___/ __/ ___/ /_____/ //_/ __ /
|
|
5
|
+
/ /__/ /_/ / / /_____/ ,< / /_/ /
|
|
6
|
+
\___/\__/_/ /_/ /_/|_|\__,_/
|
|
7
|
+
```
|
|
8
|
+
# ctrl-kd
|
|
9
|
+
|
|
10
|
+
Convert WordStar for DOS v4-v7 files to modern formats. **^KD: save and done.**
|
|
11
|
+
|
|
12
|
+
`ctrl-kd` reads WordStar for DOS documents, and WordStar print stream files,
|
|
13
|
+
and writes plain text, Markdown, HTML, RTF, or PDF (set on a viewer's
|
|
14
|
+
built-in base-14 fonts — no dependencies, nothing embedded, the page as it
|
|
15
|
+
would have printed: printed mode follows the document's own font blocks and
|
|
16
|
+
its own layout arithmetic, while modern mode is the same document reflowed
|
|
17
|
+
for today: its fonts, headers, and footnotes all carried.
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
$ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
|
|
21
|
+
# document's own fonts carried
|
|
22
|
+
$ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
|
|
23
|
+
$ ctrl-kd ESSAY.WS -t md # modern markdown instead
|
|
24
|
+
$ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
|
|
25
|
+
$ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
|
|
26
|
+
$ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
|
|
27
|
+
$ ctrl-kd --comments MEMO.WS # include the author's hidden comments
|
|
28
|
+
$ ctrl-kd --no-notes PAPER.WS # body text only, no notes
|
|
29
|
+
$ ctrl-kd --samples DIR # write 4 bundled public-domain sample .WS files into DIR
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Modes
|
|
33
|
+
|
|
34
|
+
* `--mode modern` (default; bare runs produce RTF): the document brought to a
|
|
35
|
+
modern audience — reflowed, its own fonts and styles carried, footnotes at
|
|
36
|
+
the page bottom, gaps the file never specified filled with today's
|
|
37
|
+
conventions (a comfortable serif at reading size, one-inch margins).
|
|
38
|
+
* `--mode printed` (bare runs produce PDF): every line as laid out, on the
|
|
39
|
+
era's own page — how it came off the printer. Gaps are filled with 1990's
|
|
40
|
+
conventions instead; `--page-settings` supplies a particular machine's.
|
|
41
|
+
|
|
42
|
+
More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
$ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
|
|
48
|
+
$ pipx install ctrl-kd # or: pip install ctrl-kd
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
|
|
52
|
+
|
|
53
|
+
## Adding an output format
|
|
54
|
+
|
|
55
|
+
An output format is one function over the parsed document — register it with the
|
|
56
|
+
`@ctrlkd.emitter` decorator, or ship it as a pip-installable plugin via the
|
|
57
|
+
`ctrlkd.emitters` entry-point group and it appears in the CLI automatically.
|
|
58
|
+
**[EXTENDING.md](EXTENDING.md)** has the IR contract, a complete worked example
|
|
59
|
+
(BBCode in ~40 lines), and a checklist.
|
|
60
|
+
|
|
61
|
+
## Siblings
|
|
62
|
+
|
|
63
|
+
**[Soft Return](https://github.com/jonmichaels/soft-return)** — macOS viewer and converter plus QuickLook extension.
|
|
64
|
+
Includes a Swift command line utility.
|
|
65
|
+
|
|
66
|
+
## Lineage
|
|
67
|
+
|
|
68
|
+
I wanted to be able to see the 70-some WordStar 4 files I had from junior high
|
|
69
|
+
and high school. In about an hour and half my agent had my files looking
|
|
70
|
+
pretty good. And then I fell down the research rabbit hole...
|
|
71
|
+
|
|
72
|
+
`ctrl-kd` wouldn't have been possible without the tools and documentation that
|
|
73
|
+
kept WordStar readable: Yohanes Nugroho's WS-CON, Michael Petrie's English port,
|
|
74
|
+
the `wsconvert`project, Robert J. Sawyer's WordStar archive, and the WordStar
|
|
75
|
+
format documentation community.
|
|
76
|
+
|
|
77
|
+
My own test files are personal and are not distributed — this repo's tests use
|
|
78
|
+
synthetic fixtures and some public domain docs I retyped in WordStar 4 and
|
|
79
|
+
WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
|
|
80
|
+
`pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
|
|
81
|
+
against that if you have a copy.
|
|
82
|
+
|
|
83
|
+
## Credits
|
|
84
|
+
|
|
85
|
+
Written by Jon Michaels — whose 1987–1992 WordStar files, and the need to read
|
|
86
|
+
them again, are the reason this exists — with Athena (Claude, Anthropic) as
|
|
87
|
+
co-author.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ctrl-kd"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
authors = [{name = "Jon Michaels"}]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
keywords = ["wordstar", "converter", "retrocomputing", "archive", "dos"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Topic :: Text Processing :: Filters",
|
|
20
|
+
"Topic :: System :: Archiving",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://github.com/jonmichaels/ctrl-kd"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
ctrl-kd = "ctrlkd.cli:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
where = ["src"]
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.dynamic]
|
|
33
|
+
# single source of truth: src/ctrlkd/__init__.py __version__ -- the 4.0.0
|
|
34
|
+
# release shipped with pyproject still saying 3.0.0 because the version
|
|
35
|
+
# lived in two places and the bump hit one (2026-08-06); never again
|
|
36
|
+
version = {attr = "ctrlkd.__version__"}
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.package-data]
|
|
39
|
+
# The four bundled public-domain sample documents (see samples/README.md and
|
|
40
|
+
# `ctrl-kd --samples DIR`) travel with the wheel/sdist as package data.
|
|
41
|
+
ctrlkd = ["samples/*.WS"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
# Two-tier test architecture (K1, 2026-08-26; tier 3/private relocated out
|
|
45
|
+
# of this public repo entirely -- see README). Bare `pytest` must run ONLY
|
|
46
|
+
# tier 1 (tests/test_samples.py and every other test with no marker below)
|
|
47
|
+
# -- green, complete, zero skips, no environment required. Tier 2 is
|
|
48
|
+
# DESELECTED here, not skipped: it never even collects into the report, so
|
|
49
|
+
# a bare run's summary line is an honest denominator.
|
|
50
|
+
#
|
|
51
|
+
# Arming (see tests/sawyer_fixture.py, conftest.py):
|
|
52
|
+
# sawyer CTRLKD_SAWYER_ARCHIVE=/path (legacy alias: CTRLKD_CORPUS_SOURCE)
|
|
53
|
+
#
|
|
54
|
+
# tools/run-full-suite.sh overrides this filter (`-o addopts=""`) for an
|
|
55
|
+
# armed run, where an unarmed gate FAILS instead of silently not running --
|
|
56
|
+
# see that script's own header for why.
|
|
57
|
+
testpaths = ["tests"]
|
|
58
|
+
markers = [
|
|
59
|
+
"sawyer: opt-in tier 2 -- an explicit, committed list of documents from Robert J. Sawyer's public WordStar 7 archive (arm with CTRLKD_SAWYER_ARCHIVE)",
|
|
60
|
+
]
|
|
61
|
+
addopts = "-m \"not sawyer\""
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ctrl-kd
|
|
3
|
+
Version: 4.5.0
|
|
4
|
+
Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
|
|
5
|
+
Author: Jon Michaels
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jonmichaels/ctrl-kd
|
|
8
|
+
Keywords: wordstar,converter,retrocomputing,archive,dos
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Text Processing :: Filters
|
|
14
|
+
Classifier: Topic :: System :: Archiving
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
__ __ __ __
|
|
22
|
+
_____/ /______/ / / /______/ /
|
|
23
|
+
/ ___/ __/ ___/ /_____/ //_/ __ /
|
|
24
|
+
/ /__/ /_/ / / /_____/ ,< / /_/ /
|
|
25
|
+
\___/\__/_/ /_/ /_/|_|\__,_/
|
|
26
|
+
```
|
|
27
|
+
# ctrl-kd
|
|
28
|
+
|
|
29
|
+
Convert WordStar for DOS v4-v7 files to modern formats. **^KD: save and done.**
|
|
30
|
+
|
|
31
|
+
`ctrl-kd` reads WordStar for DOS documents, and WordStar print stream files,
|
|
32
|
+
and writes plain text, Markdown, HTML, RTF, or PDF (set on a viewer's
|
|
33
|
+
built-in base-14 fonts — no dependencies, nothing embedded, the page as it
|
|
34
|
+
would have printed: printed mode follows the document's own font blocks and
|
|
35
|
+
its own layout arithmetic, while modern mode is the same document reflowed
|
|
36
|
+
for today: its fonts, headers, and footnotes all carried.
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
$ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
|
|
40
|
+
# document's own fonts carried
|
|
41
|
+
$ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
|
|
42
|
+
$ ctrl-kd ESSAY.WS -t md # modern markdown instead
|
|
43
|
+
$ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
|
|
44
|
+
$ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
|
|
45
|
+
$ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
|
|
46
|
+
$ ctrl-kd --comments MEMO.WS # include the author's hidden comments
|
|
47
|
+
$ ctrl-kd --no-notes PAPER.WS # body text only, no notes
|
|
48
|
+
$ ctrl-kd --samples DIR # write 4 bundled public-domain sample .WS files into DIR
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Modes
|
|
52
|
+
|
|
53
|
+
* `--mode modern` (default; bare runs produce RTF): the document brought to a
|
|
54
|
+
modern audience — reflowed, its own fonts and styles carried, footnotes at
|
|
55
|
+
the page bottom, gaps the file never specified filled with today's
|
|
56
|
+
conventions (a comfortable serif at reading size, one-inch margins).
|
|
57
|
+
* `--mode printed` (bare runs produce PDF): every line as laid out, on the
|
|
58
|
+
era's own page — how it came off the printer. Gaps are filled with 1990's
|
|
59
|
+
conventions instead; `--page-settings` supplies a particular machine's.
|
|
60
|
+
|
|
61
|
+
More information: **[FAQ.md](FAQ.md)**, and **[ERAS.md](ERAS.md)**.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```console
|
|
66
|
+
$ brew install jonmichaels/tap/ctrl-kd # macOS / Linuxbrew
|
|
67
|
+
$ pipx install ctrl-kd # or: pip install ctrl-kd
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Python ≥ 3.9, no dependencies. Library API: `ctrlkd.convert(data, to='html')`.
|
|
71
|
+
|
|
72
|
+
## Adding an output format
|
|
73
|
+
|
|
74
|
+
An output format is one function over the parsed document — register it with the
|
|
75
|
+
`@ctrlkd.emitter` decorator, or ship it as a pip-installable plugin via the
|
|
76
|
+
`ctrlkd.emitters` entry-point group and it appears in the CLI automatically.
|
|
77
|
+
**[EXTENDING.md](EXTENDING.md)** has the IR contract, a complete worked example
|
|
78
|
+
(BBCode in ~40 lines), and a checklist.
|
|
79
|
+
|
|
80
|
+
## Siblings
|
|
81
|
+
|
|
82
|
+
**[Soft Return](https://github.com/jonmichaels/soft-return)** — macOS viewer and converter plus QuickLook extension.
|
|
83
|
+
Includes a Swift command line utility.
|
|
84
|
+
|
|
85
|
+
## Lineage
|
|
86
|
+
|
|
87
|
+
I wanted to be able to see the 70-some WordStar 4 files I had from junior high
|
|
88
|
+
and high school. In about an hour and half my agent had my files looking
|
|
89
|
+
pretty good. And then I fell down the research rabbit hole...
|
|
90
|
+
|
|
91
|
+
`ctrl-kd` wouldn't have been possible without the tools and documentation that
|
|
92
|
+
kept WordStar readable: Yohanes Nugroho's WS-CON, Michael Petrie's English port,
|
|
93
|
+
the `wsconvert`project, Robert J. Sawyer's WordStar archive, and the WordStar
|
|
94
|
+
format documentation community.
|
|
95
|
+
|
|
96
|
+
My own test files are personal and are not distributed — this repo's tests use
|
|
97
|
+
synthetic fixtures and some public domain docs I retyped in WordStar 4 and
|
|
98
|
+
WordStar 7 in DOSBox-X, plus Robert J. Sawyer's public WS7 archive (opt-in,
|
|
99
|
+
`pytest -m sawyer`; see `tests/SAWYER-CORPUS.md`) you can run your own tests
|
|
100
|
+
against that if you have a copy.
|
|
101
|
+
|
|
102
|
+
## Credits
|
|
103
|
+
|
|
104
|
+
Written by Jon Michaels — whose 1987–1992 WordStar files, and the need to read
|
|
105
|
+
them again, are the reason this exists — with Athena (Claude, Anthropic) as
|
|
106
|
+
co-author.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/ctrl_kd.egg-info/PKG-INFO
|
|
5
|
+
src/ctrl_kd.egg-info/SOURCES.txt
|
|
6
|
+
src/ctrl_kd.egg-info/dependency_links.txt
|
|
7
|
+
src/ctrl_kd.egg-info/entry_points.txt
|
|
8
|
+
src/ctrl_kd.egg-info/top_level.txt
|
|
9
|
+
src/ctrlkd/__init__.py
|
|
10
|
+
src/ctrlkd/afm.py
|
|
11
|
+
src/ctrlkd/cli.py
|
|
12
|
+
src/ctrlkd/convert.py
|
|
13
|
+
src/ctrlkd/core.py
|
|
14
|
+
src/ctrlkd/emit.py
|
|
15
|
+
src/ctrlkd/fontmap.py
|
|
16
|
+
src/ctrlkd/info.py
|
|
17
|
+
src/ctrlkd/layout.py
|
|
18
|
+
src/ctrlkd/pdf.py
|
|
19
|
+
src/ctrlkd/pictures.py
|
|
20
|
+
src/ctrlkd/pix.py
|
|
21
|
+
src/ctrlkd/piximg.py
|
|
22
|
+
src/ctrlkd/symbolmap.py
|
|
23
|
+
src/ctrlkd/typestyles.py
|
|
24
|
+
src/ctrlkd/writer.py
|
|
25
|
+
src/ctrlkd/wschange.py
|
|
26
|
+
src/ctrlkd/samples/LYING.WS
|
|
27
|
+
src/ctrlkd/samples/OCAPTAIN.WS
|
|
28
|
+
src/ctrlkd/samples/TWAINLET.WS
|
|
29
|
+
src/ctrlkd/samples/WARPRAYR.WS
|
|
30
|
+
tests/test_ctrlkd.py
|
|
31
|
+
tests/test_endnote_leading_gap.py
|
|
32
|
+
tests/test_fidelity_gate.py
|
|
33
|
+
tests/test_flags_toc_inline.py
|
|
34
|
+
tests/test_glyph_aspect.py
|
|
35
|
+
tests/test_layout_marks.py
|
|
36
|
+
tests/test_lj6dtp_bullet_glyph.py
|
|
37
|
+
tests/test_lj6dtp_char_substitution.py
|
|
38
|
+
tests/test_lj6dtp_colour_restore.py
|
|
39
|
+
tests/test_lj6dtp_heading_face.py
|
|
40
|
+
tests/test_lj6dtp_hp_patterns.py
|
|
41
|
+
tests/test_lj6dtp_legend_line_spacing.py
|
|
42
|
+
tests/test_lj6dtp_pcl_rectangles.py
|
|
43
|
+
tests/test_lj6dtp_shading_table_rules.py
|
|
44
|
+
tests/test_lj6dtp_table_rule_weight.py
|
|
45
|
+
tests/test_modern_box_regions.py
|
|
46
|
+
tests/test_modern_line_spacing.py
|
|
47
|
+
tests/test_modern_lint.py
|
|
48
|
+
tests/test_note_rulings_20260824.py
|
|
49
|
+
tests/test_pictures.py
|
|
50
|
+
tests/test_pix.py
|
|
51
|
+
tests/test_polarity_gate.py
|
|
52
|
+
tests/test_printed_fidelity.py
|
|
53
|
+
tests/test_samples.py
|
|
54
|
+
tests/test_sawyer_corpus.py
|
|
55
|
+
tests/test_screenplay_detection.py
|
|
56
|
+
tests/test_screenplay_pdf.py
|
|
57
|
+
tests/test_screenplay_rendering.py
|
|
58
|
+
tests/test_sentence_spacing_n9.py
|
|
59
|
+
tests/test_style_leading.py
|
|
60
|
+
tests/test_verse_quote_couplet.py
|
|
61
|
+
tests/test_verse_spacing.py
|
|
62
|
+
tests/test_writer.py
|
|
63
|
+
tests/test_wschange.py
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
|
|
8
8
|
ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
|
|
9
9
|
ctrl-kd -t text -t html -d out/ *.WS # batch, multiple formats
|
|
10
|
+
ctrl-kd --samples DIR # write the 4 bundled sample .WS files into DIR
|
|
10
11
|
"""
|
|
11
|
-
import argparse, json, os, sys
|
|
12
|
+
import argparse, importlib.resources, json, os, shutil, sys
|
|
12
13
|
|
|
13
14
|
BANNER = r""" __ __ __ __
|
|
14
15
|
_____/ /______/ / / /______/ /
|
|
@@ -21,7 +22,7 @@ BANNER = r""" __ __ __ __
|
|
|
21
22
|
# because the name never changes; no .flf machinery needed.
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
from . import core, emit
|
|
25
|
+
from . import core, emit, pictures
|
|
25
26
|
from .convert import DEFAULT_NOTE_KINDS # module attr, not the re-exported convert()
|
|
26
27
|
|
|
27
28
|
def diagnose(path, data):
|
|
@@ -30,6 +31,26 @@ def diagnose(path, data):
|
|
|
30
31
|
from .info import document_info
|
|
31
32
|
return document_info(data, path=path)
|
|
32
33
|
|
|
34
|
+
# The four public-domain WordStar sample documents (see samples/README.md at
|
|
35
|
+
# the repo root for credits) -- shipped as package data (src/ctrlkd/samples/,
|
|
36
|
+
# [tool.setuptools.package-data] in pyproject.toml) so `--samples` works from
|
|
37
|
+
# an installed wheel, not just a checkout.
|
|
38
|
+
SAMPLE_NAMES = ['LYING.WS', 'OCAPTAIN.WS', 'TWAINLET.WS', 'WARPRAYR.WS']
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_samples(outdir):
|
|
42
|
+
"""Write the four bundled sample documents into outdir. Returns the list
|
|
43
|
+
of paths written."""
|
|
44
|
+
os.makedirs(outdir, exist_ok=True)
|
|
45
|
+
written = []
|
|
46
|
+
samples_dir = importlib.resources.files('ctrlkd').joinpath('samples')
|
|
47
|
+
for name in SAMPLE_NAMES:
|
|
48
|
+
dest = os.path.join(outdir, name)
|
|
49
|
+
with importlib.resources.as_file(samples_dir.joinpath(name)) as src:
|
|
50
|
+
shutil.copyfile(src, dest)
|
|
51
|
+
written.append(dest)
|
|
52
|
+
return written
|
|
53
|
+
|
|
33
54
|
def main(argv=None):
|
|
34
55
|
emit.load_plugins() # third-party emitters (ctrlkd.emitters entry points)
|
|
35
56
|
ap = argparse.ArgumentParser(
|
|
@@ -41,7 +62,12 @@ def main(argv=None):
|
|
|
41
62
|
from . import __version__
|
|
42
63
|
ap.add_argument('--version', action='version',
|
|
43
64
|
version=BANNER + f'\nctrl-kd {__version__}')
|
|
44
|
-
ap.add_argument('files', nargs='
|
|
65
|
+
ap.add_argument('files', nargs='*', help='input file(s) (not required '
|
|
66
|
+
'with --samples)')
|
|
67
|
+
ap.add_argument('--samples', metavar='DIR',
|
|
68
|
+
help='write the four bundled public-domain WordStar '
|
|
69
|
+
'sample documents into DIR (see samples/README.md); '
|
|
70
|
+
'no conversion, files are not required')
|
|
45
71
|
ap.add_argument('-t', '--to', action='append', choices=emit.formats(),
|
|
46
72
|
help='output format (repeatable). Default follows the '
|
|
47
73
|
'mode: modern -> rtf (the full-fidelity living '
|
|
@@ -103,6 +129,70 @@ def main(argv=None):
|
|
|
103
129
|
ap.add_argument('--no-styles', action='store_true',
|
|
104
130
|
help='omit paragraph-style pass-through (HTML classes + '
|
|
105
131
|
'generated CSS, RTF stylesheet) from the output')
|
|
132
|
+
ap.add_argument('--headers', choices=('on', 'off'), default='on',
|
|
133
|
+
help='headers, footers, and page numbers in the paged '
|
|
134
|
+
'surfaces (Printed/Native PDF and RTF). Default: on')
|
|
135
|
+
ap.add_argument('--page-numbers', choices=('auto', 'on', 'off'),
|
|
136
|
+
default='auto',
|
|
137
|
+
help="WordStar's own AUTOMATIC page number -- the one "
|
|
138
|
+
'.pc positions, a separate mechanism from a # the '
|
|
139
|
+
'author placed inside a real .he/.fo (that always '
|
|
140
|
+
'prints, unaffected by this flag). Printed PDF '
|
|
141
|
+
'only. auto (DEFAULT): the document\'s own dot '
|
|
142
|
+
'commands decide -- .pn/.pg turn it on, .op turns '
|
|
143
|
+
'it off, exactly like real WordStar; a document '
|
|
144
|
+
'that never touches any of the four gets no '
|
|
145
|
+
'number, byte-identical to before this flag '
|
|
146
|
+
'existed. on: force stock default numbering '
|
|
147
|
+
'(bottom-center; .pc repositions it) even on a '
|
|
148
|
+
'silent document. off: suppress it unconditionally. '
|
|
149
|
+
'A declared footer always pre-empts it, in every '
|
|
150
|
+
'mode (WSFORMAT.WS: "active only when the footers '
|
|
151
|
+
'are not in use"). --headers off also suppresses '
|
|
152
|
+
'it, per --headers\' own documented scope.')
|
|
153
|
+
ap.add_argument('--line-numbers', choices=('on', 'off'), default='on',
|
|
154
|
+
help="the document's own .l# line-number gutter in the "
|
|
155
|
+
'paged surfaces (Printed/Native PDF and RTF); no '
|
|
156
|
+
'effect on a document that never set .l#. Default: on')
|
|
157
|
+
ap.add_argument('--sentence-spacing', choices=('auto', 'keep', 'single'),
|
|
158
|
+
default='auto',
|
|
159
|
+
help='the typewriter double space after a sentence-'
|
|
160
|
+
"ending '.', '?', or '!'. auto (DEFAULT): follows "
|
|
161
|
+
'--mode -- modern converts it to a single space '
|
|
162
|
+
'(the modern typographic convention); printed '
|
|
163
|
+
'keeps the document exactly as authored (period '
|
|
164
|
+
'fidelity). keep/single force that choice '
|
|
165
|
+
'regardless of mode. A simple textual rule, no '
|
|
166
|
+
'abbreviation detection: "e.g. x" collapses like '
|
|
167
|
+
'a real sentence end. Markdown never emits a '
|
|
168
|
+
'trailing double space from this either way (that '
|
|
169
|
+
"is CommonMark's own hard-break marker) -- unrelated "
|
|
170
|
+
'to this flag, always on.')
|
|
171
|
+
ap.add_argument('--toc', choices=('on', 'off'), default='off',
|
|
172
|
+
help='compile a Table of Contents (.tc) and Index (.ix) '
|
|
173
|
+
'section at the document end, in every format; the '
|
|
174
|
+
'two paged surfaces (Printed PDF and RTF) resolve '
|
|
175
|
+
'each entry to a real page number, every other '
|
|
176
|
+
'format lists entries without one. Default: off')
|
|
177
|
+
ap.add_argument('--inline-styling', choices=('on', 'off'), default='on',
|
|
178
|
+
help='inline colour (^A) and font-size (^B... a symmetric '
|
|
179
|
+
'type-2 font block) changes the author placed mid-'
|
|
180
|
+
'text -- RTF gets \\cf from a 16-colour screen '
|
|
181
|
+
'palette and \\fsN; HTML gets a span with color/'
|
|
182
|
+
'font-size. Default: on')
|
|
183
|
+
ap.add_argument('--pictures', choices=('off', 'embed', 'export'), default='embed',
|
|
184
|
+
help='WS5+ PIX image references (register, "PIX images '
|
|
185
|
+
'RULED IN"). embed (DEFAULT): RTF/PDF native '
|
|
186
|
+
'embedding, HTML data URI, MD exports files + a '
|
|
187
|
+
'one-line stderr note (MD has no true embed). '
|
|
188
|
+
'export: PNG files under <docname>-images/ beside '
|
|
189
|
+
'the output, relative links from HTML/MD; RTF/PDF '
|
|
190
|
+
'still embed (no portable reference mechanism) AND '
|
|
191
|
+
'the PNGs are also written. off: the plain '
|
|
192
|
+
'[image: NAME] placeholder, as before this flag '
|
|
193
|
+
'existed. A missing/unreadable .PIX is reported on '
|
|
194
|
+
'stderr (name + probed locations) and never fails '
|
|
195
|
+
'the conversion; the placeholder is kept either way.')
|
|
106
196
|
ap.add_argument('--no-notes', action='store_true',
|
|
107
197
|
help='omit footnotes, endnotes and annotations from the output')
|
|
108
198
|
ap.add_argument('--comments', action='store_true',
|
|
@@ -112,6 +202,12 @@ def main(argv=None):
|
|
|
112
202
|
help='report what the file is (variant, margin, dot commands, '
|
|
113
203
|
'unknown codes) as JSON; no conversion')
|
|
114
204
|
a = ap.parse_args(argv)
|
|
205
|
+
if a.samples:
|
|
206
|
+
for dest in write_samples(a.samples):
|
|
207
|
+
print(f'-> {dest}', file=sys.stderr)
|
|
208
|
+
return 0
|
|
209
|
+
if not a.files:
|
|
210
|
+
ap.error('the following arguments are required: files')
|
|
115
211
|
mode_explicit = a.mode is not None
|
|
116
212
|
a.mode = a.mode or 'modern'
|
|
117
213
|
# The default format follows the mode (ruling 2026-08-05): bare modern =
|
|
@@ -223,11 +319,21 @@ def main(argv=None):
|
|
|
223
319
|
doc.meta['page'] = core.effective_page(doc.meta['page'],
|
|
224
320
|
page_settings)
|
|
225
321
|
base = os.path.splitext(os.path.basename(path))[0]
|
|
322
|
+
# Round 19 (PIX images RULED IN, ledger PIX row): resolved/decoded
|
|
323
|
+
# ONCE per document, reused across every requested format (each
|
|
324
|
+
# PIX file is read and decoded at most once regardless of how
|
|
325
|
+
# many -t flags this run carries). `path` is the real filesystem
|
|
326
|
+
# location resolution searches near -- the CLI always has one; a
|
|
327
|
+
# library caller without a real path passes None (every tag then
|
|
328
|
+
# reports 'unresolved', ctrlkd.pictures' own documented behavior).
|
|
329
|
+
pix_results = (pictures.resolve_document_pictures(doc, path)
|
|
330
|
+
if doc.graphics else [])
|
|
331
|
+
if pix_results and a.pictures != 'off':
|
|
332
|
+
# 'off' means the user doesn't want the feature at all -- no
|
|
333
|
+
# point reporting misses for pictures nothing will render.
|
|
334
|
+
pictures.report_misses(pix_results, path, path)
|
|
226
335
|
for fmt in formats:
|
|
227
336
|
reg = emit.get_emitter(fmt)
|
|
228
|
-
out = reg['fn'](doc, a.mode, title=base, notes=notes,
|
|
229
|
-
styles=not a.no_styles, fonts_target=a.fonts,
|
|
230
|
-
note_refs=a.note_refs)
|
|
231
337
|
if a.output:
|
|
232
338
|
dest = a.output
|
|
233
339
|
else:
|
|
@@ -235,6 +341,44 @@ def main(argv=None):
|
|
|
235
341
|
base + reg['ext'])
|
|
236
342
|
if a.outdir:
|
|
237
343
|
os.makedirs(a.outdir, exist_ok=True)
|
|
344
|
+
# --pictures export writes PNG files beside the output for
|
|
345
|
+
# every applicable format; MD's own embed mode degrades to
|
|
346
|
+
# the same export-and-link behavior (ruled: MD has no true
|
|
347
|
+
# embed) -- ONE stderr note for that degradation, here, not
|
|
348
|
+
# inside emit_markdown (library functions stay silent, same
|
|
349
|
+
# convention as every other emit_* degradation this session).
|
|
350
|
+
image_links = None
|
|
351
|
+
# MD's embed-degrades-to-export only matters in MODERN mode --
|
|
352
|
+
# a Printed-mode MD body is emit_text's fenced facsimile
|
|
353
|
+
# (never consults image_links at all, by design: a fence is
|
|
354
|
+
# the emitter's own "verbatim" promise), so exporting files
|
|
355
|
+
# and printing the degradation note for it would be pure
|
|
356
|
+
# waste, not a correctness issue but a confusing one.
|
|
357
|
+
need_export = (a.pictures == 'export'
|
|
358
|
+
or (fmt == 'md' and a.pictures == 'embed'
|
|
359
|
+
and a.mode == 'modern'))
|
|
360
|
+
if need_export and any(r.ok for r in pix_results):
|
|
361
|
+
images_dir = os.path.join(os.path.dirname(dest) or '.',
|
|
362
|
+
base + '-images')
|
|
363
|
+
written = pictures.write_export_images(pix_results, images_dir)
|
|
364
|
+
image_links = {i: f'{base}-images/{name}'
|
|
365
|
+
for i, name in written.items()}
|
|
366
|
+
if fmt == 'md' and a.pictures == 'embed' and written:
|
|
367
|
+
print(f'ctrl-kd: {path}: Markdown has no true image '
|
|
368
|
+
f'embedding -- exporting {len(written)} PNG '
|
|
369
|
+
f"file(s) to {os.path.basename(images_dir)}/ "
|
|
370
|
+
f'and linking to them instead (degradation per '
|
|
371
|
+
f'the pictures flag ruling)', file=sys.stderr)
|
|
372
|
+
out = reg['fn'](doc, a.mode, title=base, notes=notes,
|
|
373
|
+
styles=not a.no_styles, fonts_target=a.fonts,
|
|
374
|
+
note_refs=a.note_refs, headers=a.headers == 'on',
|
|
375
|
+
line_numbers=a.line_numbers == 'on',
|
|
376
|
+
toc=a.toc == 'on',
|
|
377
|
+
inline_styling=a.inline_styling == 'on',
|
|
378
|
+
pictures=a.pictures, pix_results=pix_results,
|
|
379
|
+
image_links=image_links,
|
|
380
|
+
page_numbers=a.page_numbers,
|
|
381
|
+
sentence_spacing=a.sentence_spacing)
|
|
238
382
|
if isinstance(out, bytes): # binary formats (e.g. pdf)
|
|
239
383
|
with open(dest, 'wb') as f:
|
|
240
384
|
f.write(out)
|