panache-cli 3.7.0__tar.gz → 3.8.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 (337) hide show
  1. {panache_cli-3.7.0 → panache_cli-3.8.0}/Cargo.lock +7 -7
  2. {panache_cli-3.7.0 → panache_cli-3.8.0}/Cargo.toml +3 -3
  3. {panache_cli-3.7.0 → panache_cli-3.8.0}/PKG-INFO +1 -1
  4. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/CHANGELOG.md +13 -0
  5. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/Cargo.toml +2 -2
  6. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/inline.rs +4 -3
  7. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math/STYLE.md +19 -10
  8. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math/ir.rs +8 -1
  9. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math/lower.rs +6 -1
  10. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math/printer.rs +55 -11
  11. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math/render.rs +8 -21
  12. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/math.rs +49 -4
  13. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/CHANGELOG.md +5 -0
  14. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/Cargo.toml +1 -1
  15. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/math.rs +63 -27
  16. panache_cli-3.8.0/src/linter/rules/blank_line_in_display_math.rs +169 -0
  17. panache_cli-3.8.0/src/linter/rules/inline_math_line_break.rs +111 -0
  18. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/math_content.rs +15 -0
  19. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules.rs +5 -0
  20. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter.rs +2 -0
  21. {panache_cli-3.7.0 → panache_cli-3.8.0}/LICENSE +0 -0
  22. {panache_cli-3.7.0 → panache_cli-3.8.0}/README.md +0 -0
  23. {panache_cli-3.7.0 → panache_cli-3.8.0}/assets/quarto-schema/schema.json +0 -0
  24. {panache_cli-3.7.0 → panache_cli-3.8.0}/build.rs +0 -0
  25. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/README.md +0 -0
  26. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/config.rs +0 -0
  27. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/directives.rs +0 -0
  28. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/blockquotes.rs +0 -0
  29. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/blocks.rs +0 -0
  30. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/code_blocks.rs +0 -0
  31. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/containers.rs +0 -0
  32. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/core.rs +0 -0
  33. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/document.rs +0 -0
  34. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/fenced_divs.rs +0 -0
  35. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/hashpipe.rs +0 -0
  36. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/headings.rs +0 -0
  37. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/indent_utils.rs +0 -0
  38. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/inline_layout.rs +0 -0
  39. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/lists.rs +0 -0
  40. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/metadata.rs +0 -0
  41. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/paragraphs.rs +0 -0
  42. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/preserve.rs +0 -0
  43. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/raw.rs +0 -0
  44. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/sentence_wrap.rs +0 -0
  45. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/shortcodes.rs +0 -0
  46. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/smart.rs +0 -0
  47. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/tables.rs +0 -0
  48. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/utils.rs +0 -0
  49. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/STYLE.md +0 -0
  50. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/block_map.rs +0 -0
  51. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/block_sequence.rs +0 -0
  52. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/document.rs +0 -0
  53. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/flow.rs +0 -0
  54. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/options.rs +0 -0
  55. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml/scalar.rs +0 -0
  56. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter/yaml.rs +0 -0
  57. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/formatter.rs +0 -0
  58. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/lib.rs +0 -0
  59. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/parser.rs +0 -0
  60. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/syntax.rs +0 -0
  61. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/utils.rs +0 -0
  62. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-formatter/src/yaml_engine.rs +0 -0
  63. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/README.md +0 -0
  64. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/build.rs +0 -0
  65. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/data/math_symbols.json +0 -0
  66. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/data/unicode-math.LICENSE +0 -0
  67. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/data/unicode-math.NOTICE +0 -0
  68. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/grid_layout.rs +0 -0
  69. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/lib.rs +0 -0
  70. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/options.rs +0 -0
  71. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/pandoc_ast.rs +0 -0
  72. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/block_dispatcher.rs +0 -0
  73. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/admonitions.rs +0 -0
  74. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/blockquotes.rs +0 -0
  75. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/code_blocks.rs +0 -0
  76. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/container_prefix.rs +0 -0
  77. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/definition_lists.rs +0 -0
  78. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/fenced_divs.rs +0 -0
  79. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/figures.rs +0 -0
  80. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/headings.rs +0 -0
  81. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/horizontal_rules.rs +0 -0
  82. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/html_blocks.rs +0 -0
  83. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/indented_code.rs +0 -0
  84. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/latex_envs.rs +0 -0
  85. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/line_blocks.rs +0 -0
  86. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/lists.rs +0 -0
  87. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/metadata.rs +0 -0
  88. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/myst_directives.rs +0 -0
  89. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/myst_targets.rs +0 -0
  90. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/paragraphs.rs +0 -0
  91. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/raw_blocks.rs +0 -0
  92. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/reference_links.rs +0 -0
  93. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tables.rs +0 -0
  94. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/blanklines.rs +0 -0
  95. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/blockquotes.rs +0 -0
  96. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/code_blocks.rs +0 -0
  97. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/content_containers.rs +0 -0
  98. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/definition_lists.rs +0 -0
  99. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/figures.rs +0 -0
  100. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/footnote_marker_line.rs +0 -0
  101. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/fragment_context.rs +0 -0
  102. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/frame_pinning.rs +0 -0
  103. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/headings.rs +0 -0
  104. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/helpers.rs +0 -0
  105. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/lists.rs +0 -0
  106. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/losslessness.rs +0 -0
  107. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/metadata_guards.rs +0 -0
  108. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks/tests/tables.rs +0 -0
  109. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/blocks.rs +0 -0
  110. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/core/blockquotes.rs +0 -0
  111. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/core/definition_lists.rs +0 -0
  112. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/core/html_interruptions.rs +0 -0
  113. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/core/list_items.rs +0 -0
  114. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/core.rs +0 -0
  115. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/diagnostics.rs +0 -0
  116. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/bookdown.rs +0 -0
  117. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/bracketed_spans.rs +0 -0
  118. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/citations.rs +0 -0
  119. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/code_spans.rs +0 -0
  120. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/core.rs +0 -0
  121. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/emoji.rs +0 -0
  122. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/escapes.rs +0 -0
  123. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/hard_breaks.rs +0 -0
  124. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/inline_executable.rs +0 -0
  125. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/inline_footnotes.rs +0 -0
  126. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/inline_html.rs +0 -0
  127. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/inline_ir.rs +0 -0
  128. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/latex.rs +0 -0
  129. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/links.rs +0 -0
  130. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/mark.rs +0 -0
  131. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/math.rs +0 -0
  132. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/myst_roles.rs +0 -0
  133. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/myst_substitutions.rs +0 -0
  134. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/native_spans.rs +0 -0
  135. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/raw_inline.rs +0 -0
  136. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/refdef_map.rs +0 -0
  137. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/shortcodes.rs +0 -0
  138. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/sink.rs +0 -0
  139. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/strikeout.rs +0 -0
  140. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/subscript.rs +0 -0
  141. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/superscript.rs +0 -0
  142. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/svelte.rs +0 -0
  143. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/tests.rs +0 -0
  144. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/uri-schemes.csv +0 -0
  145. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines/wikilinks.rs +0 -0
  146. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/inlines.rs +0 -0
  147. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/math.rs +0 -0
  148. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/reparse.rs +0 -0
  149. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/attributes.rs +0 -0
  150. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/chunk_options.rs +0 -0
  151. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/container_stack.rs +0 -0
  152. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/continuation.rs +0 -0
  153. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/helpers.rs +0 -0
  154. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/inline_emission.rs +0 -0
  155. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/list_item_buffer.rs +0 -0
  156. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/marker_utils.rs +0 -0
  157. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/text_buffer.rs +0 -0
  158. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/tree_copy.rs +0 -0
  159. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils/yaml_regions.rs +0 -0
  160. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/utils.rs +0 -0
  161. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/verify.rs +0 -0
  162. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/cooking.rs +0 -0
  163. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/events.rs +0 -0
  164. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/model.rs +0 -0
  165. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/parser.rs +0 -0
  166. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/profile.rs +0 -0
  167. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/scanner.rs +0 -0
  168. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml/validator.rs +0 -0
  169. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser/yaml.rs +0 -0
  170. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/parser.rs +0 -0
  171. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/range_utils.rs +0 -0
  172. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/semantic/math.rs +0 -0
  173. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/semantic.rs +0 -0
  174. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/alerts.rs +0 -0
  175. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/ast.rs +0 -0
  176. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/attributes.rs +0 -0
  177. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/block_quotes.rs +0 -0
  178. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/blocks.rs +0 -0
  179. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/chunk_options.rs +0 -0
  180. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/citations.rs +0 -0
  181. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/code_blocks.rs +0 -0
  182. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/code_span.rs +0 -0
  183. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/crossrefs.rs +0 -0
  184. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/definitions.rs +0 -0
  185. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/fenced_divs.rs +0 -0
  186. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/headings.rs +0 -0
  187. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/inlines.rs +0 -0
  188. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/kind.rs +0 -0
  189. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/links.rs +0 -0
  190. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/lists.rs +0 -0
  191. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/myst.rs +0 -0
  192. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/raw_tex.rs +0 -0
  193. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/references.rs +0 -0
  194. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/shortcodes.rs +0 -0
  195. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/tables.rs +0 -0
  196. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/yaml.rs +0 -0
  197. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax/yaml_ast.rs +0 -0
  198. {panache_cli-3.7.0 → panache_cli-3.8.0}/crates/panache-parser/src/syntax.rs +0 -0
  199. {panache_cli-3.7.0 → panache_cli-3.8.0}/pyproject.toml +0 -0
  200. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/bibtex.rs +0 -0
  201. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/csl_json.rs +0 -0
  202. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/csl_yaml.rs +0 -0
  203. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/index.rs +0 -0
  204. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/preview.rs +0 -0
  205. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib/ris.rs +0 -0
  206. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bib.rs +0 -0
  207. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/bin/distill_quarto_schema.rs +0 -0
  208. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/cache.rs +0 -0
  209. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/cli.rs +0 -0
  210. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/config/formatter_presets.rs +0 -0
  211. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/config/types/schema_helpers.rs +0 -0
  212. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/config/types.rs +0 -0
  213. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/config.rs +0 -0
  214. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/diagnostic_renderer.rs +0 -0
  215. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/directives.rs +0 -0
  216. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/external_formatters_common.rs +0 -0
  217. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/external_formatters_sync.rs +0 -0
  218. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/external_tools_common.rs +0 -0
  219. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/formatter.rs +0 -0
  220. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/includes.rs +0 -0
  221. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/incremental.rs +0 -0
  222. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/io_context.rs +0 -0
  223. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lib.rs +0 -0
  224. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/code_block_collector.rs +0 -0
  225. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/diagnostics.rs +0 -0
  226. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/clippy.rs +0 -0
  227. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/eslint.rs +0 -0
  228. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/jarl.rs +0 -0
  229. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/jolars.rs +0 -0
  230. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/ruff.rs +0 -0
  231. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/shellcheck.rs +0 -0
  232. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters/staticcheck.rs +0 -0
  233. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters.rs +0 -0
  234. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/external_linters_sync.rs +0 -0
  235. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/fuzzy.rs +0 -0
  236. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/index.rs +0 -0
  237. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/metadata_diagnostics.rs +0 -0
  238. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/offsets.rs +0 -0
  239. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/project_index.rs +0 -0
  240. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema/distill.rs +0 -0
  241. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema/interp.rs +0 -0
  242. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema/model.rs +0 -0
  243. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema/report.rs +0 -0
  244. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema/value.rs +0 -0
  245. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/quarto_schema.rs +0 -0
  246. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/adjacent_footnote_refs.rs +0 -0
  247. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/blank_line_in_inline_footnote.rs +0 -0
  248. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/chunk_label_spaces.rs +0 -0
  249. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/citation_keys.rs +0 -0
  250. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/citation_nonbreaking_space.rs +0 -0
  251. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/consumer_divergence.rs +0 -0
  252. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/crossref_as_link_target.rs +0 -0
  253. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/duplicate_references.rs +0 -0
  254. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/duplicate_yaml_anchor.rs +0 -0
  255. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/emoji_aliases.rs +0 -0
  256. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/empty_list_item.rs +0 -0
  257. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/empty_values.rs +0 -0
  258. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/figure_crossref_captions.rs +0 -0
  259. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/footnote_after_image.rs +0 -0
  260. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/footnote_ref_in_footnote_def.rs +0 -0
  261. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/footnote_swallowed_by_bracket.rs +0 -0
  262. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/heading_eaten_attrs.rs +0 -0
  263. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/heading_hierarchy.rs +0 -0
  264. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/heading_strip_comments_residue.rs +0 -0
  265. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/html_entities.rs +0 -0
  266. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/link_text_is_url.rs +0 -0
  267. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/missing_chunk_labels.rs +0 -0
  268. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/quarto_schema.rs +0 -0
  269. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/reversed_footnote_marker.rs +0 -0
  270. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/stray_fenced_div_markers.rs +0 -0
  271. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/swallowed_list_marker.rs +0 -0
  272. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/table_column_count.rs +0 -0
  273. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/undefined_anchor.rs +0 -0
  274. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/undefined_references.rs +0 -0
  275. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/unspaced_citation.rs +0 -0
  276. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/unsupported_metadata_key.rs +0 -0
  277. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/unused_definitions.rs +0 -0
  278. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/rules/unused_yaml_anchor.rs +0 -0
  279. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/runner.rs +0 -0
  280. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/yaml_anchors.rs +0 -0
  281. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/linter/yaml_resolve.rs +0 -0
  282. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/config.rs +0 -0
  283. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/context.rs +0 -0
  284. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/conversions.rs +0 -0
  285. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/dispatch.rs +0 -0
  286. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/documents.rs +0 -0
  287. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/global_state.rs +0 -0
  288. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/code_actions.rs +0 -0
  289. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/completion.rs +0 -0
  290. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/configuration.rs +0 -0
  291. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/diagnostics.rs +0 -0
  292. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/document_highlight.rs +0 -0
  293. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/document_links.rs +0 -0
  294. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/document_symbols.rs +0 -0
  295. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/file_operations.rs +0 -0
  296. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/file_rename.rs +0 -0
  297. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/file_watcher.rs +0 -0
  298. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/folding_ranges.rs +0 -0
  299. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/footnote_conversion.rs +0 -0
  300. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/formatting.rs +0 -0
  301. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/goto_definition.rs +0 -0
  302. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/heading_link_conversion.rs +0 -0
  303. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/hover.rs +0 -0
  304. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/link_conversion.rs +0 -0
  305. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/linked_editing_range.rs +0 -0
  306. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/list_conversion.rs +0 -0
  307. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/prepare_rename.rs +0 -0
  308. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/references.rs +0 -0
  309. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/rename.rs +0 -0
  310. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/semantic_tokens.rs +0 -0
  311. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/shortcode_args.rs +0 -0
  312. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/workspace_folders.rs +0 -0
  313. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers/workspace_symbols.rs +0 -0
  314. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/handlers.rs +0 -0
  315. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/helpers.rs +0 -0
  316. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/line_index.rs +0 -0
  317. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/navigation.rs +0 -0
  318. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/symbols.rs +0 -0
  319. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/task_pool.rs +0 -0
  320. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/testing.rs +0 -0
  321. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp/uri_ext.rs +0 -0
  322. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/lsp.rs +0 -0
  323. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/main.rs +0 -0
  324. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata/bibliography.rs +0 -0
  325. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata/citations.rs +0 -0
  326. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata/project.rs +0 -0
  327. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata/references.rs +0 -0
  328. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata/yaml.rs +0 -0
  329. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/metadata.rs +0 -0
  330. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/parser.rs +0 -0
  331. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/range_utils.rs +0 -0
  332. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/salsa.rs +0 -0
  333. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/syntax.rs +0 -0
  334. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/utils.rs +0 -0
  335. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/vfs.rs +0 -0
  336. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/yaml_engine.rs +0 -0
  337. {panache_cli-3.7.0 → panache_cli-3.8.0}/src/yaml_regions.rs +0 -0
@@ -746,9 +746,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
746
746
 
747
747
  [[package]]
748
748
  name = "hermit-abi"
749
- version = "0.5.2"
749
+ version = "0.5.3"
750
750
  source = "registry+https://github.com/rust-lang/crates.io-index"
751
- checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
751
+ checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
752
752
 
753
753
  [[package]]
754
754
  name = "icu_collections"
@@ -878,9 +878,9 @@ dependencies = [
878
878
 
879
879
  [[package]]
880
880
  name = "indexmap"
881
- version = "2.14.0"
881
+ version = "2.14.1"
882
882
  source = "registry+https://github.com/rust-lang/crates.io-index"
883
- checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
883
+ checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb"
884
884
  dependencies = [
885
885
  "equivalent",
886
886
  "hashbrown 0.17.1",
@@ -1250,7 +1250,7 @@ checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
1250
1250
 
1251
1251
  [[package]]
1252
1252
  name = "panache"
1253
- version = "3.7.0"
1253
+ version = "3.8.0"
1254
1254
  dependencies = [
1255
1255
  "annotate-snippets",
1256
1256
  "assert_cmd",
@@ -1295,7 +1295,7 @@ dependencies = [
1295
1295
 
1296
1296
  [[package]]
1297
1297
  name = "panache-formatter"
1298
- version = "0.22.0"
1298
+ version = "0.23.0"
1299
1299
  dependencies = [
1300
1300
  "badness-formatter",
1301
1301
  "insta",
@@ -1315,7 +1315,7 @@ dependencies = [
1315
1315
 
1316
1316
  [[package]]
1317
1317
  name = "panache-parser"
1318
- version = "0.28.0"
1318
+ version = "0.28.1"
1319
1319
  dependencies = [
1320
1320
  "badness-parser",
1321
1321
  "entities",
@@ -9,7 +9,7 @@ authors = ["Johan Larsson <johan@jolars.co>"]
9
9
 
10
10
  [package]
11
11
  name = "panache"
12
- version = "3.7.0"
12
+ version = "3.8.0"
13
13
  edition.workspace = true
14
14
  rust-version.workspace = true
15
15
  # `distill_quarto_schema` is a dev-only vendoring bin (src/bin/); keep bare
@@ -51,11 +51,11 @@ path = "src/main.rs"
51
51
  required-features = ["cli"]
52
52
 
53
53
  [dependencies]
54
- panache-formatter = { path = "crates/panache-formatter", version = "0.22.0", features = [
54
+ panache-formatter = { path = "crates/panache-formatter", version = "0.23.0", features = [
55
55
  "serde",
56
56
  "schema",
57
57
  ] }
58
- panache-parser = { path = "crates/panache-parser", version = "0.28.0", features = [
58
+ panache-parser = { path = "crates/panache-parser", version = "0.28.1", features = [
59
59
  "serde",
60
60
  "schema",
61
61
  ] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: panache-cli
3
- Version: 3.7.0
3
+ Version: 3.8.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.23.0](https://github.com/jolars/panache/compare/panache-formatter-v0.22.0...panache-formatter-v0.23.0) (2026-08-31)
4
+
5
+ ### Features
6
+ - **math:** indent top-level environments ([`f222d44`](https://github.com/jolars/panache/commit/f222d448d74a53eb0d939108e244d560c9fc0e2e))
7
+
8
+ ### Bug Fixes
9
+ - **formatter:** preserve math control spaces at line ends ([`b449e66`](https://github.com/jolars/panache/commit/b449e662644835ae8b62db99afa000e47be281ec))
10
+ - **formatter:** preserve math control spaces ([`85dd96f`](https://github.com/jolars/panache/commit/85dd96f72ae3d924b2efde5c46baa8c70f7a2f60)), fixes [#522](https://github.com/jolars/panache/issues/522)
11
+ - **formatter:** preserve control spaces in math rows ([`2c2e24f`](https://github.com/jolars/panache/commit/2c2e24fc087a6697f4f985d70c5e4478975cddb2)), fixes [#521](https://github.com/jolars/panache/issues/521)
12
+
13
+ ### Dependencies
14
+ - updated crates/panache-parser to v0.28.1
15
+
3
16
  ## [0.22.0](https://github.com/jolars/panache/compare/panache-formatter-v0.21.3...panache-formatter-v0.22.0) (2026-08-28)
4
17
 
5
18
  ### Features
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "panache-formatter"
3
- version = "0.22.0"
3
+ version = "0.23.0"
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.28.0" }
22
+ panache-parser = { path = "../panache-parser", version = "0.28.1" }
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 }
@@ -456,7 +456,7 @@ pub(super) fn format_inline_node(node: &SyntaxNode, config: &Config) -> String {
456
456
  None => format!(
457
457
  "{}\n{}\n{}",
458
458
  open,
459
- math::trim_trailing_whitespace_per_line(content.trim()),
459
+ math::trim_preserved_math_body(&content),
460
460
  close,
461
461
  ),
462
462
  }
@@ -533,7 +533,8 @@ pub(super) fn format_inline_node(node: &SyntaxNode, config: &Config) -> String {
533
533
  math::push_body_with_trailing_newline(&mut result, &body);
534
534
  }
535
535
  None => {
536
- let mut trimmed_content = content.trim_end();
536
+ let cleaned_content = math::trim_trailing_whitespace_per_line(&content);
537
+ let mut trimmed_content = cleaned_content.trim_end_matches(['\r', '\n']);
537
538
  while let Some((first, rest)) = trimmed_content.split_once('\n') {
538
539
  if first.trim().is_empty() {
539
540
  trimmed_content = rest;
@@ -558,7 +559,7 @@ pub(super) fn format_inline_node(node: &SyntaxNode, config: &Config) -> String {
558
559
  };
559
560
  if !stripped.is_empty() {
560
561
  result.push_str(&pad);
561
- result.push_str(stripped.trim_end_matches([' ', '\t']));
562
+ result.push_str(stripped);
562
563
  }
563
564
  result.push('\n');
564
565
  }
@@ -48,14 +48,12 @@ Text-domain, unknown, unmatched, over-attached, and document-redefined command
48
48
  arguments are opaque preservation islands when the surrounding expression can
49
49
  still be lowered safely; they do not automatically preserve the whole span. The
50
50
  host's preserved-body path removes ASCII spaces and tabs immediately before a
51
- line ending. This line hygiene does not otherwise normalize or reflow the
52
- preserved content.
51
+ line ending, except for the semantic ASCII space in the TeX control symbol `\ `.
52
+ This line hygiene does not otherwise normalize or reflow the preserved content.
53
53
 
54
54
  ## Intentional Badness differences
55
55
 
56
56
  - Markdown inline hosts join layout lines unless a TeX comment pins the break.
57
- - Standalone display environments own their indentation; `math_indent` is not
58
- applied around their markers.
59
57
  - A soft newline before a signature-proven argument collapses as insignificant
60
58
  whitespace.
61
59
  - Panache applies both sides of the TeXbook Bin-to-Ord rule: it tightens
@@ -67,6 +65,9 @@ preserved content.
67
65
  - Panache preserves scripted composite relations such as `<=_i`, `>=_i`, and
68
66
  `==_i`; the pinned formatter incorrectly separates the relation head from its
69
67
  CST-separated script.
68
+ - Panache retains an authored environment-row boundary after a standalone TeX
69
+ control space. The pinned formatter moves the control space onto the next row;
70
+ Panache keeps the semantic space at the physical line end.
70
71
 
71
72
  ## Rules
72
73
 
@@ -97,9 +98,11 @@ preserved content.
97
98
 
98
99
  3. **Environment layout.** A standalone `\begin{name}` and `\end{name}` each go
99
100
  on their own line at the environment's indent. The body is indented **one
100
- level (2 spaces) deeper**, accumulating for nested environments.
101
- `math_indent` does **not** apply inside standalone environments; their
102
- two-space body indent is a fixed part of the stable style.
101
+ level (2 spaces) deeper**, accumulating for nested environments. An
102
+ environment inside a Markdown display-math host inherits `math_indent` around
103
+ its markers, then adds the fixed two-space body indent. A raw standalone TeX
104
+ environment has no Markdown host indent; its body still uses the same fixed
105
+ two-space step.
103
106
 
104
107
  Signature-declared environment arguments remain attached to the opening
105
108
  marker. In particular, `array`'s optional position and required column
@@ -191,9 +194,11 @@ preserved content.
191
194
  **source character counts**, so alignment is cosmetic source-tidiness, not
192
195
  rendered-glyph alignment (`\alpha` counts as 6).
193
196
 
194
- Every math-body line ends without trailing ASCII spaces or tabs. The printer
195
- and preserved-body host paths enforce this invariant; alignment padding may
196
- appear before a `\\` marker, but never at the physical line end.
197
+ Every math-body line ends without layout-generated ASCII spaces or tabs. The
198
+ printer and preserved-body host paths enforce this invariant; alignment
199
+ padding may appear before a `\\` marker, but never at the physical line end.
200
+ The semantic ASCII space in the TeX control symbol `\ ` is the sole exception
201
+ and survives even when that token ends a physical line.
197
202
 
198
203
  A grid cell containing one comment-bearing group, signature-proven argument,
199
204
  braced script, or `\left`/`\right` body uses the typed comment layout from
@@ -339,6 +344,10 @@ preserved content.
339
344
  `+`/`-` is `Ord` and never a break site. Typed lowering keeps the semantic
340
345
  atom stream intact across continuation segments, so a leading binary
341
346
  operator stays binary instead of coercing to a sign.
347
+ - **Semantic control spaces survive breaks.** The math IR represents `\ `
348
+ separately from layout padding. An authored or selected line ending after
349
+ that token retains its ASCII space, while any formatter-generated padding
350
+ after it is removed.
342
351
  - **A logical row is one equation.** Free rows split into logical rows only
343
352
  on a top-level hard `\\`; a soft newline is insignificant whitespace and
344
353
  does **not** start a new row, so a multi-line authored equation (and the
@@ -15,6 +15,8 @@ use std::rc::Rc;
15
15
  pub(super) enum Ir {
16
16
  /// Literal single-line text.
17
17
  Text(Rc<str>),
18
+ /// The TeX control symbol `\ `, whose ASCII space is semantic.
19
+ ControlSpace,
18
20
  /// Documents printed back-to-back.
19
21
  Concat(Rc<[Ir]>),
20
22
  /// A space when flat, or a newline when broken.
@@ -59,6 +61,10 @@ impl Ir {
59
61
  }
60
62
  }
61
63
 
64
+ pub(super) fn control_space() -> Self {
65
+ Self::ControlSpace
66
+ }
67
+
62
68
  pub(super) fn concat(documents: impl IntoIterator<Item = Ir>) -> Self {
63
69
  let documents: Vec<_> = documents
64
70
  .into_iter()
@@ -117,7 +123,7 @@ impl Ir {
117
123
  inner.contains_forced_break()
118
124
  }
119
125
  Self::BoundedAlign { aligned, .. } => aligned.contains_forced_break(),
120
- Self::Text(_) | Self::Line | Self::SoftLine | Self::Nil => false,
126
+ Self::Text(_) | Self::ControlSpace | Self::Line | Self::SoftLine | Self::Nil => false,
121
127
  }
122
128
  }
123
129
 
@@ -126,6 +132,7 @@ impl Ir {
126
132
  pub(super) fn flat_width(&self) -> Option<usize> {
127
133
  match self {
128
134
  Self::Text(text) => Some(text.chars().count()),
135
+ Self::ControlSpace => Some(2),
129
136
  Self::Verbatim(text) => (!text.contains('\n')).then(|| text.chars().count()),
130
137
  Self::Concat(documents) => documents.iter().try_fold(0usize, |width, document| {
131
138
  width.checked_add(document.flat_width()?)
@@ -2275,7 +2275,12 @@ fn atom_document(
2275
2275
  {
2276
2276
  let text = token_slice(range, token)?;
2277
2277
  let slash = text == "/";
2278
- (Ir::verbatim(text), slash)
2278
+ let document = if text == r"\ " {
2279
+ Ir::control_space()
2280
+ } else {
2281
+ Ir::verbatim(text)
2282
+ };
2283
+ (document, slash)
2279
2284
  }
2280
2285
  SyntaxElement::Node(node) => {
2281
2286
  if let Some(group) = MathGroup::cast(node.clone()) {
@@ -98,6 +98,7 @@ impl Printer {
98
98
  match command.document {
99
99
  Ir::Nil => {}
100
100
  Ir::Text(text) => writer.write_text(text),
101
+ Ir::ControlSpace => writer.write_control_space(),
101
102
  Ir::Verbatim(text) if self.flatten_forced_breaks => {
102
103
  writer.write_flattened_verbatim(text)
103
104
  }
@@ -181,6 +182,7 @@ impl Printer {
181
182
  Ir::Text(text) => {
182
183
  column = column.saturating_add(text.chars().count());
183
184
  }
185
+ Ir::ControlSpace => column = column.saturating_add(2),
184
186
  Ir::Verbatim(text) if !text.contains('\n') => {
185
187
  column = column.saturating_add(text.chars().count());
186
188
  }
@@ -219,6 +221,7 @@ impl Printer {
219
221
  Ir::SoftLine if command.mode == Mode::Flat => {}
220
222
  Ir::SoftLine | Ir::HardLine | Ir::EmptyLine => return true,
221
223
  Ir::Text(text) => column = column.saturating_add(text.chars().count()),
224
+ Ir::ControlSpace => column = column.saturating_add(2),
222
225
  Ir::Verbatim(text) => {
223
226
  let first = text
224
227
  .split_once('\n')
@@ -304,6 +307,8 @@ struct Writer {
304
307
  /// that indentation is dropped at every join.
305
308
  flatten: bool,
306
309
  drop_leading_space: bool,
310
+ /// ASCII whitespace emitted for layout at the physical line end.
311
+ trailing_layout_whitespace: usize,
307
312
  }
308
313
 
309
314
  impl Writer {
@@ -315,6 +320,7 @@ impl Writer {
315
320
  needs_indent,
316
321
  flatten,
317
322
  drop_leading_space: false,
323
+ trailing_layout_whitespace: 0,
318
324
  }
319
325
  }
320
326
 
@@ -328,21 +334,36 @@ impl Writer {
328
334
  }
329
335
 
330
336
  fn finish(mut self) -> String {
331
- if !self.flatten {
332
- self.trim_trailing_whitespace();
333
- }
337
+ self.trim_trailing_whitespace();
334
338
  self.output
335
339
  }
336
340
 
337
341
  fn trim_trailing_whitespace(&mut self) {
338
342
  self.output
339
- .truncate(self.output.trim_end_matches([' ', '\t']).len());
343
+ .truncate(self.output.len() - self.trailing_layout_whitespace);
344
+ self.column = self.column.saturating_sub(self.trailing_layout_whitespace);
345
+ self.trailing_layout_whitespace = 0;
346
+ }
347
+
348
+ fn push_layout_text(&mut self, text: &str) {
349
+ self.output.push_str(text);
350
+ self.column += text.chars().count();
351
+ let trailing_whitespace = text
352
+ .as_bytes()
353
+ .iter()
354
+ .rev()
355
+ .take_while(|&&byte| matches!(byte, b' ' | b'\t'))
356
+ .count();
357
+ if trailing_whitespace == text.len() {
358
+ self.trailing_layout_whitespace += trailing_whitespace;
359
+ } else {
360
+ self.trailing_layout_whitespace = trailing_whitespace;
361
+ }
340
362
  }
341
363
 
342
364
  fn flush_indent(&mut self) {
343
365
  if self.needs_indent {
344
- self.output.push_str(&" ".repeat(self.pending_indent));
345
- self.column += self.pending_indent;
366
+ self.push_layout_text(&" ".repeat(self.pending_indent));
346
367
  self.needs_indent = false;
347
368
  }
348
369
  }
@@ -358,8 +379,15 @@ impl Writer {
358
379
  }
359
380
  self.drop_leading_space = false;
360
381
  self.flush_indent();
361
- self.output.push_str(text);
362
- self.column += text.chars().count();
382
+ self.push_layout_text(text);
383
+ }
384
+
385
+ fn write_control_space(&mut self) {
386
+ self.drop_leading_space = false;
387
+ self.flush_indent();
388
+ self.output.push_str(r"\ ");
389
+ self.column += 2;
390
+ self.trailing_layout_whitespace = 0;
363
391
  }
364
392
 
365
393
  /// Write one space, unless the line is still empty or already ends in one.
@@ -398,9 +426,9 @@ impl Writer {
398
426
  self.output.push('\n');
399
427
  self.column = 0;
400
428
  self.needs_indent = false;
429
+ self.trailing_layout_whitespace = 0;
401
430
  }
402
- self.output.push_str(segment);
403
- self.column += segment.chars().count();
431
+ self.push_layout_text(segment);
404
432
  }
405
433
  }
406
434
 
@@ -410,6 +438,7 @@ impl Writer {
410
438
  self.column = 0;
411
439
  self.pending_indent = indent;
412
440
  self.needs_indent = indent > 0;
441
+ self.trailing_layout_whitespace = 0;
413
442
  }
414
443
 
415
444
  fn empty_line(&mut self, indent: usize) {
@@ -418,6 +447,7 @@ impl Writer {
418
447
  self.column = 0;
419
448
  self.pending_indent = indent;
420
449
  self.needs_indent = indent > 0;
450
+ self.trailing_layout_whitespace = 0;
421
451
  }
422
452
  }
423
453
 
@@ -544,6 +574,20 @@ mod tests {
544
574
  assert_eq!(printer(80).print(&document, 0), "a\nb\nc\n\nd");
545
575
  }
546
576
 
577
+ #[test]
578
+ fn line_boundaries_preserve_control_spaces_but_drop_later_padding() {
579
+ let document = Ir::concat([
580
+ Ir::text("a"),
581
+ Ir::control_space(),
582
+ Ir::text(" "),
583
+ Ir::HardLine,
584
+ Ir::text("b"),
585
+ Ir::control_space(),
586
+ ]);
587
+
588
+ assert_eq!(printer(80).print(&document, 0), "a\\ \nb\\ ");
589
+ }
590
+
547
591
  #[test]
548
592
  fn multiline_verbatim_forces_an_enclosing_group_open() {
549
593
  let document = Ir::group(Ir::concat([
@@ -595,7 +639,7 @@ mod tests {
595
639
  Ir::verbatim("b\nc"),
596
640
  Ir::HardLine,
597
641
  ]);
598
- assert_eq!(printer(4).print_flat(&document), "a b c ");
642
+ assert_eq!(printer(4).print_flat(&document), "a b c");
599
643
  }
600
644
 
601
645
  #[test]
@@ -116,7 +116,7 @@ fn render_inline_content(
116
116
  if keeps_breaks {
117
117
  printer.print(document, 0)
118
118
  } else {
119
- printer.print_flat(document).trim().to_string()
119
+ printer.print_flat(document)
120
120
  }
121
121
  };
122
122
 
@@ -144,7 +144,10 @@ fn render_inline_content(
144
144
  /// on that line; the caller already puts the closing delimiter on a line of its
145
145
  /// own, so keeping the break would leave a blank line between them.
146
146
  fn trimmed_body(printer: &Printer, document: &Ir, indent: usize) -> String {
147
- printer.print(document, indent).trim_end().to_string()
147
+ printer
148
+ .print(document, indent)
149
+ .trim_end_matches(['\r', '\n'])
150
+ .to_string()
148
151
  }
149
152
 
150
153
  fn render_display(
@@ -197,25 +200,9 @@ fn render_display(
197
200
  opts.line_width.saturating_sub(opts.math_indent),
198
201
  )
199
202
  {
200
- let significant = top
201
- .iter()
202
- .filter(|element| !is_layout_whitespace(element))
203
- .collect::<Vec<_>>();
204
- let base_indent = if significant.len() == 1
205
- && significant[0].as_node().is_some_and(|node| {
206
- node.kind() == SyntaxKind::MATH_ENVIRONMENT
207
- || MathScripted::cast(node.clone()).is_some_and(|scripted| {
208
- scripted
209
- .base()
210
- .and_then(SyntaxElement::into_node)
211
- .is_some_and(|base| base.kind() == SyntaxKind::MATH_ENVIRONMENT)
212
- })
213
- }) {
214
- 0
215
- } else {
216
- opts.math_indent
217
- };
218
- return Some(Printer::new(opts.line_width, INDENT.len()).print(&document, base_indent));
203
+ return Some(
204
+ Printer::new(opts.line_width, INDENT.len()).print(&document, opts.math_indent),
205
+ );
219
206
  }
220
207
 
221
208
  if has_mixed_environment_content(top) {
@@ -156,9 +156,10 @@ impl Formatter {
156
156
  push_body_with_trailing_newline(&mut self.output, &body);
157
157
  }
158
158
  None => {
159
- for line in content.trim().lines() {
159
+ let content = trim_preserved_math_body(&content);
160
+ for line in content.lines() {
160
161
  self.output.push_str(&" ".repeat(self.config.math_indent));
161
- self.output.push_str(line.trim_end());
162
+ self.output.push_str(line);
162
163
  self.output.push('\n');
163
164
  }
164
165
  }
@@ -178,6 +179,10 @@ pub(super) fn push_body_with_trailing_newline(output: &mut String, body: &str) {
178
179
  }
179
180
 
180
181
  /// Drop ASCII line-end padding without otherwise normalizing preserved math.
182
+ ///
183
+ /// A space immediately controlled by an odd-length backslash run is the TeX
184
+ /// control symbol `\ `, not padding. Keep that byte while removing any layout
185
+ /// whitespace after it.
181
186
  pub(super) fn trim_trailing_whitespace_per_line(body: &str) -> String {
182
187
  let mut output = String::with_capacity(body.len());
183
188
  for segment in body.split_inclusive('\n') {
@@ -185,18 +190,44 @@ pub(super) fn trim_trailing_whitespace_per_line(body: &str) -> String {
185
190
  let (line, carriage_return) = line
186
191
  .strip_suffix('\r')
187
192
  .map_or((line, false), |line| (line, true));
188
- output.push_str(line.trim_end_matches([' ', '\t']));
193
+ output.push_str(trim_math_line_end(line));
189
194
  if carriage_return {
190
195
  output.push('\r');
191
196
  }
192
197
  output.push('\n');
193
198
  } else {
194
- output.push_str(segment.trim_end_matches([' ', '\t']));
199
+ output.push_str(trim_math_line_end(segment));
195
200
  }
196
201
  }
197
202
  output
198
203
  }
199
204
 
205
+ pub(super) fn trim_preserved_math_body(body: &str) -> String {
206
+ trim_trailing_whitespace_per_line(body)
207
+ .trim_start()
208
+ .trim_end_matches(['\r', '\n'])
209
+ .to_string()
210
+ }
211
+
212
+ fn trim_math_line_end(line: &str) -> &str {
213
+ let trimmed = line.trim_end_matches([' ', '\t']);
214
+ let trailing = &line[trimmed.len()..];
215
+ if !trailing.starts_with(' ') {
216
+ return trimmed;
217
+ }
218
+ let backslashes = trimmed
219
+ .as_bytes()
220
+ .iter()
221
+ .rev()
222
+ .take_while(|&&byte| byte == b'\\')
223
+ .count();
224
+ if backslashes % 2 == 1 {
225
+ &line[..trimmed.len() + 1]
226
+ } else {
227
+ trimmed
228
+ }
229
+ }
230
+
200
231
  fn inline_delimiters(
201
232
  style: MathDelimiterStyle,
202
233
  is_display_math: bool,
@@ -660,6 +691,20 @@ mod tests {
660
691
  assert_idempotent("\\alpha x", MathContext::Inline);
661
692
  }
662
693
 
694
+ #[test]
695
+ fn inline_preserves_trailing_control_space() {
696
+ assert_eq!(fmt(r"x\ ", MathContext::Inline), r"x\ ");
697
+ assert_idempotent(r"x\ ", MathContext::Inline);
698
+ }
699
+
700
+ #[test]
701
+ fn preserved_line_cleanup_keeps_only_semantic_control_space() {
702
+ assert_eq!(
703
+ trim_trailing_whitespace_per_line("a\\ \t \nb\\\\ \nc \t\n"),
704
+ "a\\ \nb\\\\\nc\n"
705
+ );
706
+ }
707
+
663
708
  #[test]
664
709
  fn inline_keeps_optional_arguments_tight() {
665
710
  assert_eq!(fmt(r"\sqrt[3]{x}", MathContext::Inline), r"\sqrt[3]{x}");
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.28.1](https://github.com/jolars/panache/compare/panache-parser-v0.28.0...panache-parser-v0.28.1) (2026-08-31)
4
+
5
+ ### Bug Fixes
6
+ - **math:** report unescaped dollar ([`8083731`](https://github.com/jolars/panache/commit/80837318919cfe318eebd8c8b83a43db13ab2be6))
7
+
3
8
  ## [0.28.0](https://github.com/jolars/panache/compare/panache-parser-v0.27.2...panache-parser-v0.28.0) (2026-08-28)
4
9
 
5
10
  ### Features
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "panache-parser"
3
- version = "0.28.0"
3
+ version = "0.28.1"
4
4
  edition.workspace = true
5
5
  rust-version.workspace = true
6
6
  readme = "README.md"