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.
- checksums.yaml +4 -4
- data/ext/apex_ext/apex_ext.c +6 -0
- data/ext/apex_ext/apex_src/AGENTS.md +41 -0
- data/ext/apex_ext/apex_src/CHANGELOG.md +412 -2
- data/ext/apex_ext/apex_src/CMakeLists.txt +41 -29
- data/ext/apex_ext/apex_src/Formula/apex.rb +2 -2
- data/ext/apex_ext/apex_src/Package.swift +9 -0
- data/ext/apex_ext/apex_src/README.md +31 -9
- data/ext/apex_ext/apex_src/ROADMAP.md +5 -0
- data/ext/apex_ext/apex_src/VERSION +1 -1
- data/ext/apex_ext/apex_src/cli/main.c +1125 -13
- data/ext/apex_ext/apex_src/docs/index.md +459 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +67 -5
- data/ext/apex_ext/apex_src/include/apex/ast_man.h +20 -0
- data/ext/apex_ext/apex_src/include/apex/ast_markdown.h +39 -0
- data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +40 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +1 -1
- data/ext/apex_ext/apex_src/man/apex-config.5 +333 -258
- data/ext/apex_ext/apex_src/man/apex-config.5.md +3 -1
- data/ext/apex_ext/apex_src/man/apex-plugins.7 +401 -316
- data/ext/apex_ext/apex_src/man/apex.1 +663 -620
- data/ext/apex_ext/apex_src/man/apex.1.html +703 -0
- data/ext/apex_ext/apex_src/man/apex.1.md +160 -90
- data/ext/apex_ext/apex_src/objc/Apex.swift +6 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +12 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +9 -0
- data/ext/apex_ext/apex_src/pages/index.md +459 -0
- data/ext/apex_ext/apex_src/src/_README.md +4 -4
- data/ext/apex_ext/apex_src/src/apex.c +702 -44
- data/ext/apex_ext/apex_src/src/ast_json.c +1130 -0
- data/ext/apex_ext/apex_src/src/ast_json.h +46 -0
- data/ext/apex_ext/apex_src/src/ast_man.c +948 -0
- data/ext/apex_ext/apex_src/src/ast_markdown.c +409 -0
- data/ext/apex_ext/apex_src/src/ast_terminal.c +2516 -0
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +8 -5
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +491 -1514
- data/ext/apex_ext/apex_src/src/extensions/definition_list.h +8 -15
- data/ext/apex_ext/apex_src/src/extensions/emoji.c +207 -0
- data/ext/apex_ext/apex_src/src/extensions/emoji.h +14 -0
- data/ext/apex_ext/apex_src/src/extensions/header_ids.c +178 -71
- data/ext/apex_ext/apex_src/src/extensions/highlight.c +37 -5
- data/ext/apex_ext/apex_src/src/extensions/ial.c +416 -47
- data/ext/apex_ext/apex_src/src/extensions/includes.c +241 -10
- data/ext/apex_ext/apex_src/src/extensions/includes.h +1 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +166 -3
- data/ext/apex_ext/apex_src/src/extensions/metadata.h +7 -0
- data/ext/apex_ext/apex_src/src/extensions/sup_sub.c +34 -3
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +55 -10
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.h +7 -4
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +84 -52
- data/ext/apex_ext/apex_src/src/extensions/toc.c +133 -19
- data/ext/apex_ext/apex_src/src/filters_ast.c +194 -0
- data/ext/apex_ext/apex_src/src/filters_ast.h +36 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +1265 -35
- data/ext/apex_ext/apex_src/src/html_renderer.h +21 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +40 -14
- data/ext/apex_ext/apex_src/tests/CMakeLists.txt +1 -0
- data/ext/apex_ext/apex_src/tests/README.md +11 -5
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +13 -2
- data/ext/apex_ext/apex_src/tests/fixtures/filters/filter_output_with_rawblock.json +1 -0
- data/ext/apex_ext/apex_src/tests/fixtures/filters/unwrap.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/auto-wildcard.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.avif +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.jpg +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu.webp +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.avif +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.jpg +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/img/app-pass-1-profile-menu@2x.webp +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/media_formats_test.md +63 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/data-semi.csv +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/with space.txt +1 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/inline_tables_test.md +4 -1
- data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +64 -0
- data/ext/apex_ext/apex_src/tests/terminal_width_test.sh +29 -0
- data/ext/apex_ext/apex_src/tests/test-swift-package.sh +14 -0
- data/ext/apex_ext/apex_src/tests/test_cmark_callback.c +189 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +374 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +68 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +291 -2
- data/ext/apex_ext/apex_src/tests/test_runner.c +10 -0
- data/ext/apex_ext/apex_src/tests/test_syntax_highlight.c +1 -1
- data/ext/apex_ext/apex_src/tests/test_tables.c +17 -1
- data/lib/apex/version.rb +1 -1
- metadata +32 -2
- data/ext/apex_ext/apex_src/docs/FUTURE_FEATURES.md +0 -456
|
@@ -1,456 +1,541 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
Plugins can be small scripts (Ruby, Python, etc.)
|
|
10
|
-
|
|
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
|
|
13
|
-
|
|
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[
|
|
21
|
+
\f[B]Enable plugins\f[]: \fRapex \-\-plugins input.md\f[]
|
|
22
|
+
|
|
18
23
|
.IP \(bu 2
|
|
19
|
-
\f[B]Disable plugins\f[
|
|
24
|
+
\f[B]Disable plugins\f[]: \fRapex \-\-no\-plugins input.md\f[]
|
|
25
|
+
|
|
20
26
|
.SS Metadata keys
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
\
|
|
32
|
+
\fRplugins\f[]
|
|
33
|
+
|
|
25
34
|
.IP \(bu 2
|
|
26
|
-
\
|
|
35
|
+
\fRenable\-plugins\f[]
|
|
36
|
+
|
|
27
37
|
.IP \(bu 2
|
|
28
|
-
\
|
|
38
|
+
\fRenable_plugins\f[]
|
|
39
|
+
|
|
29
40
|
.PP
|
|
30
41
|
Example:
|
|
31
|
-
|
|
32
|
-
.
|
|
42
|
+
|
|
43
|
+
.PP
|
|
44
|
+
.nf
|
|
45
|
+
\fR
|
|
33
46
|
\-\-\-
|
|
34
|
-
title
|
|
35
|
-
plugins
|
|
47
|
+
title: Plugin demo
|
|
48
|
+
plugins: true
|
|
36
49
|
\-\-\-
|
|
37
|
-
|
|
50
|
+
|
|
51
|
+
\f[]
|
|
52
|
+
.fi
|
|
53
|
+
|
|
38
54
|
.SS Precedence
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
\
|
|
60
|
+
\fR\-\-plugins\f[] forces plugins \f[B]on\f[]
|
|
61
|
+
|
|
43
62
|
.IP \(bu 2
|
|
44
|
-
\
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
|
|
73
|
+
.IP "1." 4
|
|
74
|
+
\f[B]Project\-local plugins\f[]
|
|
75
|
+
|
|
52
76
|
.IP \(bu 2
|
|
53
|
-
Directory: \
|
|
54
|
-
|
|
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
|
-
|
|
81
|
+
|
|
58
82
|
.IP \(bu 2
|
|
59
|
-
\
|
|
83
|
+
\fR.apex/plugins/kbd/plugin.yml\f[]
|
|
84
|
+
|
|
60
85
|
.IP \(bu 2
|
|
61
|
-
\
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
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 \
|
|
69
|
-
|
|
92
|
+
If \fR$XDG_CONFIG_HOME\f[] is set: \fR$XDG_CONFIG_HOME/apex/plugins/\f[]
|
|
93
|
+
|
|
70
94
|
.IP \(bu 2
|
|
71
|
-
Otherwise: \
|
|
95
|
+
Otherwise: \fR~/.config/apex/plugins/\f[]
|
|
96
|
+
|
|
72
97
|
.IP \(bu 2
|
|
73
98
|
Same structure: one subdirectory per plugin
|
|
74
|
-
|
|
99
|
+
|
|
75
100
|
.PP
|
|
76
|
-
\f[B]Plugin IDs must be unique.\f[
|
|
77
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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]\
|
|
84
|
-
|
|
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
|
|
89
|
-
|
|
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]\
|
|
93
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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[
|
|
141
|
+
\f[B]File name\f[]: \fRplugin.yml\f[]
|
|
142
|
+
|
|
111
143
|
.IP \(bu 2
|
|
112
|
-
\f[B]Location\f[
|
|
144
|
+
\f[B]Location\f[]: inside the plugin’s directory
|
|
145
|
+
|
|
113
146
|
.PP
|
|
114
147
|
At minimum, a plugin needs:
|
|
115
|
-
|
|
116
|
-
.
|
|
148
|
+
|
|
149
|
+
.PP
|
|
150
|
+
.nf
|
|
151
|
+
\fR
|
|
117
152
|
\-\-\-
|
|
118
|
-
id
|
|
119
|
-
phase
|
|
120
|
-
priority
|
|
153
|
+
id: my\-plugin
|
|
154
|
+
phase: pre_parse # or post_render
|
|
155
|
+
priority: 100 # optional, lower runs earlier
|
|
121
156
|
\-\-\-
|
|
122
|
-
|
|
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[
|
|
127
|
-
|
|
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[
|
|
131
|
-
|
|
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
|
|
135
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
\
|
|
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]\
|
|
179
|
+
\f[B]\fRtitle\f[]\f[]: Short, human\-friendly name for the plugin
|
|
180
|
+
|
|
143
181
|
.IP \(bu 2
|
|
144
|
-
\f[B]\
|
|
182
|
+
\f[B]\fRauthor\f[]\f[]: Free\-form author string
|
|
183
|
+
|
|
145
184
|
.IP \(bu 2
|
|
146
|
-
\f[B]\
|
|
147
|
-
|
|
185
|
+
\f[B]\fRdescription\f[]\f[]: One\-two sentence description of what the plugin does
|
|
186
|
+
|
|
148
187
|
.IP \(bu 2
|
|
149
|
-
\f[B]\
|
|
150
|
-
|
|
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]\
|
|
153
|
-
|
|
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]\
|
|
156
|
-
|
|
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[
|
|
159
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
-
|
|
167
|
-
.
|
|
205
|
+
|
|
206
|
+
.PP
|
|
207
|
+
.nf
|
|
208
|
+
\fR
|
|
168
209
|
\-\-\-
|
|
169
|
-
id
|
|
170
|
-
title
|
|
171
|
-
author
|
|
172
|
-
description
|
|
173
|
-
homepage
|
|
174
|
-
repo
|
|
175
|
-
phase
|
|
176
|
-
priority
|
|
177
|
-
timeout_ms
|
|
178
|
-
handler
|
|
179
|
-
command
|
|
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
|
-
|
|
222
|
+
|
|
223
|
+
\f[]
|
|
224
|
+
.fi
|
|
225
|
+
|
|
182
226
|
.SS JSON protocol
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
235
|
+
"version": 1,
|
|
236
|
+
"plugin_id": "kbd",
|
|
237
|
+
"phase": "pre_parse",
|
|
238
|
+
"text": "raw or rendered text here"
|
|
192
239
|
}
|
|
193
|
-
|
|
240
|
+
|
|
241
|
+
\f[]
|
|
242
|
+
.fi
|
|
243
|
+
|
|
194
244
|
.PP
|
|
195
245
|
Your plugin should:
|
|
196
|
-
|
|
246
|
+
|
|
247
|
+
.IP "1." 4
|
|
197
248
|
Read all of stdin.
|
|
198
|
-
|
|
249
|
+
|
|
250
|
+
.IP "2." 4
|
|
199
251
|
Parse the JSON.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
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
|
-
|
|
213
|
-
.
|
|
268
|
+
|
|
269
|
+
.PP
|
|
270
|
+
.nf
|
|
271
|
+
\fR
|
|
214
272
|
\-\-\-
|
|
215
|
-
id
|
|
216
|
-
title
|
|
217
|
-
author
|
|
218
|
-
description
|
|
219
|
-
homepage
|
|
220
|
-
repo
|
|
221
|
-
phase
|
|
222
|
-
pattern
|
|
223
|
-
replacement
|
|
224
|
-
flags
|
|
225
|
-
priority
|
|
226
|
-
timeout_ms
|
|
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
|
-
|
|
286
|
+
|
|
287
|
+
\f[]
|
|
288
|
+
.fi
|
|
289
|
+
|
|
229
290
|
.IP \(bu 2
|
|
230
|
-
\f[B]\
|
|
231
|
-
|
|
291
|
+
\f[B]\fRpattern\f[]\f[]: POSIX regular expression (compiled via \fRregcomp\f[]).
|
|
292
|
+
|
|
232
293
|
.IP \(bu 2
|
|
233
|
-
\f[B]\
|
|
234
|
-
|
|
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]\
|
|
238
|
-
|
|
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
|
-
|
|
300
|
+
This is ideal when you only need straightforward pattern substitution and performance matters.
|
|
301
|
+
|
|
243
302
|
.SH PLUGIN BUNDLES
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Apex supports a bundle syntax in \
|
|
247
|
-
|
|
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 \
|
|
254
|
-
|
|
316
|
+
A \fRbundle:\f[] key whose value is a YAML sequence (array) of per\-plugin configs.
|
|
317
|
+
|
|
255
318
|
.PP
|
|
256
319
|
Example:
|
|
257
|
-
|
|
258
|
-
.
|
|
320
|
+
|
|
321
|
+
.PP
|
|
322
|
+
.nf
|
|
323
|
+
\fR
|
|
259
324
|
\-\-\-
|
|
260
|
-
id
|
|
261
|
-
title
|
|
262
|
-
author
|
|
263
|
-
description
|
|
264
|
-
homepage
|
|
265
|
-
repo
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
346
|
+
|
|
347
|
+
\f[]
|
|
348
|
+
.fi
|
|
349
|
+
|
|
284
350
|
.PP
|
|
285
|
-
Apex will treat this as three distinct plugins: \f[
|
|
286
|
-
|
|
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]\
|
|
292
|
-
|
|
359
|
+
\f[B]\fRAPEX_PLUGIN_DIR\f[]\f[]
|
|
360
|
+
|
|
293
361
|
.IP \(bu 2
|
|
294
|
-
Filesystem path to the plugin
|
|
295
|
-
|
|
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
|
-
|
|
366
|
+
|
|
299
367
|
.IP \(bu 2
|
|
300
|
-
\f[B]\
|
|
301
|
-
|
|
368
|
+
\f[B]\fRAPEX_SUPPORT_DIR\f[]\f[]
|
|
369
|
+
|
|
302
370
|
.IP \(bu 2
|
|
303
|
-
Base support directory: \
|
|
304
|
-
|
|
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: \
|
|
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
|
-
|
|
378
|
+
|
|
310
379
|
.IP \(bu 2
|
|
311
|
-
\f[B]\
|
|
312
|
-
|
|
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
|
-
|
|
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[
|
|
318
|
-
|
|
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
|
|
322
|
-
|
|
389
|
+
All of these variables apply only during the external command’s execution and are restored afterward.
|
|
390
|
+
|
|
323
391
|
.SH INSTALLING PLUGINS
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
328
|
-
.
|
|
397
|
+
|
|
398
|
+
.PP
|
|
399
|
+
.nf
|
|
400
|
+
\fR
|
|
329
401
|
apex \-\-list\-plugins
|
|
330
|
-
|
|
402
|
+
|
|
403
|
+
\f[]
|
|
404
|
+
.fi
|
|
405
|
+
|
|
331
406
|
.PP
|
|
332
|
-
This command fetches the plugin directory and prints a listing of
|
|
333
|
-
|
|
407
|
+
This command fetches the plugin directory and prints a listing of installed and available plugins.
|
|
408
|
+
|
|
334
409
|
.SS Installing a plugin
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
.IP "2."
|
|
347
|
-
\f[B]Full Git URL\f[
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
.IP "3."
|
|
355
|
-
\f[B]GitHub shorthand\f[
|
|
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
|
-
|
|
361
|
-
|
|
427
|
+
|
|
428
|
+
|
|
362
429
|
.PP
|
|
363
|
-
When installing from a direct Git URL or GitHub shorthand (i.e.,
|
|
364
|
-
|
|
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
|
-
|
|
368
|
-
.
|
|
433
|
+
|
|
434
|
+
.PP
|
|
435
|
+
.nf
|
|
436
|
+
\fR
|
|
369
437
|
apex \-\-uninstall\-plugin kbd
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
Support data under \
|
|
376
|
-
|
|
377
|
-
.PP
|
|
378
|
-
This command only works for plugins installed in the user plugin
|
|
379
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
389
|
-
.
|
|
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
|
-
|
|
396
|
-
|
|
397
|
-
.
|
|
398
|
-
|
|
465
|
+
|
|
466
|
+
\f[]
|
|
467
|
+
.fi
|
|
468
|
+
|
|
469
|
+
.SS \fRplugin.yml\f[]
|
|
470
|
+
|
|
471
|
+
.PP
|
|
472
|
+
.nf
|
|
473
|
+
\fR
|
|
399
474
|
\-\-\-
|
|
400
|
-
id
|
|
401
|
-
title
|
|
402
|
-
author
|
|
403
|
-
description
|
|
404
|
-
homepage
|
|
405
|
-
repo
|
|
406
|
-
phase
|
|
407
|
-
priority
|
|
408
|
-
timeout_ms
|
|
409
|
-
handler
|
|
410
|
-
command
|
|
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
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
stdout.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
.
|
|
422
|
-
.
|
|
423
|
-
|
|
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
|
|
426
|
-
title
|
|
427
|
-
author
|
|
428
|
-
description
|
|
429
|
-
homepage
|
|
430
|
-
repo
|
|
431
|
-
phase
|
|
432
|
-
pattern
|
|
433
|
-
replacement
|
|
434
|
-
flags
|
|
435
|
-
priority
|
|
436
|
-
timeout_ms
|
|
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
|
-
|
|
518
|
+
|
|
519
|
+
\f[]
|
|
520
|
+
.fi
|
|
521
|
+
|
|
439
522
|
.PP
|
|
440
|
-
Because this is a declarative plugin, no external command is run.
|
|
441
|
-
|
|
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
|
-
|
|
526
|
+
|
|
444
527
|
.PP
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
.
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
.
|
|
456
|
-
Brett Terpstra.
|
|
539
|
+
|
|
540
|
+
.PP
|
|
541
|
+
Copyright (c) 2025 Brett Terpstra. Licensed under MIT License.
|