atrep-cli 0.3.0__tar.gz → 0.3.1__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.
Files changed (113) hide show
  1. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/Cargo.lock +3 -3
  2. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/Cargo.toml +2 -2
  3. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/PKG-INFO +12 -7
  4. {atrep_cli-0.3.0/crates/atrep → atrep_cli-0.3.1}/README.md +11 -6
  5. {atrep_cli-0.3.0/crates/atrep-cli → atrep_cli-0.3.1/crates/atrep}/README.md +11 -6
  6. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/endo.rs +386 -20
  7. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-djot.at-markdown.iso +2 -0
  8. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-djot.dia +16 -0
  9. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-djot.dj.exo +4 -0
  10. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-docbook.dia +25 -1
  11. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-docbook.docbook.exo +17 -1
  12. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.at-rst.hom +2 -1
  13. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.dia +11 -0
  14. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.html.exo +4 -0
  15. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-markdown.dia +11 -0
  16. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-markdown.md.exo +4 -0
  17. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-org.at-html.hom +1 -1
  18. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-rst.dia +12 -0
  19. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-rst.rst.exo +4 -0
  20. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.at-docbook.hom +9 -5
  21. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.at-html.hom +3 -2
  22. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.gemtext.exo +5 -3
  23. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/djot.rs +20 -0
  24. atrep_cli-0.3.1/crates/atrep/tests/docbook.rs +180 -0
  25. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/html.rs +18 -0
  26. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/litogramma.rs +54 -21
  27. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/markdown.rs +56 -0
  28. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/rst.rs +45 -0
  29. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/tasso.rs +1 -3
  30. {atrep_cli-0.3.0 → atrep_cli-0.3.1/crates/atrep-cli}/README.md +11 -6
  31. atrep_cli-0.3.0/crates/atrep/tests/docbook.rs +0 -78
  32. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/LICENSE-APACHE +0 -0
  33. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/LICENSE-MIT +0 -0
  34. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/Cargo.toml +0 -0
  35. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/atramento.rs +0 -0
  36. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/dendron.rs +0 -0
  37. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/dialektos.rs +0 -0
  38. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/error.rs +0 -0
  39. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/exo.rs +0 -0
  40. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/fetch.rs +0 -0
  41. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/glossa.rs +0 -0
  42. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/kanonizo.rs +0 -0
  43. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/lib.rs +0 -0
  44. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/litosis.rs +0 -0
  45. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/morph.rs +0 -0
  46. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/outline.rs +0 -0
  47. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/parser.rs +0 -0
  48. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/scan.rs +0 -0
  49. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/sigil.rs +0 -0
  50. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/source.rs +0 -0
  51. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/src/zygosis.rs +0 -0
  52. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-docbook.litogramma.hom +0 -0
  53. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-drama.dia +0 -0
  54. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.at-markdown.hom +0 -0
  55. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.at-org.hom +0 -0
  56. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-html.xhtml.exo +0 -0
  57. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-org.dia +0 -0
  58. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-org.org.exo +0 -0
  59. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-poesia.dia +0 -0
  60. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-prosa.dia +0 -0
  61. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-rst.at-html.hom +0 -0
  62. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-tei.dia +0 -0
  63. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-tei.tei.exo +0 -0
  64. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.dia +0 -0
  65. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.latex.a5.exo +0 -0
  66. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.latex.exo +0 -0
  67. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.latex.redletter.exo +0 -0
  68. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.latex.ru.exo +0 -0
  69. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.osis.exo +0 -0
  70. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.usfm.exo +0 -0
  71. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/at-usfm.usx.exo +0 -0
  72. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/bibliogramma.bib.exo +0 -0
  73. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/bibliogramma.bibtex.exo +0 -0
  74. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/bibliogramma.dia +0 -0
  75. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/koine.dia +0 -0
  76. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/koine.latex.exo +0 -0
  77. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.at-tei.hom +0 -0
  78. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.dia +0 -0
  79. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.html.exo +0 -0
  80. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/std/litogramma.latex.exo +0 -0
  81. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/atramento.rs +0 -0
  82. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/attei.rs +0 -0
  83. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/autonym.rs +0 -0
  84. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/bibtex.rs +0 -0
  85. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/collate.rs +0 -0
  86. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/deixis.rs +0 -0
  87. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/errors.rs +0 -0
  88. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/exo.rs +0 -0
  89. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/base.dia +0 -0
  90. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/child.dia +0 -0
  91. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/exempli.html.exo +0 -0
  92. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/exempli.lektos +0 -0
  93. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/intro.atd +0 -0
  94. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/pipeline.svg +0 -0
  95. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/fixtures/steps.txt +0 -0
  96. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/golden.rs +0 -0
  97. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/jats.rs +0 -0
  98. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/lektos.rs +0 -0
  99. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/lex0.rs +0 -0
  100. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/metagraphe.rs +0 -0
  101. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/milestone.rs +0 -0
  102. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/morph.rs +0 -0
  103. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/org.rs +0 -0
  104. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/outline.rs +0 -0
  105. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/remote.rs +0 -0
  106. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/stichoi.rs +0 -0
  107. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/tei.rs +0 -0
  108. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/usfm.rs +0 -0
  109. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/vocab.rs +0 -0
  110. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep/tests/zygo.rs +0 -0
  111. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep-cli/Cargo.toml +0 -0
  112. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/crates/atrep-cli/src/main.rs +0 -0
  113. {atrep_cli-0.3.0 → atrep_cli-0.3.1}/pyproject.toml +0 -0
@@ -60,7 +60,7 @@ dependencies = [
60
60
 
61
61
  [[package]]
62
62
  name = "atrep"
63
- version = "0.3.0"
63
+ version = "0.3.1"
64
64
  dependencies = [
65
65
  "flate2",
66
66
  "serde",
@@ -73,7 +73,7 @@ dependencies = [
73
73
 
74
74
  [[package]]
75
75
  name = "atrep-cli"
76
- version = "0.3.0"
76
+ version = "0.3.1"
77
77
  dependencies = [
78
78
  "atrep",
79
79
  "clap",
@@ -81,7 +81,7 @@ dependencies = [
81
81
 
82
82
  [[package]]
83
83
  name = "atrep-lsp"
84
- version = "0.3.0"
84
+ version = "0.3.1"
85
85
  dependencies = [
86
86
  "atrep",
87
87
  "lsp-server",
@@ -3,14 +3,14 @@ resolver = "2"
3
3
  members = ["crates/atrep", "crates/atrep-cli"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.0"
6
+ version = "0.3.1"
7
7
  edition = "2024"
8
8
  license = "MIT OR Apache-2.0"
9
9
  authors = ["Bojan Durickovic <dev@deyanovich.org>"]
10
10
  repository = "https://gitlab.com/atrep/atrep-rs"
11
11
 
12
12
  [workspace.dependencies]
13
- atrep = { path = "crates/atrep", version = "0.3.0" }
13
+ atrep = { path = "crates/atrep", version = "0.3.1" }
14
14
  unicode-normalization = "0.1"
15
15
  sha2 = "0.10"
16
16
  ureq = "3"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atrep-cli
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Programming Language :: Rust
@@ -262,7 +262,8 @@ Implemented:
262
262
  and never across a non-injective rename onto a trigger (peer
263
263
  triggers would share a rank the serialized form cannot
264
264
  express; spec v0.11.1) — everywhere else `apply_route` falls
265
- back to staged application automatically. `atrep compose a b [c ...]` writes
265
+ back to staged application automatically.
266
+ `atrep compose a b [c ...]` writes
266
267
  the composite as an ordinary `.hom` file in normal form —
267
268
  group rules in rank order, table rules sorted, implicit
268
269
  identities elided, with `@=via` declarations recording the
@@ -280,18 +281,22 @@ Implemented:
280
281
  HTML-subset, and reStructuredText-subset importers into
281
282
  `at-markdown`/`at-html`/`at-rst` (strict over the canonical
282
283
  subsets; RST footnotes become deixis callouts, fixed adornment
283
- table for title levels), Org-mode and Djot subset importers into the
284
- `at-org` and `at-djot` std dialektoi, a DocBook subset
285
- importer into `at-docbook` (`.dbk`); the `at-tei` std dialektos
284
+ table for title levels, hyperlink references with embedded
285
+ URIs as the visible-URL link), Org-mode and Djot subset
286
+ importers into the `at-org` and `at-djot` std dialektoi, a
287
+ DocBook subset importer into `at-docbook` (`.dbk`; quote and
288
+ link included); the `at-tei` std dialektos
286
289
  applies the bibliogramma pattern to TEI — ~15 form sims with
287
290
  the TEI element identity in vocabulary-bound genoses
288
291
  (`@,x,@.persname`), a `tei` exo emitting real TEI XML, and a
289
- litogramma hom giving litogramma TEI export via morph+exo, a BibTeX importer into
292
+ litogramma hom giving litogramma TEI export via morph+exo, a
293
+ BibTeX importer into
290
294
  `bibliogramma` (`.bib`), a JATS subset importer (`.jats`) into
291
295
  litogramma with the ref-list embedded as a bibliogramma
292
296
  englossis — the BibTeX-isomorphic bibliography
293
297
  extension defined beside litogramma (entry lemma = citation
294
- key, genos = entry type, fields as lemma-named sims) — the first *nested* std
298
+ key, genos = entry type, fields as lemma-named sims) — the
299
+ first *nested* std
295
300
  dialektos: one uniform section sim nests, so
296
301
  structure-preserving morphisms to and from litogramma need
297
302
  no flattening — (`.org`: star headings, the emphasis
@@ -245,7 +245,8 @@ Implemented:
245
245
  and never across a non-injective rename onto a trigger (peer
246
246
  triggers would share a rank the serialized form cannot
247
247
  express; spec v0.11.1) — everywhere else `apply_route` falls
248
- back to staged application automatically. `atrep compose a b [c ...]` writes
248
+ back to staged application automatically.
249
+ `atrep compose a b [c ...]` writes
249
250
  the composite as an ordinary `.hom` file in normal form —
250
251
  group rules in rank order, table rules sorted, implicit
251
252
  identities elided, with `@=via` declarations recording the
@@ -263,18 +264,22 @@ Implemented:
263
264
  HTML-subset, and reStructuredText-subset importers into
264
265
  `at-markdown`/`at-html`/`at-rst` (strict over the canonical
265
266
  subsets; RST footnotes become deixis callouts, fixed adornment
266
- table for title levels), Org-mode and Djot subset importers into the
267
- `at-org` and `at-djot` std dialektoi, a DocBook subset
268
- importer into `at-docbook` (`.dbk`); the `at-tei` std dialektos
267
+ table for title levels, hyperlink references with embedded
268
+ URIs as the visible-URL link), Org-mode and Djot subset
269
+ importers into the `at-org` and `at-djot` std dialektoi, a
270
+ DocBook subset importer into `at-docbook` (`.dbk`; quote and
271
+ link included); the `at-tei` std dialektos
269
272
  applies the bibliogramma pattern to TEI — ~15 form sims with
270
273
  the TEI element identity in vocabulary-bound genoses
271
274
  (`@,x,@.persname`), a `tei` exo emitting real TEI XML, and a
272
- litogramma hom giving litogramma TEI export via morph+exo, a BibTeX importer into
275
+ litogramma hom giving litogramma TEI export via morph+exo, a
276
+ BibTeX importer into
273
277
  `bibliogramma` (`.bib`), a JATS subset importer (`.jats`) into
274
278
  litogramma with the ref-list embedded as a bibliogramma
275
279
  englossis — the BibTeX-isomorphic bibliography
276
280
  extension defined beside litogramma (entry lemma = citation
277
- key, genos = entry type, fields as lemma-named sims) — the first *nested* std
281
+ key, genos = entry type, fields as lemma-named sims) — the
282
+ first *nested* std
278
283
  dialektos: one uniform section sim nests, so
279
284
  structure-preserving morphisms to and from litogramma need
280
285
  no flattening — (`.org`: star headings, the emphasis
@@ -245,7 +245,8 @@ Implemented:
245
245
  and never across a non-injective rename onto a trigger (peer
246
246
  triggers would share a rank the serialized form cannot
247
247
  express; spec v0.11.1) — everywhere else `apply_route` falls
248
- back to staged application automatically. `atrep compose a b [c ...]` writes
248
+ back to staged application automatically.
249
+ `atrep compose a b [c ...]` writes
249
250
  the composite as an ordinary `.hom` file in normal form —
250
251
  group rules in rank order, table rules sorted, implicit
251
252
  identities elided, with `@=via` declarations recording the
@@ -263,18 +264,22 @@ Implemented:
263
264
  HTML-subset, and reStructuredText-subset importers into
264
265
  `at-markdown`/`at-html`/`at-rst` (strict over the canonical
265
266
  subsets; RST footnotes become deixis callouts, fixed adornment
266
- table for title levels), Org-mode and Djot subset importers into the
267
- `at-org` and `at-djot` std dialektoi, a DocBook subset
268
- importer into `at-docbook` (`.dbk`); the `at-tei` std dialektos
267
+ table for title levels, hyperlink references with embedded
268
+ URIs as the visible-URL link), Org-mode and Djot subset
269
+ importers into the `at-org` and `at-djot` std dialektoi, a
270
+ DocBook subset importer into `at-docbook` (`.dbk`; quote and
271
+ link included); the `at-tei` std dialektos
269
272
  applies the bibliogramma pattern to TEI — ~15 form sims with
270
273
  the TEI element identity in vocabulary-bound genoses
271
274
  (`@,x,@.persname`), a `tei` exo emitting real TEI XML, and a
272
- litogramma hom giving litogramma TEI export via morph+exo, a BibTeX importer into
275
+ litogramma hom giving litogramma TEI export via morph+exo, a
276
+ BibTeX importer into
273
277
  `bibliogramma` (`.bib`), a JATS subset importer (`.jats`) into
274
278
  litogramma with the ref-list embedded as a bibliogramma
275
279
  englossis — the BibTeX-isomorphic bibliography
276
280
  extension defined beside litogramma (entry lemma = citation
277
- key, genos = entry type, fields as lemma-named sims) — the first *nested* std
281
+ key, genos = entry type, fields as lemma-named sims) — the
282
+ first *nested* std
278
283
  dialektos: one uniform section sim nests, so
279
284
  structure-preserving morphisms to and from litogramma need
280
285
  no flattening — (`.org`: star headings, the emphasis
@@ -9,7 +9,8 @@
9
9
  //! at-markdown models - ATX headings, paragraphs, blockquotes,
10
10
  //! flat list items, fenced code (info string becomes a genos),
11
11
  //! standalone images, emphasis/strong, code spans, backslash
12
- //! escapes.
12
+ //! escapes, and the footnote extension (`[^name]` callouts as
13
+ //! deixes, `[^name]: body` definitions as footnote bodies).
13
14
  //! - HTML into `at-html`: the canonical subset the at-html syntax
14
15
  //! mapper models - h1-h6, p, em, strong, span/div (class maps
15
16
  //! to genoses), blockquote, ul/ol/li, pre>code, inline code,
@@ -142,6 +143,29 @@ fn parse_blocks(lines: &[&str]) -> Result<Vec<Block>> {
142
143
  continue;
143
144
  }
144
145
 
146
+ // Footnote definition `[^name]: body` (the footnote
147
+ // extension); continuation lines indent four spaces.
148
+ if let Some(after) = line.strip_prefix("[^")
149
+ && let Some((name, body)) = after.split_once("]: ")
150
+ && !name.is_empty()
151
+ {
152
+ let (children, next) = item_content(lines, i, body, " ")?;
153
+ blocks.push(Block::Para {
154
+ symbol: "^".to_string(),
155
+ taxis: None,
156
+ lemma: vec![],
157
+ children,
158
+ hypograph: vec![],
159
+ bracket_matching: true,
160
+ ann: Annotations {
161
+ onym: Some(name.to_string()),
162
+ genoses: vec![],
163
+ },
164
+ });
165
+ i = next;
166
+ continue;
167
+ }
168
+
145
169
  // Standalone image: enmedia.
146
170
  if let Some(target) = line
147
171
  .trim_end()
@@ -225,6 +249,39 @@ fn ordered_marker(line: &str) -> Option<(u64, &str)> {
225
249
 
226
250
  /// Parse inline Markdown: code spans, strong, emphasis, backslash
227
251
  /// escapes. Unclosed delimiters fall back to literal text.
252
+ /// The visible-URL link endo: the grammata IS the displayed
253
+ /// target (the link sim's own doctrine). Hidden-href sources
254
+ /// project to prose text with this beside it, pending F9.
255
+ fn link_endo(url: String) -> Inline {
256
+ Inline::Endo {
257
+ symbol: "><".to_string(),
258
+ content: vec![Inline::Text(url)],
259
+ bracket_matching: true,
260
+ ann: Annotations::default(),
261
+ }
262
+ }
263
+
264
+ /// A CommonMark-shaped autolink at `chars[open] == '<'`: an
265
+ /// absolute URI (ASCII-alphabetic scheme, then `:`), no
266
+ /// whitespace or `<` inside, closed by `>`. Returns the URI and
267
+ /// the index past the closing `>`.
268
+ fn autolink_target(chars: &[char], open: usize) -> Option<(String, usize)> {
269
+ let close = chars[open + 1..].iter().position(|&c| c == '>')? + open + 1;
270
+ let inner: String = chars[open + 1..close].iter().collect();
271
+ if inner.is_empty() || inner.chars().any(|c| c.is_whitespace() || c == '<') {
272
+ return None;
273
+ }
274
+ let (scheme, rest) = inner.split_once(':')?;
275
+ let mut sc = scheme.chars();
276
+ if !sc.next().is_some_and(|c| c.is_ascii_alphabetic())
277
+ || !sc.all(|c| c.is_ascii_alphanumeric() || matches!(c, '+' | '.' | '-'))
278
+ || rest.is_empty()
279
+ {
280
+ return None;
281
+ }
282
+ Some((inner, close + 1))
283
+ }
284
+
228
285
  fn parse_inline(text: &str) -> Vec<Inline> {
229
286
  let chars: Vec<char> = text.chars().collect();
230
287
  let mut inlines: Vec<Inline> = Vec::new();
@@ -260,6 +317,61 @@ fn parse_inline(text: &str) -> Vec<Inline> {
260
317
  i = close + 1;
261
318
  continue;
262
319
  }
320
+ // Footnote callout `[^name]` (the footnote extension).
321
+ if c == '['
322
+ && chars.get(i + 1) == Some(&'^')
323
+ && let Some(close) = find(&chars, i + 2, &[']'])
324
+ {
325
+ flush(&mut lit, &mut inlines);
326
+ inlines.push(Inline::Deixis {
327
+ symbol: "^".to_string(),
328
+ onym: chars[i + 2..close].iter().collect(),
329
+ ann: Annotations::default(),
330
+ });
331
+ i = close + 1;
332
+ continue;
333
+ }
334
+ // Autolink `<URL>` — the visible-URL link: the target IS
335
+ // the display, exactly the link sim's shape.
336
+ if c == '<'
337
+ && let Some((url, next)) = autolink_target(&chars, i)
338
+ {
339
+ flush(&mut lit, &mut inlines);
340
+ inlines.push(link_endo(url));
341
+ i = next;
342
+ continue;
343
+ }
344
+ // Inline link `[text](url)`: a hidden href. The faithful
345
+ // form waits on F9; meanwhile the org projection applies —
346
+ // the text stays prose with the visible URL beside it,
347
+ // `text (url)`, and nothing is lost. (An image's `![` is
348
+ // not a link; nested brackets are outside the subset.)
349
+ if c == '['
350
+ && (i == 0 || chars[i - 1] != '!')
351
+ && let Some(close) = find(&chars, i + 1, &[']'])
352
+ && chars.get(close + 1) == Some(&'(')
353
+ && let Some(end) = find(&chars, close + 2, &[')'])
354
+ {
355
+ let text: String = chars[i + 1..close].iter().collect();
356
+ let url: String = chars[close + 2..end]
357
+ .iter()
358
+ .collect::<String>()
359
+ .trim()
360
+ .to_string();
361
+ flush(&mut lit, &mut inlines);
362
+ if url.is_empty() {
363
+ inlines.extend(parse_inline(&text));
364
+ } else if text.trim().is_empty() || text.trim() == url {
365
+ inlines.push(link_endo(url));
366
+ } else {
367
+ inlines.extend(parse_inline(&text));
368
+ inlines.push(Inline::Text(" (".to_string()));
369
+ inlines.push(link_endo(url));
370
+ inlines.push(Inline::Text(")".to_string()));
371
+ }
372
+ i = end + 1;
373
+ continue;
374
+ }
263
375
  // Strong, then emphasis.
264
376
  if c == '*' {
265
377
  let strong = chars.get(i + 1) == Some(&'*');
@@ -862,6 +974,35 @@ fn parse_html_inlines(
862
974
  ann: Annotations::default(),
863
975
  });
864
976
  }
977
+ "a" => {
978
+ // The visible-URL link: an anchor whose text
979
+ // is its target (or none) is the link sim
980
+ // exactly; a hidden href projects as prose
981
+ // text with the visible URL beside it — the
982
+ // org projection, pending F9's faithful form.
983
+ let href = attr(attrs, "href")
984
+ .map(|h| h.trim().to_string())
985
+ .unwrap_or_default();
986
+ let (content, next) = parse_html_inlines(toks, i + 1, name, breaks)?;
987
+ if href.is_empty() {
988
+ inlines.extend(content);
989
+ } else {
990
+ let visible = match content.as_slice() {
991
+ [] => true,
992
+ [Inline::Text(t)] => t.trim() == href,
993
+ _ => false,
994
+ };
995
+ if visible {
996
+ inlines.push(link_endo(href));
997
+ } else {
998
+ inlines.extend(content);
999
+ inlines.push(Inline::Text(" (".to_string()));
1000
+ inlines.push(link_endo(href));
1001
+ inlines.push(Inline::Text(")".to_string()));
1002
+ }
1003
+ }
1004
+ i = next;
1005
+ }
865
1006
  other => {
866
1007
  return Err(html_err(format!("unsupported inline element: `<{other}>`")));
867
1008
  }
@@ -1193,6 +1334,32 @@ fn parse_rst_inline(text: &str) -> Vec<Inline> {
1193
1334
  i = close + 2;
1194
1335
  continue;
1195
1336
  }
1337
+ // Hyperlink reference with embedded URI, `text <url>`_ (or
1338
+ // anonymous, `__). Text equal to the URL, or absent, is the
1339
+ // visible-URL link sim exactly; distinct text projects as
1340
+ // prose with the visible URL beside it, pending F9. Named
1341
+ // references without a URI stay literal, as do bare URLs.
1342
+ if c == '`'
1343
+ && chars.get(i + 1) != Some(&'`')
1344
+ && let Some(close) = find(&chars, i + 1, &['`', '_'])
1345
+ && let Some((text, url)) = rst_embedded_uri(&chars[i + 1..close])
1346
+ {
1347
+ flush(&mut lit, &mut inlines);
1348
+ let text = text.trim();
1349
+ if text.is_empty() || text == url {
1350
+ inlines.push(link_endo(url));
1351
+ } else {
1352
+ inlines.extend(parse_rst_inline(text));
1353
+ inlines.push(Inline::Text(" (".to_string()));
1354
+ inlines.push(link_endo(url));
1355
+ inlines.push(Inline::Text(")".to_string()));
1356
+ }
1357
+ i = close + 2;
1358
+ if chars.get(i) == Some(&'_') {
1359
+ i += 1;
1360
+ }
1361
+ continue;
1362
+ }
1196
1363
  // Strong, then emphasis.
1197
1364
  if c == '*' {
1198
1365
  let strong = chars.get(i + 1) == Some(&'*');
@@ -1239,6 +1406,27 @@ fn parse_rst_inline(text: &str) -> Vec<Inline> {
1239
1406
 
1240
1407
  /// A choice element: prefer the regularized reading
1241
1408
  /// (expan/corr/reg) over the source form (abbr/sic/orig).
1409
+ /// Split the inside of a `` `...`_ `` reference into (text, URI)
1410
+ /// when it carries an embedded URI: `text <uri>` with the angle
1411
+ /// group last and preceded by whitespace (or standing alone). A
1412
+ /// `<name_>` alias, whitespace inside the target, or a stray
1413
+ /// backtick disqualifies it.
1414
+ fn rst_embedded_uri(inner: &[char]) -> Option<(String, String)> {
1415
+ if inner.last() != Some(&'>') || inner.contains(&'`') {
1416
+ return None;
1417
+ }
1418
+ let open = inner.iter().rposition(|&c| c == '<')?;
1419
+ if open > 0 && !inner[open - 1].is_whitespace() {
1420
+ return None;
1421
+ }
1422
+ let url: String = inner[open + 1..inner.len() - 1].iter().collect();
1423
+ if url.is_empty() || url.chars().any(char::is_whitespace) || url.ends_with('_') {
1424
+ return None;
1425
+ }
1426
+ let text: String = inner[..open].iter().collect();
1427
+ Some((text, url))
1428
+ }
1429
+
1242
1430
  fn tei_choice(toks: &[Tok], mut i: usize, notes: &mut usize) -> Result<(Vec<Inline>, usize)> {
1243
1431
  let mut preferred: Vec<Inline> = Vec::new();
1244
1432
  let mut fallback: Vec<Inline> = Vec::new();
@@ -4775,6 +4963,48 @@ fn djot_inlines(text: &str) -> Result<Vec<Inline>> {
4775
4963
  i = end + 1;
4776
4964
  continue;
4777
4965
  }
4966
+ // Autolink `<URL>` — the visible-URL link.
4967
+ if c == '<'
4968
+ && let Some((url, next)) = autolink_target(&chars, i)
4969
+ {
4970
+ flush_plain(&mut plain, &mut inlines);
4971
+ inlines.push(link_endo(url));
4972
+ i = next;
4973
+ continue;
4974
+ }
4975
+ // Inline link `[text](url)`: the org projection, as in
4976
+ // at-markdown (the iso pair reads links identically).
4977
+ if c == '['
4978
+ && (i == 0 || chars[i - 1] != '!')
4979
+ && chars.get(i + 1) != Some(&'^')
4980
+ && let Some(rel) = chars[i + 1..].iter().position(|&ch| ch == ']')
4981
+ {
4982
+ let close = i + 1 + rel;
4983
+ if chars.get(close + 1) == Some(&'(')
4984
+ && let Some(rel2) = chars[close + 2..].iter().position(|&ch| ch == ')')
4985
+ {
4986
+ let end = close + 2 + rel2;
4987
+ let text: String = chars[i + 1..close].iter().collect();
4988
+ let url: String = chars[close + 2..end]
4989
+ .iter()
4990
+ .collect::<String>()
4991
+ .trim()
4992
+ .to_string();
4993
+ flush_plain(&mut plain, &mut inlines);
4994
+ if url.is_empty() {
4995
+ inlines.extend(djot_inlines(&text)?);
4996
+ } else if text.trim().is_empty() || text.trim() == url {
4997
+ inlines.push(link_endo(url));
4998
+ } else {
4999
+ inlines.extend(djot_inlines(&text)?);
5000
+ inlines.push(Inline::Text(" (".to_string()));
5001
+ inlines.push(link_endo(url));
5002
+ inlines.push(Inline::Text(")".to_string()));
5003
+ }
5004
+ i = end + 1;
5005
+ continue;
5006
+ }
5007
+ }
4778
5008
  plain.push(c);
4779
5009
  i += 1;
4780
5010
  }
@@ -4807,7 +5037,17 @@ pub fn docbook_to_document(xml: &str) -> Result<Document> {
4807
5037
  match &toks[i] {
4808
5038
  Tok::Text(t) if t.trim().is_empty() => i += 1,
4809
5039
  Tok::Open { name, .. } if name == "article" || name == "book" || name == "chapter" => {
4810
- let (inner, next) = docbook_blocks(&toks, i + 1, name.clone(), &mut notes)?;
5040
+ let (mut inner, next) = docbook_blocks(&toks, i + 1, name.clone(), &mut notes)?;
5041
+ // The root's leading title (bare, or from <info>)
5042
+ // is the document title, standing alone first.
5043
+ if let Some(content) = docbook_take_title(&mut inner) {
5044
+ blocks.push(Block::Paragraph(vec![Inline::Endo {
5045
+ symbol: "=".to_string(),
5046
+ content,
5047
+ bracket_matching: true,
5048
+ ann: Annotations::default(),
5049
+ }]));
5050
+ }
4811
5051
  blocks.extend(inner);
4812
5052
  i = next;
4813
5053
  }
@@ -4818,6 +5058,7 @@ pub fn docbook_to_document(xml: &str) -> Result<Document> {
4818
5058
  }
4819
5059
  }
4820
5060
  }
5061
+ docbook_settle_titles(&mut blocks);
4821
5062
  Ok(Document {
4822
5063
  dialect_id: "at-docbook".to_string(),
4823
5064
  dialect_version: None,
@@ -4825,6 +5066,50 @@ pub fn docbook_to_document(xml: &str) -> Result<Document> {
4825
5066
  })
4826
5067
  }
4827
5068
 
5069
+ /// The sentinel symbol a `<title>` carries until its container
5070
+ /// claims it (section lemma, document title).
5071
+ const DOCBOOK_TITLE: &str = "\u{0}title";
5072
+
5073
+ /// Take a leading sentinel title paragraph off a block run.
5074
+ fn docbook_take_title(blocks: &mut Vec<Block>) -> Option<Vec<Inline>> {
5075
+ match blocks.first() {
5076
+ Some(Block::Paragraph(inlines))
5077
+ if matches!(inlines.first(),
5078
+ Some(Inline::Endo { symbol, .. }) if symbol == DOCBOOK_TITLE) => {}
5079
+ _ => return None,
5080
+ }
5081
+ let Block::Paragraph(mut inlines) = blocks.remove(0) else {
5082
+ unreachable!()
5083
+ };
5084
+ let Some(Inline::Endo { content, .. }) = inlines.pop() else {
5085
+ unreachable!()
5086
+ };
5087
+ Some(content)
5088
+ }
5089
+
5090
+ /// A `<title>` no container claimed (inside a blockquote, an
5091
+ /// admonition, a list) is a caption: it settles as a plain
5092
+ /// paragraph of its text rather than leaking the sentinel.
5093
+ fn docbook_settle_titles(blocks: &mut [Block]) {
5094
+ for block in blocks.iter_mut() {
5095
+ match block {
5096
+ Block::Paragraph(inlines) => {
5097
+ if let [
5098
+ Inline::Endo {
5099
+ symbol, content, ..
5100
+ },
5101
+ ] = inlines.as_mut_slice()
5102
+ && symbol == DOCBOOK_TITLE
5103
+ {
5104
+ *inlines = std::mem::take(content);
5105
+ }
5106
+ }
5107
+ Block::Para { children, .. } => docbook_settle_titles(children),
5108
+ _ => {}
5109
+ }
5110
+ }
5111
+ }
5112
+
4828
5113
  fn docbook_blocks(
4829
5114
  toks: &[Tok],
4830
5115
  mut i: usize,
@@ -4843,14 +5128,53 @@ fn docbook_blocks(
4843
5128
  )));
4844
5129
  }
4845
5130
  Tok::Open { name, .. } if name == "info" => {
4846
- i = skip_element(toks, i + 1, name.clone())?;
5131
+ // Metadata is skipped, except the title, which
5132
+ // rides the sentinel like a bare <title>.
5133
+ i += 1;
5134
+ loop {
5135
+ match toks.get(i) {
5136
+ None => return Err(docbook_err("unterminated <info>".into())),
5137
+ Some(Tok::Close(name)) if name == "info" => {
5138
+ i += 1;
5139
+ break;
5140
+ }
5141
+ Some(Tok::Open {
5142
+ name, self_closing, ..
5143
+ }) if name == "title" => {
5144
+ if *self_closing {
5145
+ i += 1;
5146
+ continue;
5147
+ }
5148
+ let ((content, inner), next) =
5149
+ docbook_inline_run(toks, i + 1, "title", notes)?;
5150
+ blocks.push(Block::Paragraph(vec![Inline::Endo {
5151
+ symbol: DOCBOOK_TITLE.to_string(),
5152
+ content,
5153
+ bracket_matching: true,
5154
+ ann: Annotations::default(),
5155
+ }]));
5156
+ blocks.extend(inner);
5157
+ i = next;
5158
+ }
5159
+ Some(Tok::Open {
5160
+ name, self_closing, ..
5161
+ }) => {
5162
+ i = if *self_closing {
5163
+ i + 1
5164
+ } else {
5165
+ skip_element(toks, i + 1, name.clone())?
5166
+ };
5167
+ }
5168
+ Some(_) => i += 1,
5169
+ }
5170
+ }
4847
5171
  }
4848
5172
  Tok::Open { name, .. } if name == "title" => {
4849
- // Sentinel-wrapped; the enclosing section
4850
- // promotes it to the lemma.
5173
+ // Sentinel-wrapped; the enclosing section (or the
5174
+ // root) promotes it to the lemma (or the title).
4851
5175
  let ((content, inner), next) = docbook_inline_run(toks, i + 1, "title", notes)?;
4852
5176
  blocks.push(Block::Paragraph(vec![Inline::Endo {
4853
- symbol: "\u{0}title".to_string(),
5177
+ symbol: DOCBOOK_TITLE.to_string(),
4854
5178
  content,
4855
5179
  bracket_matching: true,
4856
5180
  ann: Annotations::default(),
@@ -4863,20 +5187,8 @@ fn docbook_blocks(
4863
5187
  let n = name.clone();
4864
5188
  let (mut children, next) = docbook_blocks(toks, i + 1, n, notes)?;
4865
5189
  // The leading title paragraph becomes the lemma.
4866
- let lemma = match children.first() {
4867
- Some(Block::Paragraph(inlines))
4868
- if matches!(inlines.first(),
4869
- Some(Inline::Endo { symbol, .. }) if symbol == "\u{0}title") =>
4870
- {
4871
- let Some(Block::Paragraph(mut inlines)) = Some(children.remove(0)) else {
4872
- unreachable!()
4873
- };
4874
- let Some(Inline::Endo { content, .. }) = inlines.pop() else {
4875
- unreachable!()
4876
- };
4877
- content
4878
- }
4879
- _ => return Err(docbook_err("section without a title".into())),
5190
+ let Some(lemma) = docbook_take_title(&mut children) else {
5191
+ return Err(docbook_err("section without a title".into()));
4880
5192
  };
4881
5193
  blocks.push(Block::Para {
4882
5194
  symbol: "#".to_string(),
@@ -5094,6 +5406,60 @@ fn docbook_inline_run(
5094
5406
  });
5095
5407
  i = next;
5096
5408
  }
5409
+ Tok::Open { name, .. } if name == "quote" => {
5410
+ let ((content, inner), next) = docbook_inline_run(toks, i + 1, "quote", notes)?;
5411
+ inlines.push(Inline::Endo {
5412
+ symbol: "\"\"".to_string(),
5413
+ content,
5414
+ bracket_matching: true,
5415
+ ann: Annotations::default(),
5416
+ });
5417
+ bodies.extend(inner);
5418
+ i = next;
5419
+ }
5420
+ Tok::Open {
5421
+ name,
5422
+ attrs,
5423
+ self_closing,
5424
+ ..
5425
+ } if name == "link" || name == "ulink" => {
5426
+ // The visible-URL link: a DocBook 5 xlink:href (or
5427
+ // DocBook 4 ulink url) whose text is its target, or
5428
+ // none, is the link sim exactly; a hidden href
5429
+ // projects as prose text with the visible URL beside
5430
+ // it — the html projection, pending F9's faithful
5431
+ // form. An internal linkend has no URL: prose only.
5432
+ let url = attr(attrs, "xlink:href")
5433
+ .or_else(|| attr(attrs, "url"))
5434
+ .map(|u| u.trim().to_string())
5435
+ .unwrap_or_default();
5436
+ let (content, next) = if *self_closing {
5437
+ (Vec::new(), i + 1)
5438
+ } else {
5439
+ let n = name.clone();
5440
+ let ((content, inner), next) = docbook_inline_run(toks, i + 1, &n, notes)?;
5441
+ bodies.extend(inner);
5442
+ (content, next)
5443
+ };
5444
+ if url.is_empty() {
5445
+ inlines.extend(content);
5446
+ } else {
5447
+ let visible = match content.as_slice() {
5448
+ [] => true,
5449
+ [Inline::Text(t)] => t.trim() == url,
5450
+ _ => false,
5451
+ };
5452
+ if visible {
5453
+ inlines.push(link_endo(url));
5454
+ } else {
5455
+ inlines.extend(content);
5456
+ inlines.push(Inline::Text(" (".to_string()));
5457
+ inlines.push(link_endo(url));
5458
+ inlines.push(Inline::Text(")".to_string()));
5459
+ }
5460
+ }
5461
+ i = next;
5462
+ }
5097
5463
  other => return Err(docbook_err(format!("unsupported {other:?} inline"))),
5098
5464
  }
5099
5465
  }
@@ -8,3 +8,5 @@
8
8
 
9
9
  @:: _ *
10
10
  @:: * **
11
+ @:: >< ><
12
+ @:: ^ ^