panache-cli 3.4.0__tar.gz → 3.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.
Files changed (322) hide show
  1. {panache_cli-3.4.0 → panache_cli-3.5.0}/Cargo.lock +12 -11
  2. {panache_cli-3.4.0 → panache_cli-3.5.0}/Cargo.toml +4 -3
  3. {panache_cli-3.4.0 → panache_cli-3.5.0}/PKG-INFO +1 -1
  4. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/CHANGELOG.md +13 -0
  5. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/Cargo.toml +2 -2
  6. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/config.rs +3 -0
  7. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/core.rs +82 -84
  8. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/headings.rs +16 -4
  9. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/inline.rs +3 -1
  10. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/inline_layout.rs +1 -1
  11. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/lists.rs +12 -7
  12. panache_cli-3.5.0/crates/panache-formatter/src/formatter/preserve.rs +103 -0
  13. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter.rs +1 -0
  14. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/utils.rs +47 -2
  15. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/CHANGELOG.md +31 -0
  16. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/Cargo.toml +1 -1
  17. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/lib.rs +3 -1
  18. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/options.rs +41 -0
  19. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/pandoc_ast.rs +200 -36
  20. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/block_dispatcher.rs +15 -8
  21. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/blockquotes.rs +3 -2
  22. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/container_prefix.rs +17 -0
  23. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/headings.rs +376 -101
  24. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/horizontal_rules.rs +22 -0
  25. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/metadata.rs +133 -21
  26. panache_cli-3.5.0/crates/panache-parser/src/parser/blocks/tests/fragment_context.rs +154 -0
  27. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/headings.rs +186 -0
  28. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/losslessness.rs +3 -1
  29. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks.rs +2 -0
  30. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/core.rs +73 -5
  31. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/code_spans.rs +3 -2
  32. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/core.rs +85 -36
  33. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/escapes.rs +15 -2
  34. panache_cli-3.5.0/crates/panache-parser/src/parser/inlines/hard_breaks.rs +102 -0
  35. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/inline_executable.rs +3 -2
  36. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/inline_ir.rs +33 -24
  37. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/raw_inline.rs +3 -2
  38. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/sink.rs +2 -1
  39. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/tests.rs +182 -1
  40. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines.rs +2 -0
  41. panache_cli-3.5.0/crates/panache-parser/src/parser/reparse.rs +3971 -0
  42. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/attributes.rs +56 -2
  43. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/helpers.rs +29 -0
  44. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/validator.rs +55 -73
  45. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml.rs +1 -0
  46. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/cache.rs +6 -4
  47. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/config.rs +3 -3
  48. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/formatter.rs +1 -0
  49. panache_cli-3.5.0/src/io_context.rs +126 -0
  50. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/undefined_anchor.rs +16 -0
  51. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/context.rs +2 -1
  52. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/conversions.rs +84 -27
  53. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/dispatch.rs +27 -7
  54. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/documents.rs +93 -53
  55. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/global_state.rs +116 -7
  56. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/diagnostics.rs +19 -10
  57. panache_cli-3.5.0/src/lsp/line_index.rs +942 -0
  58. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/testing.rs +77 -2
  59. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp.rs +12 -1
  60. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/main.rs +54 -41
  61. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/parser.rs +3 -1
  62. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/salsa.rs +145 -33
  63. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/utils.rs +21 -1
  64. panache_cli-3.4.0/crates/panache-parser/src/parser/reparse.rs +0 -2041
  65. panache_cli-3.4.0/src/lsp/line_index.rs +0 -341
  66. {panache_cli-3.4.0 → panache_cli-3.5.0}/LICENSE +0 -0
  67. {panache_cli-3.4.0 → panache_cli-3.5.0}/README.md +0 -0
  68. {panache_cli-3.4.0 → panache_cli-3.5.0}/assets/quarto-schema/schema.json +0 -0
  69. {panache_cli-3.4.0 → panache_cli-3.5.0}/build.rs +0 -0
  70. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/README.md +0 -0
  71. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/directives.rs +0 -0
  72. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/blockquotes.rs +0 -0
  73. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/code_blocks.rs +0 -0
  74. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/fenced_divs.rs +0 -0
  75. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/hashpipe.rs +0 -0
  76. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/indent_utils.rs +0 -0
  77. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/math/STYLE.md +0 -0
  78. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/math/linebreak.rs +0 -0
  79. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/math/operators.rs +0 -0
  80. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/math/render.rs +0 -0
  81. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/math.rs +0 -0
  82. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/metadata.rs +0 -0
  83. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/paragraphs.rs +0 -0
  84. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/sentence_wrap.rs +0 -0
  85. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/shortcodes.rs +0 -0
  86. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/smart.rs +0 -0
  87. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/tables.rs +0 -0
  88. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/utils.rs +0 -0
  89. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/STYLE.md +0 -0
  90. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/block_map.rs +0 -0
  91. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/block_sequence.rs +0 -0
  92. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/document.rs +0 -0
  93. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/flow.rs +0 -0
  94. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/options.rs +0 -0
  95. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml/scalar.rs +0 -0
  96. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/formatter/yaml.rs +0 -0
  97. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/lib.rs +0 -0
  98. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/parser.rs +0 -0
  99. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/syntax.rs +0 -0
  100. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-formatter/src/yaml_engine.rs +0 -0
  101. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/README.md +0 -0
  102. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/build.rs +0 -0
  103. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/grid_layout.rs +0 -0
  104. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/admonitions.rs +0 -0
  105. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/code_blocks.rs +0 -0
  106. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/definition_lists.rs +0 -0
  107. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/fenced_divs.rs +0 -0
  108. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/figures.rs +0 -0
  109. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/html_blocks.rs +0 -0
  110. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/indented_code.rs +0 -0
  111. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/latex_envs.rs +0 -0
  112. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/line_blocks.rs +0 -0
  113. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/lists.rs +0 -0
  114. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/myst_directives.rs +0 -0
  115. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/myst_targets.rs +0 -0
  116. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/paragraphs.rs +0 -0
  117. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/raw_blocks.rs +0 -0
  118. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/reference_links.rs +0 -0
  119. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tables.rs +0 -0
  120. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/blanklines.rs +0 -0
  121. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/blockquotes.rs +0 -0
  122. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/code_blocks.rs +0 -0
  123. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/content_containers.rs +0 -0
  124. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/definition_lists.rs +0 -0
  125. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/figures.rs +0 -0
  126. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/footnote_marker_line.rs +0 -0
  127. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/frame_pinning.rs +0 -0
  128. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/helpers.rs +0 -0
  129. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/lists.rs +0 -0
  130. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/metadata_guards.rs +0 -0
  131. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/blocks/tests/tables.rs +0 -0
  132. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/diagnostics.rs +0 -0
  133. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/bookdown.rs +0 -0
  134. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/bracketed_spans.rs +0 -0
  135. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/citations.rs +0 -0
  136. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/emoji.rs +0 -0
  137. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/inline_footnotes.rs +0 -0
  138. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/inline_html.rs +0 -0
  139. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/latex.rs +0 -0
  140. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/links.rs +0 -0
  141. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/mark.rs +0 -0
  142. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/math.rs +0 -0
  143. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/myst_roles.rs +0 -0
  144. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/myst_substitutions.rs +0 -0
  145. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/native_spans.rs +0 -0
  146. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/refdef_map.rs +0 -0
  147. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/shortcodes.rs +0 -0
  148. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/strikeout.rs +0 -0
  149. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/subscript.rs +0 -0
  150. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/superscript.rs +0 -0
  151. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/svelte.rs +0 -0
  152. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/uri-schemes.csv +0 -0
  153. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/inlines/wikilinks.rs +0 -0
  154. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/math.rs +0 -0
  155. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/chunk_options.rs +0 -0
  156. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/container_stack.rs +0 -0
  157. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/continuation.rs +0 -0
  158. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/inline_emission.rs +0 -0
  159. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/list_item_buffer.rs +0 -0
  160. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/marker_utils.rs +0 -0
  161. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/text_buffer.rs +0 -0
  162. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/tree_copy.rs +0 -0
  163. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils/yaml_regions.rs +0 -0
  164. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/utils.rs +0 -0
  165. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/verify.rs +0 -0
  166. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/cooking.rs +0 -0
  167. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/events.rs +0 -0
  168. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/model.rs +0 -0
  169. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/parser.rs +0 -0
  170. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/profile.rs +0 -0
  171. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser/yaml/scanner.rs +0 -0
  172. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/parser.rs +0 -0
  173. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/range_utils.rs +0 -0
  174. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/alerts.rs +0 -0
  175. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/ast.rs +0 -0
  176. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/attributes.rs +0 -0
  177. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/block_quotes.rs +0 -0
  178. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/blocks.rs +0 -0
  179. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/chunk_options.rs +0 -0
  180. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/citations.rs +0 -0
  181. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/code_blocks.rs +0 -0
  182. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/code_span.rs +0 -0
  183. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/crossrefs.rs +0 -0
  184. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/definitions.rs +0 -0
  185. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/fenced_divs.rs +0 -0
  186. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/headings.rs +0 -0
  187. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/inlines.rs +0 -0
  188. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/kind.rs +0 -0
  189. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/links.rs +0 -0
  190. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/lists.rs +0 -0
  191. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/math.rs +0 -0
  192. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/myst.rs +0 -0
  193. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/raw_tex.rs +0 -0
  194. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/references.rs +0 -0
  195. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/shortcodes.rs +0 -0
  196. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/tables.rs +0 -0
  197. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/yaml.rs +0 -0
  198. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax/yaml_ast.rs +0 -0
  199. {panache_cli-3.4.0 → panache_cli-3.5.0}/crates/panache-parser/src/syntax.rs +0 -0
  200. {panache_cli-3.4.0 → panache_cli-3.5.0}/pyproject.toml +0 -0
  201. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/bibtex.rs +0 -0
  202. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/csl_json.rs +0 -0
  203. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/csl_yaml.rs +0 -0
  204. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/index.rs +0 -0
  205. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/preview.rs +0 -0
  206. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib/ris.rs +0 -0
  207. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bib.rs +0 -0
  208. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/bin/distill_quarto_schema.rs +0 -0
  209. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/cli.rs +0 -0
  210. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/config/formatter_presets.rs +0 -0
  211. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/config/types/schema_helpers.rs +0 -0
  212. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/config/types.rs +0 -0
  213. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/diagnostic_renderer.rs +0 -0
  214. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/directives.rs +0 -0
  215. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/external_formatters_common.rs +0 -0
  216. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/external_formatters_sync.rs +0 -0
  217. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/external_tools_common.rs +0 -0
  218. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/includes.rs +0 -0
  219. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/incremental.rs +0 -0
  220. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lib.rs +0 -0
  221. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/code_block_collector.rs +0 -0
  222. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/diagnostics.rs +0 -0
  223. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/clippy.rs +0 -0
  224. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/eslint.rs +0 -0
  225. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/jarl.rs +0 -0
  226. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/jolars.rs +0 -0
  227. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/ruff.rs +0 -0
  228. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/shellcheck.rs +0 -0
  229. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters/staticcheck.rs +0 -0
  230. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters.rs +0 -0
  231. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/external_linters_sync.rs +0 -0
  232. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/fuzzy.rs +0 -0
  233. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/index.rs +0 -0
  234. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/metadata_diagnostics.rs +0 -0
  235. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/offsets.rs +0 -0
  236. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/project_index.rs +0 -0
  237. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema/distill.rs +0 -0
  238. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema/interp.rs +0 -0
  239. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema/model.rs +0 -0
  240. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema/report.rs +0 -0
  241. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema/value.rs +0 -0
  242. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/quarto_schema.rs +0 -0
  243. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/adjacent_footnote_refs.rs +0 -0
  244. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/chunk_label_spaces.rs +0 -0
  245. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/citation_keys.rs +0 -0
  246. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/citation_nonbreaking_space.rs +0 -0
  247. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/consumer_divergence.rs +0 -0
  248. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/crossref_as_link_target.rs +0 -0
  249. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/duplicate_references.rs +0 -0
  250. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/duplicate_yaml_anchor.rs +0 -0
  251. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/emoji_aliases.rs +0 -0
  252. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/empty_list_item.rs +0 -0
  253. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/empty_values.rs +0 -0
  254. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/figure_crossref_captions.rs +0 -0
  255. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/footnote_after_image.rs +0 -0
  256. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/footnote_ref_in_footnote_def.rs +0 -0
  257. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/footnote_swallowed_by_bracket.rs +0 -0
  258. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/heading_eaten_attrs.rs +0 -0
  259. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/heading_hierarchy.rs +0 -0
  260. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/heading_strip_comments_residue.rs +0 -0
  261. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/html_entities.rs +0 -0
  262. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/link_text_is_url.rs +0 -0
  263. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/math_content.rs +0 -0
  264. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/missing_chunk_labels.rs +0 -0
  265. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/quarto_schema.rs +0 -0
  266. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/reversed_footnote_marker.rs +0 -0
  267. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/stray_fenced_div_markers.rs +0 -0
  268. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/swallowed_list_marker.rs +0 -0
  269. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/table_column_count.rs +0 -0
  270. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/undefined_references.rs +0 -0
  271. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/unspaced_citation.rs +0 -0
  272. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/unsupported_metadata_key.rs +0 -0
  273. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/unused_definitions.rs +0 -0
  274. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules/unused_yaml_anchor.rs +0 -0
  275. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/rules.rs +0 -0
  276. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/runner.rs +0 -0
  277. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/yaml_anchors.rs +0 -0
  278. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter/yaml_resolve.rs +0 -0
  279. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/linter.rs +0 -0
  280. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/config.rs +0 -0
  281. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/code_actions.rs +0 -0
  282. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/completion.rs +0 -0
  283. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/configuration.rs +0 -0
  284. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/document_highlight.rs +0 -0
  285. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/document_links.rs +0 -0
  286. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/document_symbols.rs +0 -0
  287. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/file_operations.rs +0 -0
  288. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/file_rename.rs +0 -0
  289. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/file_watcher.rs +0 -0
  290. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/folding_ranges.rs +0 -0
  291. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/footnote_conversion.rs +0 -0
  292. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/formatting.rs +0 -0
  293. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/goto_definition.rs +0 -0
  294. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/heading_link_conversion.rs +0 -0
  295. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/hover.rs +0 -0
  296. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/link_conversion.rs +0 -0
  297. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/linked_editing_range.rs +0 -0
  298. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/list_conversion.rs +0 -0
  299. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/prepare_rename.rs +0 -0
  300. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/references.rs +0 -0
  301. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/rename.rs +0 -0
  302. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/semantic_tokens.rs +0 -0
  303. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/shortcode_args.rs +0 -0
  304. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/workspace_folders.rs +0 -0
  305. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers/workspace_symbols.rs +0 -0
  306. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/handlers.rs +0 -0
  307. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/helpers.rs +0 -0
  308. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/navigation.rs +0 -0
  309. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/symbols.rs +0 -0
  310. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/task_pool.rs +0 -0
  311. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/lsp/uri_ext.rs +0 -0
  312. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata/bibliography.rs +0 -0
  313. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata/citations.rs +0 -0
  314. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata/project.rs +0 -0
  315. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata/references.rs +0 -0
  316. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata/yaml.rs +0 -0
  317. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/metadata.rs +0 -0
  318. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/range_utils.rs +0 -0
  319. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/syntax.rs +0 -0
  320. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/vfs.rs +0 -0
  321. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/yaml_engine.rs +0 -0
  322. {panache_cli-3.4.0 → panache_cli-3.5.0}/src/yaml_regions.rs +0 -0
@@ -992,9 +992,9 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
992
992
 
993
993
  [[package]]
994
994
  name = "libredox"
995
- version = "0.1.19"
995
+ version = "0.1.20"
996
996
  source = "registry+https://github.com/rust-lang/crates.io-index"
997
- checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa"
997
+ checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a"
998
998
  dependencies = [
999
999
  "libc",
1000
1000
  ]
@@ -1203,7 +1203,7 @@ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
1203
1203
 
1204
1204
  [[package]]
1205
1205
  name = "panache"
1206
- version = "3.4.0"
1206
+ version = "3.5.0"
1207
1207
  dependencies = [
1208
1208
  "annotate-snippets",
1209
1209
  "assert_cmd",
@@ -1223,6 +1223,7 @@ dependencies = [
1223
1223
  "log",
1224
1224
  "lsp-server",
1225
1225
  "lsp-types",
1226
+ "memchr",
1226
1227
  "num_cpus",
1227
1228
  "panache-formatter",
1228
1229
  "panache-parser",
@@ -1235,7 +1236,7 @@ dependencies = [
1235
1236
  "schemars",
1236
1237
  "serde",
1237
1238
  "serde_json",
1238
- "similar 3.1.2",
1239
+ "similar 3.2.0",
1239
1240
  "similar-asserts",
1240
1241
  "tempfile",
1241
1242
  "toml",
@@ -1247,7 +1248,7 @@ dependencies = [
1247
1248
 
1248
1249
  [[package]]
1249
1250
  name = "panache-formatter"
1250
- version = "0.21.0"
1251
+ version = "0.21.1"
1251
1252
  dependencies = [
1252
1253
  "insta",
1253
1254
  "log",
@@ -1265,7 +1266,7 @@ dependencies = [
1265
1266
 
1266
1267
  [[package]]
1267
1268
  name = "panache-parser"
1268
- version = "0.26.0"
1269
+ version = "0.27.0"
1269
1270
  dependencies = [
1270
1271
  "entities",
1271
1272
  "insta",
@@ -1791,9 +1792,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
1791
1792
 
1792
1793
  [[package]]
1793
1794
  name = "similar"
1794
- version = "3.1.2"
1795
+ version = "3.2.0"
1795
1796
  source = "registry+https://github.com/rust-lang/crates.io-index"
1796
- checksum = "85ee016af5d736b69fc89e19254540fa4b5f5492853fb5503920f084011c78b6"
1797
+ checksum = "4f66ca1f7aca2474dc10c942eb22feffc897735f54cd1db90138c2fddb490987"
1797
1798
  dependencies = [
1798
1799
  "bstr",
1799
1800
  "unicode-segmentation",
@@ -1806,7 +1807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1806
1807
  checksum = "997e6ca38e97437973fc9f7f50a50d1274cacd874341a4960fea90067291038c"
1807
1808
  dependencies = [
1808
1809
  "console",
1809
- "similar 3.1.2",
1810
+ "similar 3.2.0",
1810
1811
  ]
1811
1812
 
1812
1813
  [[package]]
@@ -2062,9 +2063,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
2062
2063
 
2063
2064
  [[package]]
2064
2065
  name = "uuid"
2065
- version = "1.24.0"
2066
+ version = "1.24.1"
2066
2067
  source = "registry+https://github.com/rust-lang/crates.io-index"
2067
- checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
2068
+ checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9"
2068
2069
  dependencies = [
2069
2070
  "getrandom 0.4.3",
2070
2071
  "js-sys",
@@ -10,7 +10,7 @@ authors = ["Johan Larsson <johan@jolars.co>"]
10
10
 
11
11
  [package]
12
12
  name = "panache"
13
- version = "3.4.0"
13
+ version = "3.5.0"
14
14
  edition.workspace = true
15
15
  rust-version.workspace = true
16
16
  # `distill_quarto_schema` is a dev-only vendoring bin (src/bin/); keep bare
@@ -52,8 +52,8 @@ path = "src/main.rs"
52
52
  required-features = ["cli"]
53
53
 
54
54
  [dependencies]
55
- panache-formatter = { path = "crates/panache-formatter", version = "0.21.0" }
56
- panache-parser = { path = "crates/panache-parser", version = "0.26.0", features = [
55
+ panache-formatter = { path = "crates/panache-formatter", version = "0.21.1" }
56
+ panache-parser = { path = "crates/panache-parser", version = "0.27.0", features = [
57
57
  "serde",
58
58
  "schema",
59
59
  ] }
@@ -69,6 +69,7 @@ ignore = { version = "0.4.29", optional = true }
69
69
  log = { version = "0.4.31", features = ["release_max_level_debug"] }
70
70
  lsp-server = { version = "0.10.0", optional = true }
71
71
  lsp-types = { version = "0.97.0", optional = true }
72
+ memchr = "2.8.3"
72
73
  num_cpus = { version = "1.17.0", optional = true }
73
74
  percent-encoding = { version = "2.3.2", optional = true }
74
75
  regex = "1.12.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panache-cli
3
- Version: 3.4.0
3
+ Version: 3.5.0
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.21.1](https://github.com/jolars/panache/compare/panache-formatter-v0.21.0...panache-formatter-v0.21.1) (2026-08-17)
4
+
5
+ ### Bug Fixes
6
+ - **parser:** anchor yaml metadata delimiters at column 0 ([`55e3999`](https://github.com/jolars/panache/commit/55e3999730d4987bc37f369733ed0f420d9e6c40))
7
+ - gate heading auto-ids on `auto_identifiers` ([`efd4ae0`](https://github.com/jolars/panache/commit/efd4ae053acdad06f0f559ffdff803fd77348bf8))
8
+ - **formatter:** stop trimming heading content hashes ([`cee2dbf`](https://github.com/jolars/panache/commit/cee2dbfe3efa3a240b838aa5dbd4e1f2dba3d1d6))
9
+ - **formatter:** keep a load-bearing heading `#` run ([`be48179`](https://github.com/jolars/panache/commit/be481798358fc2722da2a3dbb1241bdb4d27bb80))
10
+ - **parser:** fold whitespace into a backslash line break ([`eaf42a0`](https://github.com/jolars/panache/commit/eaf42a00e77fe3bfda14a01e1568605f5b9c2785))
11
+ - **formatter:** drop trailing whitespace under `wrap = preserve` ([`d3fdd9f`](https://github.com/jolars/panache/commit/d3fdd9fc1e259112462709cbad91e3135010eb63)), closes [#496](https://github.com/jolars/panache/issues/496)
12
+
13
+ ### Dependencies
14
+ - updated crates/panache-parser to v0.27.0
15
+
3
16
  ## [0.21.0](https://github.com/jolars/panache/compare/panache-formatter-v0.20.5...panache-formatter-v0.21.0) (2026-08-14)
4
17
 
5
18
  ### Features
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "panache-formatter"
3
- version = "0.21.0"
3
+ version = "0.21.1"
4
4
  edition.workspace = true
5
5
  rust-version.workspace = true
6
6
  include = [
@@ -19,7 +19,7 @@ keywords = ["quarto", "pandoc", "markdown", "formatter"]
19
19
  categories = ["text-processing"]
20
20
 
21
21
  [dependencies]
22
- panache-parser = { path = "../panache-parser", version = "0.26.0" }
22
+ panache-parser = { path = "../panache-parser", version = "0.27.0" }
23
23
  log = { version = "0.4.31", features = ["release_max_level_debug"] }
24
24
  rowan = "0.17.0"
25
25
  serde = { version = "1.0.228", features = ["derive"], optional = true }
@@ -98,6 +98,7 @@ pub enum BlankLines {
98
98
 
99
99
  #[derive(Debug, Clone, PartialEq)]
100
100
  pub struct FormatterExtensions {
101
+ pub auto_identifiers: bool,
101
102
  pub blank_before_header: bool,
102
103
  pub bookdown_references: bool,
103
104
  pub east_asian_line_breaks: bool,
@@ -120,6 +121,7 @@ impl FormatterExtensions {
120
121
  let smart_default = matches!(flavor, Flavor::Pandoc | Flavor::Quarto | Flavor::RMarkdown);
121
122
 
122
123
  Self {
124
+ auto_identifiers: parser_defaults.auto_identifiers,
123
125
  blank_before_header: parser_defaults.blank_before_header,
124
126
  bookdown_references: parser_defaults.bookdown_references,
125
127
  east_asian_line_breaks: parser_defaults.east_asian_line_breaks,
@@ -177,6 +179,7 @@ macro_rules! known_formatter_extensions {
177
179
  }
178
180
 
179
181
  known_formatter_extensions! {
182
+ "auto-identifiers" => auto_identifiers,
180
183
  "blank-before-header" => blank_before_header,
181
184
  "bookdown-references" => bookdown_references,
182
185
  "east-asian-line-breaks" => east_asian_line_breaks,
@@ -14,6 +14,7 @@ use super::headings;
14
14
  use super::inline;
15
15
  use super::inline_layout;
16
16
  use super::paragraphs;
17
+ use super::preserve::{preserve_lines, preserve_lines_unprefixed};
17
18
  use super::smart::normalize_smart_punctuation;
18
19
  use super::tables;
19
20
  use super::utils::{is_block_element, is_structural_block};
@@ -1041,19 +1042,20 @@ impl Formatter {
1041
1042
  let available_width =
1042
1043
  self.config.line_width.saturating_sub(child_indent);
1043
1044
  let lines = match wrap_mode {
1044
- WrapMode::Preserve => child
1045
- .text()
1045
+ WrapMode::Preserve => preserve_lines(
1046
+ child,
1047
+ self.config.formatter_extensions.escaped_line_breaks,
1048
+ )
1049
+ .iter()
1050
+ .map(|line| {
1051
+ normalize_smart_punctuation(
1052
+ line.trim_start_matches([' ', '\t']),
1053
+ self.config.formatter_extensions.smart,
1054
+ self.config.formatter_extensions.smart_quotes,
1055
+ )
1046
1056
  .to_string()
1047
- .lines()
1048
- .map(|line| {
1049
- normalize_smart_punctuation(
1050
- line.trim_start_matches([' ', '\t']),
1051
- self.config.formatter_extensions.smart,
1052
- self.config.formatter_extensions.smart_quotes,
1053
- )
1054
- .to_string()
1055
- })
1056
- .collect(),
1057
+ })
1058
+ .collect(),
1057
1059
  WrapMode::Reflow => {
1058
1060
  self.wrapped_lines_for_paragraph(child, available_width)
1059
1061
  }
@@ -1148,19 +1150,20 @@ impl Formatter {
1148
1150
  self.config.line_width.saturating_sub(child_indent);
1149
1151
  let widths = [first_line_space, available_width];
1150
1152
  let lines = match wrap_mode {
1151
- WrapMode::Preserve => {
1152
- let text = child.text().to_string();
1153
- text.lines()
1154
- .map(|line| {
1155
- normalize_smart_punctuation(
1156
- line,
1157
- self.config.formatter_extensions.smart,
1158
- self.config.formatter_extensions.smart_quotes,
1159
- )
1160
- .to_string()
1161
- })
1162
- .collect()
1163
- }
1153
+ WrapMode::Preserve => preserve_lines(
1154
+ child,
1155
+ self.config.formatter_extensions.escaped_line_breaks,
1156
+ )
1157
+ .iter()
1158
+ .map(|line| {
1159
+ normalize_smart_punctuation(
1160
+ line,
1161
+ self.config.formatter_extensions.smart,
1162
+ self.config.formatter_extensions.smart_quotes,
1163
+ )
1164
+ .to_string()
1165
+ })
1166
+ .collect(),
1164
1167
  WrapMode::Reflow => {
1165
1168
  self.wrapped_lines_for_paragraph_with_widths(child, &widths)
1166
1169
  }
@@ -1229,8 +1232,9 @@ impl Formatter {
1229
1232
 
1230
1233
  match wrap_mode {
1231
1234
  WrapMode::Preserve => {
1232
- let text = child.text().to_string();
1233
- for line in text.lines() {
1235
+ let escaped =
1236
+ self.config.formatter_extensions.escaped_line_breaks;
1237
+ for line in preserve_lines(child, escaped) {
1234
1238
  self.output.push_str(&" ".repeat(child_indent));
1235
1239
  self.output.push_str(
1236
1240
  normalize_smart_punctuation(
@@ -1500,28 +1504,21 @@ impl Formatter {
1500
1504
  let para_start = self.output.len();
1501
1505
  match wrap_mode {
1502
1506
  WrapMode::Preserve => {
1503
- // Build paragraph text while skipping BlockQuoteMarker tokens
1504
- // (they're in the tree for losslessness but we add prefixes dynamically)
1505
- let mut lines_text = String::new();
1506
- for item in child.children_with_tokens() {
1507
- match item {
1508
- NodeOrToken::Token(t)
1509
- if t.kind() == SyntaxKind::LINE_PREFIX =>
1510
- {
1511
- // Container prefix — re-added dynamically.
1512
- }
1513
- NodeOrToken::Token(t) => {
1514
- lines_text.push_str(t.text());
1515
- }
1516
- NodeOrToken::Node(n) => {
1517
- lines_text.push_str(&n.text().to_string());
1518
- }
1507
+ // We write `content_prefix` on every line
1508
+ // ourselves, so the tree's own LINE_PREFIX
1509
+ // tokens have to come back out.
1510
+ let escaped =
1511
+ self.config.formatter_extensions.escaped_line_breaks;
1512
+ for line in preserve_lines_unprefixed(child, escaped) {
1513
+ // An empty quoted line takes the bare
1514
+ // marker, so the prefix does not become
1515
+ // trailing whitespace itself.
1516
+ if line.is_empty() {
1517
+ self.output.push_str(content_prefix.trim_end());
1518
+ } else {
1519
+ self.output.push_str(&content_prefix);
1520
+ self.output.push_str(&line);
1519
1521
  }
1520
- }
1521
-
1522
- for line in lines_text.lines() {
1523
- self.output.push_str(&content_prefix);
1524
- self.output.push_str(line);
1525
1522
  self.output.push('\n');
1526
1523
  }
1527
1524
  }
@@ -1566,10 +1563,17 @@ impl Formatter {
1566
1563
  match alert_child.kind() {
1567
1564
  SyntaxKind::PARAGRAPH => match wrap_mode {
1568
1565
  WrapMode::Preserve => {
1569
- let text = alert_child.text().to_string();
1570
- for line in text.lines() {
1571
- self.output.push_str(&content_prefix);
1572
- self.output.push_str(line);
1566
+ let escaped = self
1567
+ .config
1568
+ .formatter_extensions
1569
+ .escaped_line_breaks;
1570
+ for line in preserve_lines(&alert_child, escaped) {
1571
+ if line.is_empty() {
1572
+ self.output.push_str(content_prefix.trim_end());
1573
+ } else {
1574
+ self.output.push_str(&content_prefix);
1575
+ self.output.push_str(&line);
1576
+ }
1573
1577
  self.output.push('\n');
1574
1578
  }
1575
1579
  }
@@ -1952,25 +1956,17 @@ impl Formatter {
1952
1956
  match wrap_mode {
1953
1957
  WrapMode::Preserve => {
1954
1958
  log::trace!("Preserving paragraph line breaks");
1955
- if indent > 0 {
1956
- for (i, line) in text.lines().enumerate() {
1957
- if i > 0 {
1958
- self.output.push('\n');
1959
- }
1959
+ let escaped = self.config.formatter_extensions.escaped_line_breaks;
1960
+ for (i, line) in preserve_lines(node, escaped).iter().enumerate() {
1961
+ if i > 0 {
1962
+ self.output.push('\n');
1963
+ }
1964
+ if indent > 0 {
1960
1965
  self.output.push_str(&paragraph_indent);
1961
- self.output.push_str(
1962
- normalize_smart_punctuation(
1963
- line.trim_start(),
1964
- self.config.formatter_extensions.smart,
1965
- self.config.formatter_extensions.smart_quotes,
1966
- )
1967
- .as_ref(),
1968
- );
1969
1966
  }
1970
- } else {
1971
1967
  self.output.push_str(
1972
1968
  normalize_smart_punctuation(
1973
- &text,
1969
+ if indent > 0 { line.trim_start() } else { line },
1974
1970
  self.config.formatter_extensions.smart,
1975
1971
  self.config.formatter_extensions.smart_quotes,
1976
1972
  )
@@ -2051,32 +2047,32 @@ impl Formatter {
2051
2047
  && !self.output.ends_with(": ");
2052
2048
  match wrap_mode {
2053
2049
  WrapMode::Preserve => {
2054
- if needs_indent {
2055
- for line in text.lines() {
2050
+ let escaped = self.config.formatter_extensions.escaped_line_breaks;
2051
+ for (i, line) in preserve_lines(node, escaped).iter().enumerate() {
2052
+ if needs_indent {
2056
2053
  self.output.push_str(&" ".repeat(indent));
2057
- self.output.push_str(
2058
- normalize_smart_punctuation(
2059
- line.trim_start(),
2060
- self.config.formatter_extensions.smart,
2061
- self.config.formatter_extensions.smart_quotes,
2062
- )
2063
- .as_ref(),
2064
- );
2054
+ } else if i > 0 {
2065
2055
  self.output.push('\n');
2066
2056
  }
2067
- } else {
2068
2057
  self.output.push_str(
2069
2058
  normalize_smart_punctuation(
2070
- &text,
2059
+ if needs_indent {
2060
+ line.trim_start()
2061
+ } else {
2062
+ line
2063
+ },
2071
2064
  self.config.formatter_extensions.smart,
2072
2065
  self.config.formatter_extensions.smart_quotes,
2073
2066
  )
2074
2067
  .as_ref(),
2075
2068
  );
2076
- if !self.output.ends_with('\n') {
2069
+ if needs_indent {
2077
2070
  self.output.push('\n');
2078
2071
  }
2079
2072
  }
2073
+ if !self.output.ends_with('\n') {
2074
+ self.output.push('\n');
2075
+ }
2080
2076
  }
2081
2077
  WrapMode::Reflow => {
2082
2078
  log::trace!("Reflowing Plain block to {} width", line_width);
@@ -2545,10 +2541,12 @@ impl Formatter {
2545
2541
  let widths = [first_line_space, available_width];
2546
2542
 
2547
2543
  let lines = match wrap_mode {
2548
- WrapMode::Preserve => {
2549
- let text = n.text().to_string();
2550
- text.lines().map(|line| line.to_string()).collect()
2551
- }
2544
+ WrapMode::Preserve => preserve_lines(
2545
+ n,
2546
+ self.config
2547
+ .formatter_extensions
2548
+ .escaped_line_breaks,
2549
+ ),
2552
2550
  WrapMode::Reflow => self
2553
2551
  .wrapped_lines_for_paragraph_with_widths(
2554
2552
  n, &widths,
@@ -1,3 +1,4 @@
1
+ use panache_parser::parser::blocks::headings::content_reads_as_decoration;
1
2
  use rowan::NodeOrToken;
2
3
 
3
4
  use super::core::normalize_attribute_text;
@@ -65,16 +66,27 @@ pub(super) fn format_heading(node: &SyntaxNode, config: &Config) -> String {
65
66
  }
66
67
  }
67
68
 
68
- // Trim trailing closing hashes and surrounding whitespace (`# Title #`).
69
- let content = content
70
- .trim_end_matches(|c: char| c == '#' || c.is_whitespace())
71
- .trim_start();
69
+ // The parser splits the closing run off into its own marker token, so
70
+ // whatever is left is content; only surrounding whitespace goes.
71
+ let content = content.trim();
72
72
 
73
73
  let mut out = "#".repeat(level);
74
74
  if !content.is_empty() {
75
75
  out.push(' ');
76
76
  out.push_str(content);
77
77
  }
78
+ // A closing run is decoration and normally dropped --- except when it is
79
+ // load-bearing, i.e. when the content it leaves in front of the line ending
80
+ // would read back as decoration itself. pandoc reads a heading's attribute
81
+ // block only *after* the run, so the run is what keeps a trailing `{...}`
82
+ // in the content out of the attributes: `# foo {#id} #` is `Header 1
83
+ // (foo-id) [Str "foo", Space, Str "{#id}"]`, and dropping the run would
84
+ // rewrite the id to `id`. A content hash at the end of the line is the same
85
+ // story one level down: the `#` in `# foo # #` is content, but alone on the
86
+ // line it closes the heading instead.
87
+ if content_reads_as_decoration(content, &config.parser_options()) {
88
+ out.push_str(" #");
89
+ }
78
90
  if !attributes.is_empty() {
79
91
  out.push(' ');
80
92
  out.push_str(&attributes);
@@ -657,7 +657,9 @@ pub(super) fn format_inline_node(node: &SyntaxNode, config: &Config) -> String {
657
657
  if config.formatter_extensions.escaped_line_breaks {
658
658
  "\\\n".to_string()
659
659
  } else {
660
- node.text().to_string()
660
+ let text = node.text().to_string();
661
+ let ending = text.find(['\r', '\n']).map_or("", |at| &text[at..]);
662
+ format!("{}{ending}", crate::utils::hard_break_marker(&text))
661
663
  }
662
664
  }
663
665
  SyntaxKind::NONBREAKING_SPACE => "\\ ".to_string(),
@@ -965,7 +965,7 @@ fn process_node_recursive(
965
965
  let marker = if config.formatter_extensions.escaped_line_breaks {
966
966
  "\\"
967
967
  } else {
968
- t.text().trim_end_matches(['\r', '\n'])
968
+ crate::utils::hard_break_marker(t.text())
969
969
  };
970
970
  sink.push_hard_line_break(marker);
971
971
  }
@@ -7,6 +7,7 @@ use panache_parser::parser::blocks::definition_lists::try_parse_definition_marke
7
7
  use rowan::NodeOrToken;
8
8
 
9
9
  use super::Formatter;
10
+ use super::preserve;
10
11
 
11
12
  impl Formatter {
12
13
  fn is_marker_only_blockquote_continuation(node: &SyntaxNode) -> bool {
@@ -247,7 +248,6 @@ impl Formatter {
247
248
  /// Format a paragraph that is a continuation of a list item.
248
249
  /// Strips existing indentation from the text and applies the correct list item indentation.
249
250
  pub(super) fn format_list_continuation_paragraph(&mut self, node: &SyntaxNode, indent: usize) {
250
- let text = node.text().to_string();
251
251
  let line_width = self.config.line_width.saturating_sub(indent);
252
252
  let wrap_mode = self.config.wrap.clone().unwrap_or(WrapMode::Reflow);
253
253
  // This arm emits the paragraph's lines itself rather than going through
@@ -257,7 +257,8 @@ impl Formatter {
257
257
  match wrap_mode {
258
258
  WrapMode::Preserve => {
259
259
  // Strip existing indentation and apply list item indentation
260
- for line in text.lines() {
260
+ let escaped = self.config.formatter_extensions.escaped_line_breaks;
261
+ for line in preserve::preserve_lines(node, escaped) {
261
262
  self.output.push_str(&" ".repeat(indent));
262
263
  self.output.push_str(line.trim_start());
263
264
  self.output.push('\n');
@@ -1004,12 +1005,16 @@ impl Formatter {
1004
1005
 
1005
1006
  let preserve_lines = match wrap_mode {
1006
1007
  WrapMode::Preserve => {
1007
- let source = content_node
1008
- .as_ref()
1009
- .map(|content| content.text().to_string())
1010
- .unwrap_or_default();
1011
- Some(source.lines().map(ToString::to_string).collect::<Vec<_>>())
1008
+ let escaped = self.config.formatter_extensions.escaped_line_breaks;
1009
+ Some(
1010
+ content_node
1011
+ .as_ref()
1012
+ .map(|content| preserve::preserve_lines(content, escaped))
1013
+ .unwrap_or_default(),
1014
+ )
1012
1015
  }
1016
+ // A format-off directive means "leave these bytes alone", trailing
1017
+ // whitespace included, so this path deliberately does not trim.
1013
1018
  _ if content_has_format_directive => {
1014
1019
  let source = content_node
1015
1020
  .as_ref()
@@ -0,0 +1,103 @@
1
+ //! Line emission for `wrap = preserve`.
2
+ //!
3
+ //! Every other wrap mode re-renders inlines and so drops the padding at the
4
+ //! end of a source line as a side effect of rebuilding it. Preserve mode
5
+ //! copies bytes instead, which is what keeps the line breaks intact -- but it
6
+ //! also carried the trailing whitespace straight into the output (issue #496).
7
+ //! This module is the one place that turns a block's tokens into preserve-mode
8
+ //! lines, so the two concerns stay separated: line breaks preserved, padding
9
+ //! dropped.
10
+
11
+ use crate::syntax::{SyntaxKind, SyntaxNode};
12
+ use rowan::NodeOrToken;
13
+
14
+ /// Split a block into the lines `wrap = preserve` should emit, with trailing
15
+ /// whitespace removed and hard breaks normalized.
16
+ ///
17
+ /// Only `NEWLINE` and `HARD_LINE_BREAK` tokens end a line. Newlines inside
18
+ /// verbatim constructs never reach us as either kind -- a code span keeps its
19
+ /// whole body in one `INLINE_CODE_CONTENT` token, math uses `MATH_NEWLINE`, and
20
+ /// inline HTML uses `WHITESPACE` -- so their bytes are copied untouched and
21
+ /// this stays a prose-only trim.
22
+ ///
23
+ /// A trailing run that genuinely *is* a hard break becomes `\` when
24
+ /// `escaped_line_breaks` is on, matching what the inline formatter emits for
25
+ /// every other wrap mode. Otherwise the original whitespace run is kept, since
26
+ /// it is the only thing carrying the break.
27
+ ///
28
+ /// Container `LINE_PREFIX` tokens are kept, since most callers emit the
29
+ /// block's own source indentation. Callers that rebuild the prefix themselves
30
+ /// want [`preserve_lines_unprefixed`] instead.
31
+ pub(super) fn preserve_lines(node: &SyntaxNode, escaped_line_breaks: bool) -> Vec<String> {
32
+ lines_with_prefix(node, escaped_line_breaks, LinePrefix::Keep)
33
+ }
34
+
35
+ /// Like [`preserve_lines`], but drops the container `LINE_PREFIX` tokens. They
36
+ /// are in the tree for losslessness; a caller that writes its own prefix on
37
+ /// every line would otherwise emit them twice.
38
+ pub(super) fn preserve_lines_unprefixed(
39
+ node: &SyntaxNode,
40
+ escaped_line_breaks: bool,
41
+ ) -> Vec<String> {
42
+ lines_with_prefix(node, escaped_line_breaks, LinePrefix::Drop)
43
+ }
44
+
45
+ #[derive(Clone, Copy, PartialEq)]
46
+ enum LinePrefix {
47
+ Keep,
48
+ Drop,
49
+ }
50
+
51
+ fn lines_with_prefix(
52
+ node: &SyntaxNode,
53
+ escaped_line_breaks: bool,
54
+ prefix: LinePrefix,
55
+ ) -> Vec<String> {
56
+ let mut lines = Vec::new();
57
+ let mut current = String::new();
58
+ collect(node, escaped_line_breaks, prefix, &mut lines, &mut current);
59
+
60
+ // Mirror `str::lines`: a block ending in a newline has no empty final line.
61
+ if !current.is_empty() {
62
+ lines.push(trim_padding(&current));
63
+ }
64
+ lines
65
+ }
66
+
67
+ fn collect(
68
+ node: &SyntaxNode,
69
+ escaped_line_breaks: bool,
70
+ prefix: LinePrefix,
71
+ lines: &mut Vec<String>,
72
+ current: &mut String,
73
+ ) {
74
+ for item in node.children_with_tokens() {
75
+ match item {
76
+ NodeOrToken::Node(child) => {
77
+ collect(&child, escaped_line_breaks, prefix, lines, current)
78
+ }
79
+ NodeOrToken::Token(token) => match token.kind() {
80
+ SyntaxKind::LINE_PREFIX if prefix == LinePrefix::Drop => {}
81
+ SyntaxKind::NEWLINE => {
82
+ lines.push(trim_padding(current));
83
+ current.clear();
84
+ }
85
+ SyntaxKind::HARD_LINE_BREAK => {
86
+ if escaped_line_breaks {
87
+ current.push('\\');
88
+ } else {
89
+ current.push_str(crate::utils::hard_break_marker(token.text()));
90
+ }
91
+ lines.push(std::mem::take(current));
92
+ }
93
+ _ => current.push_str(token.text()),
94
+ },
95
+ }
96
+ }
97
+ }
98
+
99
+ /// Trim only ASCII spaces and tabs. `str::trim_end` would also eat a
100
+ /// non-breaking space, which is content.
101
+ fn trim_padding(line: &str) -> String {
102
+ line.trim_end_matches([' ', '\t']).to_string()
103
+ }
@@ -13,6 +13,7 @@ mod inline_layout;
13
13
  mod lists;
14
14
  mod metadata;
15
15
  mod paragraphs;
16
+ mod preserve;
16
17
  mod sentence_wrap;
17
18
  mod shortcodes;
18
19
  mod smart;