apex-ruby 1.0.17 → 1.0.20
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.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/ext/apex_ext/apex_ext.c +260 -91
- data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
- data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
- data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
- data/ext/apex_ext/apex_src/Package.swift +15 -4
- data/ext/apex_ext/apex_src/README.md +94 -35
- data/ext/apex_ext/apex_src/VERSION +1 -1
- data/ext/apex_ext/apex_src/apex-debug.log +4 -0
- data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
- data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
- data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
- data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
- data/ext/apex_ext/apex_src/cli/main.c +262 -33
- data/ext/apex_ext/apex_src/debug.log +7 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
- data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
- data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
- data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
- data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
- data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
- data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
- data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
- data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
- data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
- data/ext/apex_ext/apex_src/include/apexc.h +1 -0
- data/ext/apex_ext/apex_src/man/apex.1 +82 -78
- data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
- data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
- data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
- data/ext/apex_ext/apex_src/output.html +87 -0
- data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
- data/ext/apex_ext/apex_src/src/_README.md +85 -32
- data/ext/apex_ext/apex_src/src/apex.c +770 -200
- data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
- data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
- data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
- data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
- data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
- data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
- data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
- data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
- data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
- data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
- data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
- data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
- data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
- data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
- data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
- data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
- data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
- data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
- data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
- data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
- data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
- data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
- data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
- data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
- data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
- data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
- data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
- data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
- data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
- data/ext/apex_ext/extconf.rb +35 -0
- data/lib/apex/version.rb +2 -2
- metadata +117 -2
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Man Page (roff / man-html) Output Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Add two new Apex output formats: roff (UNIX man page source) and styled man-page HTML, so that `apex -t man` and `apex -t man-html` produce output similar to Pandoc's `-t man` and [md2man](https://github.com/sunaku/md2man)-style HTML (e.g. [EXAMPLE](https://sunaku.github.io/md2man/man/man0/EXAMPLE.html)).
|
|
6
|
+
|
|
7
|
+
**Architecture:** Follow the existing AST-renderer pattern used by terminal and markdown: add `APEX_OUTPUT_MAN` and `APEX_OUTPUT_MAN_HTML` to the enum; implement a new module `src/ast_man.c` with `apex_cmark_to_man_roff()` and `apex_cmark_to_man_html()` that walk the cmark AST and emit roff macros (e.g. `.TH`, `.SH`, `.B`, `.I`) or a self-contained styled HTML document. Man page metadata (name, section, date) is taken from document metadata (e.g. `man_title`, `man_section`, `man_date`) or sensible defaults. No external tools (Pandoc/md2man) are invoked; rendering is in-process.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** C, cmark-gfm AST, existing apex_options and CLI; roff (man(7)) and HTML output as plain strings.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Task 1: Add output format enum values and API placeholder
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Modify: `include/apex/apex.h` (around the `apex_output_format_t` enum, ~lines 43-54)
|
|
17
|
+
- Create: `include/apex/ast_man.h`
|
|
18
|
+
- Modify: `src/apex.c` (includes and one conditional that returns early for man formats with a stub)
|
|
19
|
+
- Modify: `cli/main.c` (help string and `-t`/`--to` parsing)
|
|
20
|
+
|
|
21
|
+
**Step 1: Extend the output format enum**
|
|
22
|
+
|
|
23
|
+
In `include/apex/apex.h`, add after `APEX_OUTPUT_TERMINAL256`:
|
|
24
|
+
|
|
25
|
+
```c
|
|
26
|
+
APEX_OUTPUT_TERMINAL256 = 9, /* ANSI terminal output (256-color) */
|
|
27
|
+
APEX_OUTPUT_MAN = 10, /* roff (man page source) */
|
|
28
|
+
APEX_OUTPUT_MAN_HTML = 11 /* styled HTML man page */
|
|
29
|
+
} apex_output_format_t;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Step 2: Add public API header**
|
|
33
|
+
|
|
34
|
+
Create `include/apex/ast_man.h`:
|
|
35
|
+
|
|
36
|
+
```c
|
|
37
|
+
#ifndef APEX_AST_MAN_H
|
|
38
|
+
#define APEX_AST_MAN_H
|
|
39
|
+
|
|
40
|
+
#include "apex/apex.h"
|
|
41
|
+
#include "cmark-gfm.h"
|
|
42
|
+
|
|
43
|
+
#ifdef __cplusplus
|
|
44
|
+
extern "C" {
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
char *apex_cmark_to_man_roff(cmark_node *document, const apex_options *options);
|
|
48
|
+
char *apex_cmark_to_man_html(cmark_node *document, const apex_options *options);
|
|
49
|
+
|
|
50
|
+
#ifdef __cplusplus
|
|
51
|
+
}
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#endif
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Step 3: Add stub implementation and wire in apex.c**
|
|
58
|
+
|
|
59
|
+
Create `src/ast_man.c` with two functions that return a minimal valid result (e.g. roff: `.TH stub 1 "" ""` and newline; HTML: `<!DOCTYPE html><html><body><p>stub</p></body></html>`). In `src/apex.c`: add `#include "apex/ast_man.h"`. After the terminal block (around 5156), add:
|
|
60
|
+
|
|
61
|
+
```c
|
|
62
|
+
if (options->output_format == APEX_OUTPUT_MAN) {
|
|
63
|
+
char *roff = apex_cmark_to_man_roff(document, options);
|
|
64
|
+
return roff;
|
|
65
|
+
}
|
|
66
|
+
if (options->output_format == APEX_OUTPUT_MAN_HTML) {
|
|
67
|
+
char *man_html = apex_cmark_to_man_html(document, options);
|
|
68
|
+
return man_html;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Step 4: Wire CLI**
|
|
73
|
+
|
|
74
|
+
In `cli/main.c`: in the `-t`/`--to` parsing block, add branches for `"man"` -> `APEX_OUTPUT_MAN` and `"man-html"` -> `APEX_OUTPUT_MAN_HTML`. Update the help string for `-t, --to FORMAT` to include `man` and `man-html`.
|
|
75
|
+
|
|
76
|
+
**Step 5: Add to AST filter target format**
|
|
77
|
+
|
|
78
|
+
In `src/apex.c`, in the block that sets `target_format` for AST filters (around 5029), add:
|
|
79
|
+
|
|
80
|
+
```c
|
|
81
|
+
} else if (options->output_format == APEX_OUTPUT_MAN ||
|
|
82
|
+
options->output_format == APEX_OUTPUT_MAN_HTML) {
|
|
83
|
+
target_format = "man";
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Step 6: Register ast_man.c in build**
|
|
88
|
+
|
|
89
|
+
In `CMakeLists.txt`, add `src/ast_man.c` to the list of source files that include `ast_terminal.c` (around line 113).
|
|
90
|
+
|
|
91
|
+
**Step 7: Build and smoke test**
|
|
92
|
+
|
|
93
|
+
Run: `cd build && cmake .. && make apex_cli`
|
|
94
|
+
Run: `echo '# Hi' | ./apex -t man`
|
|
95
|
+
Expected: output starts with `.TH` and contains a stub or minimal section.
|
|
96
|
+
Run: `echo '# Hi' | ./apex -t man-html`
|
|
97
|
+
Expected: HTML document containing stub or minimal content.
|
|
98
|
+
|
|
99
|
+
**Step 8: Commit**
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git add include/apex/apex.h include/apex/ast_man.h src/ast_man.c src/apex.c cli/main.c CMakeLists.txt
|
|
103
|
+
git commit -m "feat: add man and man-html output format enum and stub renderers"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Task 2: Implement roff serializer (ast_man.c roff path)
|
|
109
|
+
|
|
110
|
+
**Files:**
|
|
111
|
+
- Modify: `src/ast_man.c`
|
|
112
|
+
|
|
113
|
+
**Step 1: Implement buffer and escape helpers**
|
|
114
|
+
|
|
115
|
+
Add a simple growable buffer (similar to `ast_terminal.c`'s `terminal_buffer`) and a function to escape roff special characters (backslash, `\.` for literal dot at start of line). Expose a function that appends roff-safe text (escape `\`, `'`, and leading `.`).
|
|
116
|
+
|
|
117
|
+
**Step 2: Emit .TH from metadata or defaults**
|
|
118
|
+
|
|
119
|
+
Parse document metadata (or options) for `man_title`, `man_section`, `man_date`, `man_source` (e.g. from YAML front matter). If missing, use: title from first H1 or "Document", section "1", date from build or "1 January 1970", source "". Emit `.TH title section date source` at the start.
|
|
120
|
+
|
|
121
|
+
**Step 3: Block-level roff: headings, paragraphs, lists, code blocks**
|
|
122
|
+
|
|
123
|
+
Walk document children. For each node type:
|
|
124
|
+
- `CMARK_NODE_HEADING`: emit `.SH` with heading text (level 1 = `.SH`, deeper levels can be `.SS` or `.SH` with combined text).
|
|
125
|
+
- `CMARK_NODE_PARAGRAPH`: emit paragraph text with `.PP` or `.IP` as needed; inline formatting (bold/italic/code) via `.B`, `.I`, `.BR`, `.IR` etc.
|
|
126
|
+
- `CMARK_NODE_LIST`: bullet list with `.IP \\(bu` or `.IP \\fB*\\fP`; ordered list with `.IP` and number.
|
|
127
|
+
- `CMARK_NODE_CODE_BLOCK`: `.PP` then verbatim block (escape and use `.nf`/`.fi` or inline with escaped newlines).
|
|
128
|
+
- `CMARK_NODE_BLOCK_QUOTE`: indent with `.RS`/`.RE` and recurse.
|
|
129
|
+
- `CMARK_NODE_TABLE`: optional; simple table as roff `TS`/`TE` or as list of rows.
|
|
130
|
+
|
|
131
|
+
**Step 4: Inline formatting**
|
|
132
|
+
|
|
133
|
+
For inline nodes: strong -> `.B`, em -> `.I`, code -> `\\fB`/`\\fP` or similar; links can be `.I text` and optional URL in parens. Escape special chars in all text.
|
|
134
|
+
|
|
135
|
+
**Step 5: Verify with man(1)**
|
|
136
|
+
|
|
137
|
+
Run: `echo -e '# NAME\n\nfoo - short desc\n\n# SYNOPSIS\n\n**foo** [*options*]' | ./apex -t man > /tmp/foo.1 && man -l /tmp/foo.1`
|
|
138
|
+
Expected: man viewer shows a minimal man page without errors.
|
|
139
|
+
|
|
140
|
+
**Step 6: Commit**
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git add src/ast_man.c
|
|
144
|
+
git commit -m "feat: implement roff (man page) serializer in ast_man.c"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Task 3: Implement man-html serializer (styled HTML)
|
|
150
|
+
|
|
151
|
+
**Files:**
|
|
152
|
+
- Modify: `src/ast_man.c`
|
|
153
|
+
|
|
154
|
+
**Step 1: Emit HTML document shell**
|
|
155
|
+
|
|
156
|
+
In `apex_cmark_to_man_html()`, emit `<!DOCTYPE html>`, `<html>`, `<head>` with `<meta charset="utf-8">`, `<title>` from man_title (or first H1), and a `<style>` block. Reuse or mirror the structure of [md2man EXAMPLE](https://sunaku.github.io/md2man/man/man0/EXAMPLE.html): section headings, monospace for options/code, list styling.
|
|
157
|
+
|
|
158
|
+
**Step 2: Add minimal CSS for man-page look**
|
|
159
|
+
|
|
160
|
+
Include inline CSS that styles: `.man-title`, `.man-section` (e.g. NAME, SYNOPSIS, OPTIONS), `.man-option` (bold/italic for option names and args), code blocks and lists so the result is readable and similar to the md2man example.
|
|
161
|
+
|
|
162
|
+
**Step 3: Walk AST and emit HTML sections**
|
|
163
|
+
|
|
164
|
+
Map block types to semantic HTML: H1 -> name/title; H2/H3 -> section headers (e.g. `<h2 id="name">NAME</h2>`); paragraphs, lists, code blocks -> `<p>`, `<ul>`/`<ol>`, `<pre><code>`; inline bold/italic/code -> `<strong>`, `<em>`, `<code>`. Escape HTML entities in text. Links: `<a href="...">`.
|
|
165
|
+
|
|
166
|
+
**Step 4: Sanity check**
|
|
167
|
+
|
|
168
|
+
Run: `echo -e '# NAME\n\nfoo - short desc\n\n# SYNOPSIS\n\n**foo** [*options*]' | ./apex -t man-html > /tmp/foo.html && open /tmp/foo.html` (or open in browser).
|
|
169
|
+
Expected: styled page with NAME and SYNOPSIS sections, no raw AST or crashes.
|
|
170
|
+
|
|
171
|
+
**Step 5: Commit**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git add src/ast_man.c
|
|
175
|
+
git commit -m "feat: implement styled man-html output in ast_man.c"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Task 4: Document metadata for man pages
|
|
181
|
+
|
|
182
|
+
**Files:**
|
|
183
|
+
- Modify: `src/ast_man.c` (read metadata from document or options)
|
|
184
|
+
- Modify: `src/extensions/metadata.c` or document in README how metadata keys map to man header
|
|
185
|
+
|
|
186
|
+
**Step 1: Define metadata keys**
|
|
187
|
+
|
|
188
|
+
Support in document metadata (YAML front matter or metadata block): `man_title` (or `title`), `man_section` (default "1"), `man_date` (default or from doc), `man_source` (optional). In `apex_cmark_to_man_roff` and `apex_cmark_to_man_html`, obtain these from the document's metadata table if available (see how apex exposes metadata to renderers), otherwise fall back to first H1 and defaults.
|
|
189
|
+
|
|
190
|
+
**Step 2: Use metadata in both roff and HTML**
|
|
191
|
+
|
|
192
|
+
Ensure `.TH` and the HTML `<title>` / header use the same metadata source. If apex does not yet pass metadata to custom renderers, add an optional `apex_metadata_item*` or similar to the options struct for this pipeline, or read from the document's first-child metadata node if the AST carries it.
|
|
193
|
+
|
|
194
|
+
**Step 3: Commit**
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
git add src/ast_man.c [and any metadata changes]
|
|
198
|
+
git commit -m "feat: man output uses document metadata for title, section, date"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Task 5: Tests and documentation
|
|
204
|
+
|
|
205
|
+
**Files:**
|
|
206
|
+
- Create or modify: `tests/` (existing test runner if any; or add a small script that runs `apex -t man` and `apex -t man-html` on a fixture and checks for expected substrings)
|
|
207
|
+
- Modify: `README.md` and `man/apex.1.md` to document `-t man` and `-t man-html`
|
|
208
|
+
|
|
209
|
+
**Step 1: Add fixture and test script**
|
|
210
|
+
|
|
211
|
+
Create `tests/fixtures/man-basic.md` with a minimal man-style doc (NAME, SYNOPSIS, one option). Create or extend a test script that: runs `apex -t man -s < tests/fixtures/man-basic.md`, greps for `.TH` and `.SH`; runs `apex -t man-html -s < tests/fixtures/man-basic.md`, greps for `<!DOCTYPE html>` and `<h2` or "NAME". Exit 0 if found, 1 otherwise.
|
|
212
|
+
|
|
213
|
+
**Step 2: Run tests**
|
|
214
|
+
|
|
215
|
+
Run the test script; fix any failures.
|
|
216
|
+
|
|
217
|
+
**Step 3: Update README and man page**
|
|
218
|
+
|
|
219
|
+
In README, add `man` and `man-html` to the list of output formats and mention that document metadata can set man page title/section/date. In `man/apex.1.md`, add **man** and **man-html** to the OPTIONS description of `-t, --to FORMAT`.
|
|
220
|
+
|
|
221
|
+
**Step 4: Commit**
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
git add tests/ README.md man/apex.1.md
|
|
225
|
+
git commit -m "docs and tests: man and man-html output"
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Definition-list option blocks (`: ` / `:: `) for man output
|
|
231
|
+
|
|
232
|
+
**Context:** Man pages often use “term + description” pairs (e.g. `**--option**` then `:: Description.`). The definition-list extension should create AST definition lists when the block parser sees a line starting with `: ` or `:: ` after a paragraph, so that man output can render them as `.TP` (term) + body.
|
|
233
|
+
|
|
234
|
+
**Done so far:**
|
|
235
|
+
|
|
236
|
+
1. **blocks.c (cmark):** In `check_open_blocks`, when the open block is a paragraph and the line starts with `: ` or `:: ` (optional second `:`, then space/tab), `goto done` so the paragraph does not match and the container backs up to the document; `open_new_blocks` then runs and the definition_list extension can open a block.
|
|
237
|
+
2. **apex.c:** Definition-list preprocessing is skipped when `output_format` is `APEX_OUTPUT_MAN` or `APEX_OUTPUT_MAN_HTML` so the block parser sees raw `: ` / `:: `.
|
|
238
|
+
3. **definition_list.c (extension):**
|
|
239
|
+
- **Segfault fix:** No longer unlink the previous paragraph in `open_block`; only insert the def_list before it. The parser’s finalize path removes the paragraph; unlinking caused use-after-free.
|
|
240
|
+
- **can_contain:** def_list and term created with `cmark_node_new_with_mem_and_ext` so `cmark_node_can_contain_type(def_list, PARAGRAPH)` allows the description paragraph under the list.
|
|
241
|
+
- **Term content:** Create a new paragraph under the term and copy `prev->content` into it (with `prev->start_line` / `start_column`), ensure trailing newline; prefer `parser->current` as `prev` when it’s the interrupted paragraph.
|
|
242
|
+
- **Postprocess:** If the def_list’s first child is a DEFINITION_TERM with a paragraph that has no “real” content (only softbreak/linebreak), and the next sibling of the def_list is a paragraph with inlines, move that paragraph’s inlines into the term’s paragraph and remove the sibling.
|
|
243
|
+
|
|
244
|
+
**Current behaviour:** For input `**--foo**` then `:: Enable foo.`:
|
|
245
|
+
|
|
246
|
+
- **HTML:** `<dt></dt>`, `<dd><p>Enable foo.</p></dd>`, then `<p><strong>–foo</strong></p>` (term empty; “term” appears as a following paragraph).
|
|
247
|
+
- **Man:** `.TP` then “Enable foo.”, then `.PP` and bold `--foo` (same structure).
|
|
248
|
+
|
|
249
|
+
So the term paragraph stays empty (copy from `prev` isn’t populating it and/or the postprocess move isn’t applied).
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### Debug steps (definition-list term empty)
|
|
254
|
+
|
|
255
|
+
Use these to see why the term has no content and why the postprocess fix may not run.
|
|
256
|
+
|
|
257
|
+
**1. Confirm `prev` and its content in `open_block`**
|
|
258
|
+
|
|
259
|
+
In `src/extensions/definition_list.c`, in `open_block`, immediately after resolving `prev` (and before creating `def_list`), add:
|
|
260
|
+
|
|
261
|
+
```c
|
|
262
|
+
/* DEBUG: remove after finding why term is empty */
|
|
263
|
+
if (getenv("APEX_DEBUG_DEFLIST")) {
|
|
264
|
+
fprintf(stderr, "[deflist open_block] prev=%p type=%u content.size=%zu parser->current=%p\n",
|
|
265
|
+
(void*)prev, (unsigned)cmark_node_get_type(prev),
|
|
266
|
+
(size_t)prev->content.size, (void*)parser->current);
|
|
267
|
+
if (prev->content.size > 0 && prev->content.size <= 200)
|
|
268
|
+
fprintf(stderr, "[deflist open_block] content: %.*s\n", (int)prev->content.size, prev->content.ptr);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Run (env var must apply to **apex**, not the left side of the pipe; debug is also appended to `/tmp/apex_deflist_debug.log`):
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
printf '%s\n' '**--foo**' ':: Enable foo.' | ./build/apex -t html -s 2>&1 | head -5
|
|
276
|
+
printf '%s\n' '**--foo**' ':: Enable foo.' | APEX_DEBUG_DEFLIST=1 ./build/apex -t html -s 2>&1 | head -20
|
|
277
|
+
# or: cat /tmp/apex_deflist_debug.log
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
- If `content.size == 0`, the paragraph has no content when we copy; trace back to when that paragraph receives the first line (e.g. whether `add_line` is called for it before we run).
|
|
281
|
+
- If `content.size > 0`, the copy path is correct; then either the copied buffer isn’t used by the inline parser (e.g. wrong node or buffer cleared later) or the postprocess is supposed to fix it but doesn’t.
|
|
282
|
+
|
|
283
|
+
**2. Confirm postprocess sees the right structure**
|
|
284
|
+
|
|
285
|
+
In `postprocess`, at the start of the `while (cur)` loop, when `cur` is a DEFINITION_LIST, add:
|
|
286
|
+
|
|
287
|
+
```c
|
|
288
|
+
if (getenv("APEX_DEBUG_DEFLIST")) {
|
|
289
|
+
cmark_node *term = cmark_node_first_child(cur);
|
|
290
|
+
cmark_node *term_para = term ? cmark_node_first_child(term) : NULL;
|
|
291
|
+
cmark_node *next_sib = cmark_node_next(cur);
|
|
292
|
+
fprintf(stderr, "[deflist postprocess] def_list=%p term=%p term_para=%p term_para.first_child=%p next_sib=%p next_sib.type=%u next_sib.first_child=%p\n",
|
|
293
|
+
(void*)cur, (void*)term, (void*)term_para,
|
|
294
|
+
term_para ? (void*)cmark_node_first_child(term_para) : NULL,
|
|
295
|
+
(void*)next_sib,
|
|
296
|
+
next_sib ? (unsigned)cmark_node_get_type(next_sib) : 0,
|
|
297
|
+
next_sib ? (void*)cmark_node_first_child(next_sib) : NULL);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Run with the same `APEX_DEBUG_DEFLIST=1` command.
|
|
302
|
+
|
|
303
|
+
- If `next_sib` is NULL, the document order is not `[def_list, paragraph]` (e.g. paragraph before def_list or root is not the document).
|
|
304
|
+
- If `next_sib.first_child` is NULL, the following paragraph has no inlines when postprocess runs (e.g. postprocess runs before `process_inlines` in the pipeline—unlikely—or that node isn’t the one that got the text).
|
|
305
|
+
- If `term_para.first_child` is non-NULL and not just softbreak/linebreak, the term was already filled (e.g. copy worked) and we intentionally don’t move; then the bug is in rendering (e.g. HTML/man not reading that node).
|
|
306
|
+
|
|
307
|
+
**3. Confirm root and document order**
|
|
308
|
+
|
|
309
|
+
In `postprocess`, before the `while (cur)` loop:
|
|
310
|
+
|
|
311
|
+
```c
|
|
312
|
+
if (getenv("APEX_DEBUG_DEFLIST")) {
|
|
313
|
+
fprintf(stderr, "[deflist postprocess] root=%p root.type=%u first_child=%p\n",
|
|
314
|
+
(void*)root, (unsigned)cmark_node_get_type(root), (void*)cmark_node_first_child(root));
|
|
315
|
+
for (cmark_node *n = cmark_node_first_child(root); n; n = cmark_node_next(n))
|
|
316
|
+
fprintf(stderr, " block=%p type=%u\n", (void*)n, (unsigned)cmark_node_get_type(n));
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
This verifies that root is the document and whether the first block is the def_list and the second the paragraph.
|
|
321
|
+
|
|
322
|
+
**4. Optional: assert in open_block**
|
|
323
|
+
|
|
324
|
+
After copying into `term_para`, assert that something was copied (only for local debugging):
|
|
325
|
+
|
|
326
|
+
```c
|
|
327
|
+
assert(term_para->content.size > 0 && "def_list term: prev had no content to copy");
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
If this fires, the fix is to ensure the interrupted paragraph’s content is available (e.g. use a different source than `prev->content` or fill the term in a later pass).
|
|
331
|
+
|
|
332
|
+
**5. Next steps depending on outcome**
|
|
333
|
+
|
|
334
|
+
- **prev->content.size == 0 in open_block:** Inspect when the first line is added to the paragraph (e.g. in `add_text_to_container` / `add_line`) and whether `open_block` is invoked before that for the second line. If the parser finalizes or clears the paragraph before we run, consider filling the term in postprocess only (e.g. always move the following paragraph’s inlines into the term when the term is empty), and ensure postprocess runs after `process_inlines`.
|
|
335
|
+
- **postprocess next_sib NULL or wrong order:** Handle “paragraph then def_list” or recurse into a wrapper root so we always see def_list and its next sibling.
|
|
336
|
+
- **postprocess runs but term_para already has content:** Copy is working; then inspect HTML/man renderer for DEFINITION_TERM (e.g. whether they descend into the term’s paragraph and render inlines).
|
|
337
|
+
|
|
338
|
+
Remove all `APEX_DEBUG_DEFLIST` branches and asserts before committing.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Execution Handoff
|
|
343
|
+
|
|
344
|
+
Plan complete and saved to `docs/plans/2025-02-27-man-page-output-implementation.md`.
|
|
345
|
+
|
|
346
|
+
**Two execution options:**
|
|
347
|
+
|
|
348
|
+
1. **Subagent-Driven (this session)** – I dispatch a fresh subagent per task, review between tasks, fast iteration.
|
|
349
|
+
2. **Parallel Session (separate)** – Open a new session with executing-plans and run through the plan task-by-task with checkpoints.
|
|
350
|
+
|
|
351
|
+
Which approach do you want?
|