apex-ruby 1.0.6 → 1.0.7
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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#include "filters_ast.h"
|
|
2
|
+
#include "ast_json.h"
|
|
3
|
+
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include <string.h>
|
|
6
|
+
#include <unistd.h>
|
|
7
|
+
#include <sys/types.h>
|
|
8
|
+
#include <sys/wait.h>
|
|
9
|
+
#include <errno.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
|
|
12
|
+
/* Helper: run a single external filter command as a JSON AST transformer.
|
|
13
|
+
*
|
|
14
|
+
* Protocol:
|
|
15
|
+
* - Apex sends the Pandoc JSON AST on stdin (no wrapper object).
|
|
16
|
+
* - Filter writes a Pandoc JSON AST on stdout.
|
|
17
|
+
* - Target format is exposed via the APEX_TARGET_FORMAT env var.
|
|
18
|
+
*
|
|
19
|
+
* On success, returns a newly allocated JSON string; caller must free().
|
|
20
|
+
* On failure, returns NULL.
|
|
21
|
+
*/
|
|
22
|
+
static char *run_single_ast_filter(const char *cmd,
|
|
23
|
+
const char *target_format,
|
|
24
|
+
const char *json_input) {
|
|
25
|
+
if (!cmd || !*cmd || !json_input) return NULL;
|
|
26
|
+
|
|
27
|
+
/* Ensure target format env var is visible to the child process. */
|
|
28
|
+
if (target_format && *target_format) {
|
|
29
|
+
setenv("APEX_TARGET_FORMAT", target_format, 1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
int in_pipe[2];
|
|
33
|
+
int out_pipe[2];
|
|
34
|
+
if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
|
|
35
|
+
return NULL;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pid_t pid = fork();
|
|
39
|
+
if (pid == -1) {
|
|
40
|
+
close(in_pipe[0]); close(in_pipe[1]);
|
|
41
|
+
close(out_pipe[0]); close(out_pipe[1]);
|
|
42
|
+
return NULL;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (pid == 0) {
|
|
46
|
+
/* Child */
|
|
47
|
+
dup2(in_pipe[0], STDIN_FILENO);
|
|
48
|
+
dup2(out_pipe[1], STDOUT_FILENO);
|
|
49
|
+
close(in_pipe[0]); close(in_pipe[1]);
|
|
50
|
+
close(out_pipe[0]); close(out_pipe[1]);
|
|
51
|
+
|
|
52
|
+
execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
|
|
53
|
+
_exit(127);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Parent */
|
|
57
|
+
close(in_pipe[0]);
|
|
58
|
+
close(out_pipe[1]);
|
|
59
|
+
|
|
60
|
+
/* Write JSON to child stdin */
|
|
61
|
+
size_t json_len = strlen(json_input);
|
|
62
|
+
const char *p = json_input;
|
|
63
|
+
ssize_t remaining = (ssize_t)json_len;
|
|
64
|
+
while (remaining > 0) {
|
|
65
|
+
ssize_t written = write(in_pipe[1], p, (size_t)remaining);
|
|
66
|
+
if (written <= 0) break;
|
|
67
|
+
p += written;
|
|
68
|
+
remaining -= written;
|
|
69
|
+
}
|
|
70
|
+
close(in_pipe[1]);
|
|
71
|
+
|
|
72
|
+
/* Read child's stdout into a growable buffer */
|
|
73
|
+
size_t cap = 8192;
|
|
74
|
+
size_t size = 0;
|
|
75
|
+
char *buf = (char *)malloc(cap);
|
|
76
|
+
if (!buf) {
|
|
77
|
+
close(out_pipe[0]);
|
|
78
|
+
int status;
|
|
79
|
+
waitpid(pid, &status, 0);
|
|
80
|
+
return NULL;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (;;) {
|
|
84
|
+
if (size + 4096 > cap) {
|
|
85
|
+
cap *= 2;
|
|
86
|
+
char *nb = (char *)realloc(buf, cap);
|
|
87
|
+
if (!nb) {
|
|
88
|
+
free(buf);
|
|
89
|
+
close(out_pipe[0]);
|
|
90
|
+
int status;
|
|
91
|
+
waitpid(pid, &status, 0);
|
|
92
|
+
return NULL;
|
|
93
|
+
}
|
|
94
|
+
buf = nb;
|
|
95
|
+
}
|
|
96
|
+
ssize_t n = read(out_pipe[0], buf + size, 4096);
|
|
97
|
+
if (n < 0) {
|
|
98
|
+
if (errno == EINTR) continue;
|
|
99
|
+
free(buf);
|
|
100
|
+
close(out_pipe[0]);
|
|
101
|
+
int status;
|
|
102
|
+
waitpid(pid, &status, 0);
|
|
103
|
+
return NULL;
|
|
104
|
+
}
|
|
105
|
+
if (n == 0) break;
|
|
106
|
+
size += (size_t)n;
|
|
107
|
+
}
|
|
108
|
+
close(out_pipe[0]);
|
|
109
|
+
|
|
110
|
+
int status;
|
|
111
|
+
if (waitpid(pid, &status, 0) == -1) {
|
|
112
|
+
free(buf);
|
|
113
|
+
return NULL;
|
|
114
|
+
}
|
|
115
|
+
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
|
116
|
+
free(buf);
|
|
117
|
+
return NULL;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
buf[size] = '\0';
|
|
121
|
+
return buf;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
cmark_node *apex_run_ast_filters(cmark_node *document,
|
|
125
|
+
const apex_options *options,
|
|
126
|
+
const char *target_format) {
|
|
127
|
+
if (!document || !options) return document;
|
|
128
|
+
if (!options->ast_filter_commands || options->ast_filter_count == 0) {
|
|
129
|
+
return document;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Serialize once per filter step. We keep 'current_doc' as the latest
|
|
133
|
+
* successfully transformed tree reference.
|
|
134
|
+
*/
|
|
135
|
+
cmark_node *current_doc = document;
|
|
136
|
+
|
|
137
|
+
for (size_t i = 0; i < options->ast_filter_count; i++) {
|
|
138
|
+
const char *cmd = options->ast_filter_commands[i];
|
|
139
|
+
if (!cmd || !*cmd) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Serialize current_doc -> JSON */
|
|
144
|
+
char *json_in = apex_cmark_to_pandoc_json(current_doc, options);
|
|
145
|
+
if (!json_in) {
|
|
146
|
+
if (options->ast_filter_strict) {
|
|
147
|
+
return NULL;
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Run external filter */
|
|
153
|
+
char *json_out = run_single_ast_filter(cmd, target_format, json_in);
|
|
154
|
+
free(json_in);
|
|
155
|
+
|
|
156
|
+
if (!json_out) {
|
|
157
|
+
if (options->ast_filter_strict) {
|
|
158
|
+
return NULL;
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Parse JSON back into cmark */
|
|
164
|
+
cmark_node *new_doc = apex_pandoc_json_to_cmark(json_out, options);
|
|
165
|
+
free(json_out);
|
|
166
|
+
|
|
167
|
+
if (!new_doc) {
|
|
168
|
+
if (options->ast_filter_strict) {
|
|
169
|
+
return NULL;
|
|
170
|
+
}
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* If the filter returned a document with no blocks, keep the original
|
|
175
|
+
* to avoid blank output (e.g. parser dropped blocks it didn't recognise).
|
|
176
|
+
*/
|
|
177
|
+
if (!cmark_node_first_child(new_doc) && cmark_node_first_child(current_doc)) {
|
|
178
|
+
cmark_node_free(new_doc);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Replace current document with transformed one. We leave freeing
|
|
183
|
+
* of the original 'document' to the caller; we only free intermediate
|
|
184
|
+
* transformed trees that we owned.
|
|
185
|
+
*/
|
|
186
|
+
if (current_doc != document) {
|
|
187
|
+
cmark_node_free(current_doc);
|
|
188
|
+
}
|
|
189
|
+
current_doc = new_doc;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return current_doc;
|
|
193
|
+
}
|
|
194
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* filters_ast.h - Run Pandoc-style JSON AST filters over a cmark document.
|
|
3
|
+
*
|
|
4
|
+
* This module wires together:
|
|
5
|
+
* - cmark-gfm AST <-> Pandoc JSON AST (via ast_json.c)
|
|
6
|
+
* - External filter processes (one per configured command)
|
|
7
|
+
*
|
|
8
|
+
* Each filter command receives the JSON AST on stdin and is expected to
|
|
9
|
+
* write a (possibly transformed) JSON AST to stdout.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#ifndef APEX_FILTERS_AST_H
|
|
13
|
+
#define APEX_FILTERS_AST_H
|
|
14
|
+
|
|
15
|
+
#include "cmark-gfm.h"
|
|
16
|
+
#include "apex/apex.h"
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Run all configured AST filters (if any) over the given cmark document.
|
|
20
|
+
*
|
|
21
|
+
* @param document Root CMARK_NODE_DOCUMENT. Ownership remains with caller;
|
|
22
|
+
* on success, a NEW document is returned and the caller
|
|
23
|
+
* is responsible for freeing the old one if desired.
|
|
24
|
+
* @param options Apex options (must not be NULL).
|
|
25
|
+
* @param target_format Target writer format string (e.g. "html").
|
|
26
|
+
*
|
|
27
|
+
* @return New CMARK_NODE_DOCUMENT with transformations applied, or the original
|
|
28
|
+
* document pointer if no filters were run. On hard failure in strict
|
|
29
|
+
* mode, NULL is returned.
|
|
30
|
+
*/
|
|
31
|
+
cmark_node *apex_run_ast_filters(cmark_node *document,
|
|
32
|
+
const apex_options *options,
|
|
33
|
+
const char *target_format);
|
|
34
|
+
|
|
35
|
+
#endif /* APEX_FILTERS_AST_H */
|
|
36
|
+
|