apex-ruby 1.0.6 → 1.0.8

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/ext/apex_ext/apex_ext.c +6 -0
  3. data/ext/apex_ext/apex_src/AGENTS.md +41 -0
  4. data/ext/apex_ext/apex_src/CHANGELOG.md +412 -2
  5. data/ext/apex_ext/apex_src/CMakeLists.txt +41 -29
  6. data/ext/apex_ext/apex_src/Formula/apex.rb +2 -2
  7. data/ext/apex_ext/apex_src/Package.swift +9 -0
  8. data/ext/apex_ext/apex_src/README.md +31 -9
  9. data/ext/apex_ext/apex_src/ROADMAP.md +5 -0
  10. data/ext/apex_ext/apex_src/VERSION +1 -1
  11. data/ext/apex_ext/apex_src/cli/main.c +1125 -13
  12. data/ext/apex_ext/apex_src/docs/index.md +459 -0
  13. data/ext/apex_ext/apex_src/include/apex/apex.h +67 -5
  14. data/ext/apex_ext/apex_src/include/apex/ast_man.h +20 -0
  15. data/ext/apex_ext/apex_src/include/apex/ast_markdown.h +39 -0
  16. data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +40 -0
  17. data/ext/apex_ext/apex_src/include/apex/module.modulemap +1 -1
  18. data/ext/apex_ext/apex_src/man/apex-config.5 +333 -258
  19. data/ext/apex_ext/apex_src/man/apex-config.5.md +3 -1
  20. data/ext/apex_ext/apex_src/man/apex-plugins.7 +401 -316
  21. data/ext/apex_ext/apex_src/man/apex.1 +663 -620
  22. data/ext/apex_ext/apex_src/man/apex.1.html +703 -0
  23. data/ext/apex_ext/apex_src/man/apex.1.md +160 -90
  24. data/ext/apex_ext/apex_src/objc/Apex.swift +6 -0
  25. data/ext/apex_ext/apex_src/objc/NSString+Apex.h +12 -0
  26. data/ext/apex_ext/apex_src/objc/NSString+Apex.m +9 -0
  27. data/ext/apex_ext/apex_src/pages/index.md +459 -0
  28. data/ext/apex_ext/apex_src/src/_README.md +4 -4
  29. data/ext/apex_ext/apex_src/src/apex.c +702 -44
  30. data/ext/apex_ext/apex_src/src/ast_json.c +1130 -0
  31. data/ext/apex_ext/apex_src/src/ast_json.h +46 -0
  32. data/ext/apex_ext/apex_src/src/ast_man.c +948 -0
  33. data/ext/apex_ext/apex_src/src/ast_markdown.c +409 -0
  34. data/ext/apex_ext/apex_src/src/ast_terminal.c +2516 -0
  35. data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +8 -5
  36. data/ext/apex_ext/apex_src/src/extensions/definition_list.c +491 -1514
  37. data/ext/apex_ext/apex_src/src/extensions/definition_list.h +8 -15
  38. data/ext/apex_ext/apex_src/src/extensions/emoji.c +207 -0
  39. data/ext/apex_ext/apex_src/src/extensions/emoji.h +14 -0
  40. data/ext/apex_ext/apex_src/src/extensions/header_ids.c +178 -71
  41. data/ext/apex_ext/apex_src/src/extensions/highlight.c +37 -5
  42. data/ext/apex_ext/apex_src/src/extensions/ial.c +416 -47
  43. data/ext/apex_ext/apex_src/src/extensions/includes.c +241 -10
  44. data/ext/apex_ext/apex_src/src/extensions/includes.h +1 -0
  45. data/ext/apex_ext/apex_src/src/extensions/metadata.c +166 -3
  46. data/ext/apex_ext/apex_src/src/extensions/metadata.h +7 -0
  47. data/ext/apex_ext/apex_src/src/extensions/sup_sub.c +34 -3
  48. data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +55 -10
  49. data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.h +7 -4
  50. data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +84 -52
  51. data/ext/apex_ext/apex_src/src/extensions/toc.c +133 -19
  52. data/ext/apex_ext/apex_src/src/filters_ast.c +194 -0
  53. data/ext/apex_ext/apex_src/src/filters_ast.h +36 -0
  54. data/ext/apex_ext/apex_src/src/html_renderer.c +1265 -35
  55. data/ext/apex_ext/apex_src/src/html_renderer.h +21 -0
  56. data/ext/apex_ext/apex_src/src/plugins_remote.c +40 -14
  57. data/ext/apex_ext/apex_src/tests/CMakeLists.txt +1 -0
  58. data/ext/apex_ext/apex_src/tests/README.md +11 -5
  59. data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +13 -2
  60. data/ext/apex_ext/apex_src/tests/fixtures/filters/filter_output_with_rawblock.json +1 -0
  61. data/ext/apex_ext/apex_src/tests/fixtures/filters/unwrap.md +7 -0
  62. data/ext/apex_ext/apex_src/tests/fixtures/images/auto-wildcard.md +8 -0
  63. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.avif +0 -0
  64. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.jpg +0 -0
  65. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.webp +0 -0
  66. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.avif +0 -0
  67. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.jpg +0 -0
  68. data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.webp +0 -0
  69. data/ext/apex_ext/apex_src/tests/fixtures/images/media_formats_test.md +63 -0
  70. data/ext/apex_ext/apex_src/tests/fixtures/includes/data-semi.csv +3 -0
  71. data/ext/apex_ext/apex_src/tests/fixtures/includes/with space.txt +1 -0
  72. data/ext/apex_ext/apex_src/tests/fixtures/tables/inline_tables_test.md +4 -1
  73. data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +64 -0
  74. data/ext/apex_ext/apex_src/tests/terminal_width_test.sh +29 -0
  75. data/ext/apex_ext/apex_src/tests/test-swift-package.sh +14 -0
  76. data/ext/apex_ext/apex_src/tests/test_cmark_callback.c +189 -0
  77. data/ext/apex_ext/apex_src/tests/test_extensions.c +374 -0
  78. data/ext/apex_ext/apex_src/tests/test_metadata.c +68 -0
  79. data/ext/apex_ext/apex_src/tests/test_output.c +291 -2
  80. data/ext/apex_ext/apex_src/tests/test_runner.c +10 -0
  81. data/ext/apex_ext/apex_src/tests/test_syntax_highlight.c +1 -1
  82. data/ext/apex_ext/apex_src/tests/test_tables.c +17 -1
  83. data/lib/apex/version.rb +1 -1
  84. metadata +32 -2
  85. data/ext/apex_ext/apex_src/docs/FUTURE_FEATURES.md +0 -456
@@ -1,456 +1,541 @@
1
- .\" Automatically generated by Pandoc 3.8.3
2
- .\"
3
- .TH "APEX\-PLUGINS" "7" "December 2025" ""
1
+ .TH "NAME" "1" "1 January 1970" ""
2
+
4
3
  .SH NAME
4
+
5
+ .PP
5
6
  apex\-plugins \- Apex plugin system for extending Markdown processing
7
+
6
8
  .SH DESCRIPTION
7
- Apex supports a lightweight plugin system that lets you add new syntax
8
- and post\-processing behavior without patching the core.
9
- Plugins can be small scripts (Ruby, Python, etc.)
10
- or simple declarative regex rules defined in YAML.
9
+
10
+ .PP
11
+ Apex supports a lightweight plugin system that lets you add new syntax and post\-processing behavior without patching the core. Plugins can be small scripts (Ruby, Python, etc.) or simple declarative regex rules defined in YAML.
12
+
11
13
  .PP
12
- Plugins are disabled by default so Apex\(cqs performance and behavior
13
- are unchanged unless you explicitly opt in.
14
+ Plugins are disabled by default so Apex’s performance and behavior are unchanged unless you explicitly opt in.
15
+
14
16
  .SH ENABLING PLUGINS
17
+
15
18
  .SS Command\-line flags
19
+
16
20
  .IP \(bu 2
17
- \f[B]Enable plugins\f[R]: \f[CR]apex \-\-plugins input.md\f[R]
21
+ \f[B]Enable plugins\f[]: \fRapex \-\-plugins input.md\f[]
22
+
18
23
  .IP \(bu 2
19
- \f[B]Disable plugins\f[R]: \f[CR]apex \-\-no\-plugins input.md\f[R]
24
+ \f[B]Disable plugins\f[]: \fRapex \-\-no\-plugins input.md\f[]
25
+
20
26
  .SS Metadata keys
21
- In the document\(cqs front matter, any of these keys are recognized
22
- (case\-insensitive):
27
+
28
+ .PP
29
+ In the document’s front matter, any of these keys are recognized (case\-insensitive):
30
+
23
31
  .IP \(bu 2
24
- \f[CR]plugins\f[R]
32
+ \fRplugins\f[]
33
+
25
34
  .IP \(bu 2
26
- \f[CR]enable\-plugins\f[R]
35
+ \fRenable\-plugins\f[]
36
+
27
37
  .IP \(bu 2
28
- \f[CR]enable_plugins\f[R]
38
+ \fRenable_plugins\f[]
39
+
29
40
  .PP
30
41
  Example:
31
- .IP
32
- .EX
42
+
43
+ .PP
44
+ .nf
45
+ \fR
33
46
  \-\-\-
34
- title\f[B]:\f[R] Plugin demo
35
- plugins\f[B]:\f[R] true
47
+ title: Plugin demo
48
+ plugins: true
36
49
  \-\-\-
37
- .EE
50
+
51
+ \f[]
52
+ .fi
53
+
38
54
  .SS Precedence
39
- If metadata enables or disables plugins, you can still override it from
40
- the CLI:
55
+
56
+ .PP
57
+ If metadata enables or disables plugins, you can still override it from the CLI:
58
+
41
59
  .IP \(bu 2
42
- \f[CR]\-\-plugins\f[R] forces plugins \f[B]on\f[R]
60
+ \fR\-\-plugins\f[] forces plugins \f[B]on\f[]
61
+
43
62
  .IP \(bu 2
44
- \f[CR]\-\-no\-plugins\f[R] forces plugins \f[B]off\f[R]
63
+ \fR\-\-no\-plugins\f[] forces plugins \f[B]off\f[]
64
+
45
65
  .PP
46
66
  CLI flags always win over metadata.
67
+
47
68
  .SH PLUGIN LOCATIONS
69
+
70
+ .PP
48
71
  Plugins are discovered from two locations, in this order:
49
- .IP "1." 3
50
- \f[B]Project\-local plugins\f[R]
51
- .RS 4
72
+
73
+ .IP "1." 4
74
+ \f[B]Project\-local plugins\f[]
75
+
52
76
  .IP \(bu 2
53
- Directory: \f[CR].apex/plugins/\f[R] in the same project as your
54
- documents
77
+ Directory: \fR.apex/plugins/\f[] in the same project as your documents
78
+
55
79
  .IP \(bu 2
56
80
  Structure: one subdirectory per plugin, for example:
57
- .RS 2
81
+
58
82
  .IP \(bu 2
59
- \f[CR].apex/plugins/kbd/plugin.yml\f[R]
83
+ \fR.apex/plugins/kbd/plugin.yml\f[]
84
+
60
85
  .IP \(bu 2
61
- \f[CR].apex/plugins/kbd/kbd_plugin.rb\f[R]
62
- .RE
63
- .RE
64
- .IP "2." 3
65
- \f[B]Global (user) plugins\f[R]
66
- .RS 4
86
+ \fR.apex/plugins/kbd/kbd_plugin.rb\f[]
87
+
88
+ .IP "2." 4
89
+ \f[B]Global (user) plugins\f[]
90
+
67
91
  .IP \(bu 2
68
- If \f[CR]$XDG_CONFIG_HOME\f[R] is set:
69
- \f[CR]$XDG_CONFIG_HOME/apex/plugins/\f[R]
92
+ If \fR$XDG_CONFIG_HOME\f[] is set: \fR$XDG_CONFIG_HOME/apex/plugins/\f[]
93
+
70
94
  .IP \(bu 2
71
- Otherwise: \f[CR]\(ti/.config/apex/plugins/\f[R]
95
+ Otherwise: \fR~/.config/apex/plugins/\f[]
96
+
72
97
  .IP \(bu 2
73
98
  Same structure: one subdirectory per plugin
74
- .RE
99
+
75
100
  .PP
76
- \f[B]Plugin IDs must be unique.\f[R] If a project plugin and a global
77
- plugin share the same \f[CR]id\f[R], the project plugin wins and the
78
- global one is ignored.
101
+ \f[B]Plugin IDs must be unique.\f[] If a project plugin and a global plugin share the same \fRid\f[], the project plugin wins and the global one is ignored.
102
+
79
103
  .SH PROCESSING PHASES
80
- Apex exposes several phases in its pipeline.
81
- Plugins can hook into one or more phases:
104
+
105
+ .PP
106
+ Apex exposes several phases in its pipeline. Plugins can hook into one or more phases:
107
+
82
108
  .IP \(bu 2
83
- \f[B]\f[CB]pre_parse\f[B]\f[R]
84
- .RS 2
109
+ \f[B]\fRpre_parse\f[]\f[]
110
+
85
111
  .IP \(bu 2
86
112
  Runs on the raw Markdown text before it is parsed.
113
+
87
114
  .IP \(bu 2
88
- Good for: custom syntax (e.g.\ \f[CR]{% kbd ... %}\f[R]), textual
89
- rewrites, adding/removing markup before Apex sees it
90
- .RE
115
+ Good for: custom syntax (e.g. \fRAPEX_LIQUID_TAG_0\f[]), textual rewrites, adding/removing markup before Apex sees it
116
+
91
117
  .IP \(bu 2
92
- \f[B]\f[CB]post_render\f[B]\f[R]
93
- .RS 2
118
+ \f[B]\fRpost_render\f[]\f[]
119
+
94
120
  .IP \(bu 2
95
121
  Runs on the final HTML output after Apex finishes rendering.
122
+
96
123
  .IP \(bu 2
97
- Good for: wrapping elements in spans/divs, adding CSS classes, simple
98
- HTML post\-processing (e.g.\ turning \f[CR]:emoji:\f[R] into
99
- \f[CR]<span>\f[R])
100
- .RE
124
+ Good for: wrapping elements in spans/divs, adding CSS classes, simple HTML post\-processing (e.g. turning \fR:memo:\f[] into \fR<span>\f[])
125
+
101
126
  .PP
102
127
  Internally, plugins for each phase are run in a deterministic order:
103
- .IP "1." 3
104
- Sorted by priority (lower numbers first; default is \f[CR]100\f[R]).
105
- .IP "2." 3
106
- Ties broken by plugin \f[CR]id\f[R] (lexicographically).
128
+
129
+ .IP "1." 4
130
+ Sorted by priority (lower numbers first; default is \fR100\f[]).
131
+
132
+ .IP "2." 4
133
+ Ties broken by plugin \fRid\f[] (lexicographically).
134
+
107
135
  .SH PLUGIN MANIFEST
136
+
137
+ .PP
108
138
  Each plugin is defined by a manifest file:
139
+
109
140
  .IP \(bu 2
110
- \f[B]File name\f[R]: \f[CR]plugin.yml\f[R]
141
+ \f[B]File name\f[]: \fRplugin.yml\f[]
142
+
111
143
  .IP \(bu 2
112
- \f[B]Location\f[R]: inside the plugin\(cqs directory
144
+ \f[B]Location\f[]: inside the plugin’s directory
145
+
113
146
  .PP
114
147
  At minimum, a plugin needs:
115
- .IP
116
- .EX
148
+
149
+ .PP
150
+ .nf
151
+ \fR
117
152
  \-\-\-
118
- id\f[B]:\f[R] my\-plugin
119
- phase\f[B]:\f[R] pre_parse\f[I] # or post_render\f[R]
120
- priority\f[B]:\f[R] 100\f[I] # optional, lower runs earlier\f[R]
153
+ id: my\-plugin
154
+ phase: pre_parse # or post_render
155
+ priority: 100 # optional, lower runs earlier
121
156
  \-\-\-
122
- .EE
157
+
158
+ \f[]
159
+ .fi
160
+
123
161
  .PP
124
162
  From there, you choose one of two plugin types:
163
+
125
164
  .IP \(bu 2
126
- \f[B]External handler plugin\f[R] \- Runs an external command (Ruby,
127
- Python, shell, etc.).
128
- Declared with a \f[CR]handler.command\f[R] field.
165
+ \f[B]External handler plugin\f[] \- Runs an external command (Ruby, Python, shell, etc.). Declared with a \fRhandler.command\f[] field.
166
+
129
167
  .IP \(bu 2
130
- \f[B]Declarative regex plugin\f[R] \- No external code; in\-process
131
- regex search/replace.
132
- Declared with \f[CR]pattern\f[R] and \f[CR]replacement\f[R] fields.
168
+ \f[B]Declarative regex plugin\f[] \- No external code; in\-process regex search/replace. Declared with \fRpattern\f[] and \fRreplacement\f[] fields.
169
+
133
170
  .PP
134
- You can\(cqt mix both styles in a single plugin; if
135
- \f[CR]handler.command\f[R] is present, the plugin is treated as
136
- external.
171
+ You can’t mix both styles in a single plugin; if \fRhandler.command\f[] is present, the plugin is treated as external.
172
+
137
173
  .SS Metadata fields
138
- To support plugin directories, automatic installation, and future
139
- auto\-update tools, Apex understands several optional metadata fields in
140
- \f[CR]plugin.yml\f[R]:
174
+
175
+ .PP
176
+ To support plugin directories, automatic installation, and future auto\-update tools, Apex understands several optional metadata fields in \fRplugin.yml\f[]:
177
+
141
178
  .IP \(bu 2
142
- \f[B]\f[CB]title\f[B]\f[R]: Short, human\-friendly name for the plugin
179
+ \f[B]\fRtitle\f[]\f[]: Short, human\-friendly name for the plugin
180
+
143
181
  .IP \(bu 2
144
- \f[B]\f[CB]author\f[B]\f[R]: Free\-form author string
182
+ \f[B]\fRauthor\f[]\f[]: Free\-form author string
183
+
145
184
  .IP \(bu 2
146
- \f[B]\f[CB]description\f[B]\f[R]: One\-two sentence description of what
147
- the plugin does
185
+ \f[B]\fRdescription\f[]\f[]: One\-two sentence description of what the plugin does
186
+
148
187
  .IP \(bu 2
149
- \f[B]\f[CB]homepage\f[B]\f[R]: Informational URL where users can learn
150
- more about the plugin
188
+ \f[B]\fRhomepage\f[]\f[]: Informational URL where users can learn more about the plugin
189
+
151
190
  .IP \(bu 2
152
- \f[B]\f[CB]repo\f[B]\f[R]: Canonical Git URL for the plugin repository,
153
- used by Apex when installing plugins
191
+ \f[B]\fRrepo\f[]\f[]: Canonical Git URL for the plugin repository, used by Apex when installing plugins
192
+
154
193
  .IP \(bu 2
155
- \f[B]\f[CB]post_install\f[B]\f[R]: Optional command that Apex will run
156
- after cloning the plugin during \f[CR]\-\-install\-plugin\f[R]
194
+ \f[B]\fRpost_install\f[]\f[]: Optional command that Apex will run after cloning the plugin during \fR\-\-install\-plugin\f[]
195
+
157
196
  .PP
158
- Only \f[CR]id\f[R], \f[CR]phase\f[R], and either
159
- \f[CR]handler.command\f[R] (for external plugins) or
160
- \f[CR]pattern\f[R]/\f[CR]replacement\f[R] (for declarative plugins) are
161
- required for execution.
197
+ Only \fRid\f[], \fRphase\f[], and either \fRhandler.command\f[] (for external plugins) or \fRpattern\f[]/\fRreplacement\f[] (for declarative plugins) are required for execution.
198
+
162
199
  .SH EXTERNAL HANDLER PLUGINS
163
- An external handler plugin defines a command to run, which receives JSON
164
- on stdin and writes the transformed text to stdout.
200
+
201
+ .PP
202
+ An external handler plugin defines a command to run, which receives JSON on stdin and writes the transformed text to stdout.
203
+
165
204
  .SS Manifest example
166
- .IP
167
- .EX
205
+
206
+ .PP
207
+ .nf
208
+ \fR
168
209
  \-\-\-
169
- id\f[B]:\f[R] kbd
170
- title\f[B]:\f[R] Keyboard Shortcuts
171
- author\f[B]:\f[R] Brett Terpstra
172
- description\f[B]:\f[R] Render {% kbd ... %} key combos to HTML
173
- homepage\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-kbd\-plugin
174
- repo\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-kbd\-plugin.git
175
- phase\f[B]:\f[R] pre_parse
176
- priority\f[B]:\f[R] 100
177
- timeout_ms\f[B]:\f[R] 0\f[I] # optional\f[R]
178
- handler\f[B]:\f[R]
179
- command\f[B]:\f[R] \(dqruby kbd_plugin.rb\(dq
210
+ id: kbd
211
+ title: Keyboard Shortcuts
212
+ author: Brett Terpstra
213
+ description: Render APEX_LIQUID_TAG_1 key combos to HTML
214
+ homepage: https://github.com/ApexMarkdown/apex\-kbd\-plugin
215
+ repo: https://github.com/ApexMarkdown/apex\-kbd\-plugin.git
216
+ phase: pre_parse
217
+ priority: 100
218
+ timeout_ms: 0 # optional
219
+ handler:
220
+ command: "ruby kbd_plugin.rb"
180
221
  \-\-\-
181
- .EE
222
+
223
+ \f[]
224
+ .fi
225
+
182
226
  .SS JSON protocol
183
- For text phases (\f[CR]pre_parse\f[R], \f[CR]post_render\f[R]), Apex
184
- sends your command a JSON object on stdin:
185
- .IP
186
- .EX
227
+
228
+ .PP
229
+ For text phases (\fRpre_parse\f[], \fRpost_render\f[]), Apex sends your command a JSON object on stdin:
230
+
231
+ .PP
232
+ .nf
233
+ \fR
187
234
  {
188
- \(dqversion\(dq: 1,
189
- \(dqplugin_id\(dq: \(dqkbd\(dq,
190
- \(dqphase\(dq: \(dqpre_parse\(dq,
191
- \(dqtext\(dq: \(dqraw or rendered text here\(dq
235
+ "version": 1,
236
+ "plugin_id": "kbd",
237
+ "phase": "pre_parse",
238
+ "text": "raw or rendered text here"
192
239
  }
193
- .EE
240
+
241
+ \f[]
242
+ .fi
243
+
194
244
  .PP
195
245
  Your plugin should:
196
- .IP "1." 3
246
+
247
+ .IP "1." 4
197
248
  Read all of stdin.
198
- .IP "2." 3
249
+
250
+ .IP "2." 4
199
251
  Parse the JSON.
200
- .IP "3." 3
201
- Transform the \f[CR]text\f[R] field.
202
- .IP "4." 3
252
+
253
+ .IP "3." 4
254
+ Transform the \fRtext\f[] field.
255
+
256
+ .IP "4." 4
203
257
  Print the new text only to stdout (no extra JSON, headers, or logging).
258
+
204
259
  .PP
205
- If your plugin fails, times out, or prints nothing, Apex will treat it
206
- as a no\-op and continue gracefully.
260
+ If your plugin fails, times out, or prints nothing, Apex will treat it as a no\-op and continue gracefully.
261
+
207
262
  .SH DECLARATIVE REGEX PLUGINS
208
- For many cases, you don\(cqt need a script at all.
209
- A declarative regex plugin uses \f[CR]regex.h\f[R] inside Apex for fast
210
- in\-process search/replace.
263
+
264
+ .PP
265
+ For many cases, you don’t need a script at all. A declarative regex plugin uses \fRregex.h\f[] inside Apex for fast in\-process search/replace.
266
+
211
267
  .SS Manifest example
212
- .IP
213
- .EX
268
+
269
+ .PP
270
+ .nf
271
+ \fR
214
272
  \-\-\-
215
- id\f[B]:\f[R] emoji\-span
216
- title\f[B]:\f[R] Emoji span wrapper
217
- author\f[B]:\f[R] Brett Terpstra
218
- description\f[B]:\f[R] Wrap :emoji: markers in a span for styling
219
- homepage\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-emoji\-plugin
220
- repo\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-emoji\-plugin.git
221
- phase\f[B]:\f[R] post_render
222
- pattern\f[B]:\f[R] \(dq(:[a\-zA\-Z0\-9_+\-]+:)\(dq
223
- replacement\f[B]:\f[R] \(dq<span class=\(rs\(dqemoji\(rs\(dq>$1</span>\(dq
224
- flags\f[B]:\f[R] \(dqi\(dq\f[I] # optional: e.g. i, m, s\f[R]
225
- priority\f[B]:\f[R] 200
226
- timeout_ms\f[B]:\f[R] 0
273
+ id: emoji\-span
274
+ title: Emoji span wrapper
275
+ author: Brett Terpstra
276
+ description: Wrap :memo: markers in a span for styling
277
+ homepage: https://github.com/ApexMarkdown/apex\-emoji\-plugin
278
+ repo: https://github.com/ApexMarkdown/apex\-emoji\-plugin.git
279
+ phase: post_render
280
+ pattern: "(:[a\-zA\-Z0\-9_+\-]+:)"
281
+ replacement: "<span class=\e"emoji\e">$1</span>"
282
+ flags: "i" # optional: e.g. i, m, s
283
+ priority: 200
284
+ timeout_ms: 0
227
285
  \-\-\-
228
- .EE
286
+
287
+ \f[]
288
+ .fi
289
+
229
290
  .IP \(bu 2
230
- \f[B]\f[CB]pattern\f[B]\f[R]: POSIX regular expression (compiled via
231
- \f[CR]regcomp\f[R]).
291
+ \f[B]\fRpattern\f[]\f[]: POSIX regular expression (compiled via \fRregcomp\f[]).
292
+
232
293
  .IP \(bu 2
233
- \f[B]\f[CB]replacement\f[B]\f[R]: Replacement string with capture groups
234
- like \f[CR]$1\f[R], \f[CR]$2\f[R], etc.
235
- Runs repeatedly across the text until no more matches.
294
+ \f[B]\fRreplacement\f[]\f[]: Replacement string with capture groups like \fR$1\f[], \fR$2\f[], etc. Runs repeatedly across the text until no more matches.
295
+
236
296
  .IP \(bu 2
237
- \f[B]\f[CB]flags\f[B]\f[R] (optional): Currently supports \f[CR]i\f[R]
238
- (case\-insensitive), \f[CR]m\f[R] (multi\-line), \f[CR]s\f[R] (dot
239
- matches newline).
297
+ \f[B]\fRflags\f[]\f[] (optional): Currently supports \fRi\f[] (case\-insensitive), \fRm\f[] (multi\-line), \fRs\f[] (dot matches newline).
298
+
240
299
  .PP
241
- This is ideal when you only need straightforward pattern substitution
242
- and performance matters.
300
+ This is ideal when you only need straightforward pattern substitution and performance matters.
301
+
243
302
  .SH PLUGIN BUNDLES
244
- Sometimes it is convenient for a single repository to provide multiple
245
- related plugins as a bundle.
246
- Apex supports a bundle syntax in \f[CR]plugin.yml\f[R] when built with
247
- full YAML (libyaml) support.
303
+
304
+ .PP
305
+ Sometimes it is convenient for a single repository to provide multiple related plugins as a bundle. Apex supports a bundle syntax in \fRplugin.yml\f[] when built with full YAML (libyaml) support.
306
+
248
307
  .SS Bundle structure
308
+
309
+ .PP
249
310
  A bundle manifest has:
311
+
250
312
  .IP \(bu 2
251
313
  Top\-level metadata that applies to the bundle as a whole.
314
+
252
315
  .IP \(bu 2
253
- A \f[CR]bundle:\f[R] key whose value is a YAML sequence (array) of
254
- per\-plugin configs.
316
+ A \fRbundle:\f[] key whose value is a YAML sequence (array) of per\-plugin configs.
317
+
255
318
  .PP
256
319
  Example:
257
- .IP
258
- .EX
320
+
321
+ .PP
322
+ .nf
323
+ \fR
259
324
  \-\-\-
260
- id\f[B]:\f[R] documentation
261
- title\f[B]:\f[R] Documentation helpers
262
- author\f[B]:\f[R] Brett Terpstra
263
- description\f[B]:\f[R] A bundle of documentation\-related helpers
264
- homepage\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-plugin\-documentation
265
- repo\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-plugin\-documentation.git
266
-
267
- bundle\f[B]:\f[R]
268
- \f[B]\-\f[R] id\f[B]:\f[R] kbd
269
- title\f[B]:\f[R] Keyboard Shortcuts
270
- description\f[B]:\f[R] Render {% kbd ... %} key combos to HTML <kbd> elements
271
- phase\f[B]:\f[R] pre_parse
272
- priority\f[B]:\f[R] 100
273
- handler\f[B]:\f[R]
274
- command\f[B]:\f[R] \(dqruby kbd_plugin.rb\(dq
275
-
276
- \f[B]\-\f[R] id\f[B]:\f[R] menubar
277
- title\f[B]:\f[R] Menubar Paths
278
- description\f[B]:\f[R] Render {% menubar File, Open %} to a styled menu path
279
- phase\f[B]:\f[R] pre_parse
280
- handler\f[B]:\f[R]
281
- command\f[B]:\f[R] \(dqruby menubar_plugin.rb\(dq
325
+ id: documentation
326
+ title: Documentation helpers
327
+ author: Brett Terpstra
328
+ description: A bundle of documentation\-related helpers
329
+ homepage: https://github.com/ApexMarkdown/apex\-plugin\-documentation
330
+ repo: https://github.com/ApexMarkdown/apex\-plugin\-documentation.git
331
+ bundle:
332
+ \- id: kbd
333
+ title: Keyboard Shortcuts
334
+ description: Render APEX_LIQUID_TAG_2 key combos to HTML <kbd> elements
335
+ phase: pre_parse
336
+ priority: 100
337
+ handler:
338
+ command: "ruby kbd_plugin.rb"
339
+ \- id: menubar
340
+ title: Menubar Paths
341
+ description: Render APEX_LIQUID_TAG_3 to a styled menu path
342
+ phase: pre_parse
343
+ handler:
344
+ command: "ruby menubar_plugin.rb"
282
345
  \-\-\-
283
- .EE
346
+
347
+ \f[]
348
+ .fi
349
+
284
350
  .PP
285
- Apex will treat this as three distinct plugins: \f[CR]kbd\f[R],
286
- \f[CR]menubar\f[R], and \f[CR]prefspane\f[R], all sourced from the same
287
- repository and manifest.
351
+ Apex will treat this as three distinct plugins: \fRkbd\f[], \fRmenubar\f[], and \fRprefspane\f[], all sourced from the same repository and manifest.
352
+
288
353
  .SH ENVIRONMENT VARIABLES
354
+
355
+ .PP
289
356
  When Apex runs an external handler plugin, it sets:
357
+
290
358
  .IP \(bu 2
291
- \f[B]\f[CB]APEX_PLUGIN_DIR\f[B]\f[R]
292
- .RS 2
359
+ \f[B]\fRAPEX_PLUGIN_DIR\f[]\f[]
360
+
293
361
  .IP \(bu 2
294
- Filesystem path to the plugin\(cqs directory (where
295
- \f[CR]plugin.yml\f[R] lives).
362
+ Filesystem path to the plugin’s directory (where \fRplugin.yml\f[] lives).
363
+
296
364
  .IP \(bu 2
297
365
  Useful for loading sidecar files, templates, etc.
298
- .RE
366
+
299
367
  .IP \(bu 2
300
- \f[B]\f[CB]APEX_SUPPORT_DIR\f[B]\f[R]
301
- .RS 2
368
+ \f[B]\fRAPEX_SUPPORT_DIR\f[]\f[]
369
+
302
370
  .IP \(bu 2
303
- Base support directory: \f[CR]$XDG_CONFIG_HOME/apex/support/\f[R] or
304
- \f[CR]\(ti/.config/apex/support/\f[R]
371
+ Base support directory: \fR$XDG_CONFIG_HOME/apex/support/\f[] or \fR~/.config/apex/support/\f[]
372
+
305
373
  .IP \(bu 2
306
- For each plugin, Apex creates: \f[CR]APEX_SUPPORT_DIR/<plugin\-id>/\f[R]
374
+ For each plugin, Apex creates: \fRAPEX_SUPPORT_DIR/<plugin\-id>/\f[]
375
+
307
376
  .IP \(bu 2
308
377
  You can safely write caches, logs, or temporary files there.
309
- .RE
378
+
310
379
  .IP \(bu 2
311
- \f[B]\f[CB]APEX_FILE_PATH\f[B]\f[R]
312
- .RS 2
380
+ \f[B]\fRAPEX_FILE_PATH\f[]\f[]
381
+
313
382
  .IP \(bu 2
314
- When Apex is invoked on a file, this is the original path that was
315
- passed on the command line.
383
+ When Apex is invoked on a file, this is the original path that was passed on the command line.
384
+
316
385
  .IP \(bu 2
317
- When Apex reads from stdin, \f[CR]APEX_FILE_PATH\f[R] is set to the
318
- current \f[CR]base_directory\f[R] (if one was set) or an empty string.
319
- .RE
386
+ When Apex reads from stdin, \fRAPEX_FILE_PATH\f[] is set to the current \fRbase_directory\f[] (if one was set) or an empty string.
387
+
320
388
  .PP
321
- All of these variables apply only during the external command\(cqs
322
- execution and are restored afterward.
389
+ All of these variables apply only during the external command’s execution and are restored afterward.
390
+
323
391
  .SH INSTALLING PLUGINS
324
- Apex can install plugins directly from a central directory or from Git
325
- URLs.
392
+
393
+ .PP
394
+ Apex can install plugins directly from a central directory or from Git URLs.
395
+
326
396
  .SS Listing available plugins
327
- .IP
328
- .EX
397
+
398
+ .PP
399
+ .nf
400
+ \fR
329
401
  apex \-\-list\-plugins
330
- .EE
402
+
403
+ \f[]
404
+ .fi
405
+
331
406
  .PP
332
- This command fetches the plugin directory and prints a listing of
333
- installed and available plugins.
407
+ This command fetches the plugin directory and prints a listing of installed and available plugins.
408
+
334
409
  .SS Installing a plugin
335
- The \f[CR]\-\-install\-plugin\f[R] command accepts three types of
336
- arguments:
337
- .IP "1." 3
338
- \f[B]Plugin ID from the directory\f[R] (recommended for curated
339
- plugins):
340
- .RS 4
341
- .IP
342
- .EX
410
+
411
+ .PP
412
+ The \fR\-\-install\-plugin\f[] command accepts three types of arguments:
413
+
414
+ .IP "1." 4
415
+ \f[B]Plugin ID from the directory\f[] (recommended for curated plugins):
343
416
  apex \-\-install\-plugin kbd
344
- .EE
345
- .RE
346
- .IP "2." 3
347
- \f[B]Full Git URL\f[R] (for plugins not in the directory):
348
- .RS 4
349
- .IP
350
- .EX
417
+
418
+
419
+ .IP "2." 4
420
+ \f[B]Full Git URL\f[] (for plugins not in the directory):
351
421
  apex \-\-install\-plugin https://github.com/ttscoff/apex\-plugin\-kbd.git
352
- .EE
353
- .RE
354
- .IP "3." 3
355
- \f[B]GitHub shorthand\f[R] (\f[CR]user/repo\f[R] format):
356
- .RS 4
357
- .IP
358
- .EX
422
+
423
+
424
+ .IP "3." 4
425
+ \f[B]GitHub shorthand\f[] (\fRuser/repo\f[] format):
359
426
  apex \-\-install\-plugin ttscoff/apex\-plugin\-kbd
360
- .EE
361
- .RE
427
+
428
+
362
429
  .PP
363
- When installing from a direct Git URL or GitHub shorthand (i.e.,
364
- anything outside the curated directory), Apex will prompt for
365
- confirmation since plugins execute unverified code.
430
+ When installing from a direct Git URL or GitHub shorthand (i.e., anything outside the curated directory), Apex will prompt for confirmation since plugins execute unverified code.
431
+
366
432
  .SS Uninstalling a plugin
367
- .IP
368
- .EX
433
+
434
+ .PP
435
+ .nf
436
+ \fR
369
437
  apex \-\-uninstall\-plugin kbd
370
- .EE
371
- .PP
372
- The \f[CR]\-\-uninstall\-plugin\f[R] command verifies that the plugin
373
- directory exists, prompts for confirmation, and removes the plugin\(cqs
374
- directory.
375
- Support data under \f[CR].../apex/support/<plugin\-id>/\f[R] is left
376
- intact.
377
- .PP
378
- This command only works for plugins installed in the user plugin
379
- directory.
380
- Project\-local plugins (in \f[CR].apex/plugins/\f[R]) must be removed
381
- manually.
438
+
439
+ \f[]
440
+ .fi
441
+
442
+ .PP
443
+ The \fR\-\-uninstall\-plugin\f[] command verifies that the plugin directory exists, prompts for confirmation, and removes the plugin’s directory. Support data under \fR.../apex/support/<plugin\-id>/\f[] is left intact.
444
+
445
+ .PP
446
+ This command only works for plugins installed in the user plugin directory. Project\-local plugins (in \fR.apex/plugins/\f[]) must be removed manually.
447
+
382
448
  .SH EXAMPLES
383
- .SS Example: \f[CR]kbd\f[R] liquid tag plugin
384
- This example shows how to support a liquid\-style
385
- \f[CR]{% kbd ... %}\f[R] syntax, turning key combos into
386
- \f[CR]<kbd>\f[R] markup.
449
+
450
+ .SS Example: \fRkbd\f[] liquid tag plugin
451
+
452
+ .PP
453
+ This example shows how to support a liquid\-style \fRAPEX_LIQUID_TAG_4\f[] syntax, turning key combos into \fR<kbd>\f[] markup.
454
+
387
455
  .SS Directory layout
388
- .IP
389
- .EX
456
+
457
+ .PP
458
+ .nf
459
+ \fR
390
460
  \&.apex/
391
461
  plugins/
392
462
  kbd/
393
463
  plugin.yml
394
464
  kbd_plugin.rb
395
- .EE
396
- .SS \f[CR]plugin.yml\f[R]
397
- .IP
398
- .EX
465
+
466
+ \f[]
467
+ .fi
468
+
469
+ .SS \fRplugin.yml\f[]
470
+
471
+ .PP
472
+ .nf
473
+ \fR
399
474
  \-\-\-
400
- id\f[B]:\f[R] kbd
401
- title\f[B]:\f[R] Keyboard Shortcuts
402
- author\f[B]:\f[R] Brett Terpstra
403
- description\f[B]:\f[R] Render {% kbd ... %} key combos to HTML <kbd> elements
404
- homepage\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-kbd\-plugin
405
- repo\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-kbd\-plugin.git
406
- phase\f[B]:\f[R] pre_parse
407
- priority\f[B]:\f[R] 100
408
- timeout_ms\f[B]:\f[R] 0
409
- handler\f[B]:\f[R]
410
- command\f[B]:\f[R] \(dqruby kbd_plugin.rb\(dq
475
+ id: kbd
476
+ title: Keyboard Shortcuts
477
+ author: Brett Terpstra
478
+ description: Render APEX_LIQUID_TAG_5 key combos to HTML <kbd> elements
479
+ homepage: https://github.com/ApexMarkdown/apex\-kbd\-plugin
480
+ repo: https://github.com/ApexMarkdown/apex\-kbd\-plugin.git
481
+ phase: pre_parse
482
+ priority: 100
483
+ timeout_ms: 0
484
+ handler:
485
+ command: "ruby kbd_plugin.rb"
411
486
  \-\-\-
412
- .EE
413
- .PP
414
- The Ruby script reads JSON from stdin, extracts \f[CR]text\f[R],
415
- replaces each \f[CR]{% kbd ... %}\f[R] occurrence with properly
416
- formatted \f[CR]<kbd>\f[R] HTML, and prints the full transformed text to
417
- stdout.
418
- .SS Example: \f[CR]:emoji:\f[R] span plugin (declarative)
419
- This plugin turns \f[CR]:emoji:\f[R] tokens in the final HTML into
420
- \f[CR]<span class=\(dqemoji\(dq>:emoji:</span>\f[R].
421
- .SS \f[CR]plugin.yml\f[R]
422
- .IP
423
- .EX
487
+
488
+ \f[]
489
+ .fi
490
+
491
+ .PP
492
+ The Ruby script reads JSON from stdin, extracts \fRtext\f[], replaces each \fRAPEX_LIQUID_TAG_6\f[] occurrence with properly formatted \fR<kbd>\f[] HTML, and prints the full transformed text to stdout.
493
+
494
+ .SS Example: \fR:memo:\f[] span plugin (declarative)
495
+
496
+ .PP
497
+ This plugin turns \fR:memo:\f[] tokens in the final HTML into \fR<span class="emoji">:memo:</span>\f[].
498
+
499
+ .SS \fRplugin.yml\f[]
500
+
501
+ .PP
502
+ .nf
503
+ \fR
424
504
  \-\-\-
425
- id\f[B]:\f[R] emoji\-span
426
- title\f[B]:\f[R] Emoji span wrapper
427
- author\f[B]:\f[R] Brett Terpstra
428
- description\f[B]:\f[R] Wrap :emoji: markers in a span for styling
429
- homepage\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-emoji\-plugin
430
- repo\f[B]:\f[R] https://github.com/ApexMarkdown/apex\-emoji\-plugin.git
431
- phase\f[B]:\f[R] post_render
432
- pattern\f[B]:\f[R] \(dq(:[a\-zA\-Z0\-9_+\-]+:)\(dq
433
- replacement\f[B]:\f[R] \(dq<span class=\(rs\(dqemoji\(rs\(dq>$1</span>\(dq
434
- flags\f[B]:\f[R] \(dqi\(dq
435
- priority\f[B]:\f[R] 200
436
- timeout_ms\f[B]:\f[R] 0
505
+ id: emoji\-span
506
+ title: Emoji span wrapper
507
+ author: Brett Terpstra
508
+ description: Wrap :memo: markers in a span for styling
509
+ homepage: https://github.com/ApexMarkdown/apex\-emoji\-plugin
510
+ repo: https://github.com/ApexMarkdown/apex\-emoji\-plugin.git
511
+ phase: post_render
512
+ pattern: "(:[a\-zA\-Z0\-9_+\-]+:)"
513
+ replacement: "<span class=\e"emoji\e">$1</span>"
514
+ flags: "i"
515
+ priority: 200
516
+ timeout_ms: 0
437
517
  \-\-\-
438
- .EE
518
+
519
+ \f[]
520
+ .fi
521
+
439
522
  .PP
440
- Because this is a declarative plugin, no external command is run.
441
- Apex compiles the regex and runs the replacements internally.
523
+ Because this is a declarative plugin, no external command is run. Apex compiles the regex and runs the replacements internally.
524
+
442
525
  .SH SEE ALSO
443
- \f[B]apex\f[R](1), \f[B]apex\-config\f[R](5)
526
+
444
527
  .PP
445
- For complete documentation, see the \c
446
- .UR https://github.com/ttscoff/apex/wiki
447
- Apex Wiki
448
- .UE \c
449
- \&.
528
+ \f[B]apex\f[](1), \f[B]apex\-config\f[](5)
529
+
530
+ .PP
531
+ For complete documentation, see the Apex Wiki (https://github.com/ttscoff/apex/wiki).
532
+
450
533
  .SH AUTHOR
534
+
535
+ .PP
451
536
  Brett Terpstra
537
+
452
538
  .SH COPYRIGHT
453
- Copyright (c) 2025 Brett Terpstra.
454
- Licensed under MIT License.
455
- .SH AUTHORS
456
- Brett Terpstra.
539
+
540
+ .PP
541
+ Copyright (c) 2025 Brett Terpstra. Licensed under MIT License.