commonmarker 0.23.10 → 2.1.1
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/Cargo.lock +1156 -0
- data/Cargo.toml +7 -0
- data/README.md +237 -172
- data/ext/commonmarker/Cargo.toml +20 -0
- data/ext/commonmarker/extconf.rb +3 -6
- data/ext/commonmarker/src/lib.rs +103 -0
- data/ext/commonmarker/src/node.rs +1221 -0
- data/ext/commonmarker/src/options.rs +220 -0
- data/ext/commonmarker/src/plugins/syntax_highlighting.rs +166 -0
- data/ext/commonmarker/src/plugins.rs +6 -0
- data/ext/commonmarker/src/utils.rs +8 -0
- data/lib/commonmarker/config.rb +92 -40
- data/lib/commonmarker/constants.rb +7 -0
- data/lib/commonmarker/extension.rb +14 -0
- data/lib/commonmarker/node/ast.rb +8 -0
- data/lib/commonmarker/node/inspect.rb +14 -4
- data/lib/commonmarker/node.rb +29 -47
- data/lib/commonmarker/renderer.rb +1 -127
- data/lib/commonmarker/utils.rb +22 -0
- data/lib/commonmarker/version.rb +2 -2
- data/lib/commonmarker.rb +27 -25
- metadata +38 -191
- data/Rakefile +0 -109
- data/bin/commonmarker +0 -118
- data/commonmarker.gemspec +0 -38
- data/ext/commonmarker/arena.c +0 -104
- data/ext/commonmarker/autolink.c +0 -508
- data/ext/commonmarker/autolink.h +0 -8
- data/ext/commonmarker/blocks.c +0 -1622
- data/ext/commonmarker/buffer.c +0 -278
- data/ext/commonmarker/buffer.h +0 -116
- data/ext/commonmarker/case_fold_switch.inc +0 -4327
- data/ext/commonmarker/chunk.h +0 -135
- data/ext/commonmarker/cmark-gfm-core-extensions.h +0 -54
- data/ext/commonmarker/cmark-gfm-extension_api.h +0 -737
- data/ext/commonmarker/cmark-gfm-extensions_export.h +0 -42
- data/ext/commonmarker/cmark-gfm.h +0 -833
- data/ext/commonmarker/cmark-gfm_export.h +0 -42
- data/ext/commonmarker/cmark-gfm_version.h +0 -7
- data/ext/commonmarker/cmark.c +0 -55
- data/ext/commonmarker/cmark_ctype.c +0 -44
- data/ext/commonmarker/cmark_ctype.h +0 -33
- data/ext/commonmarker/commonmark.c +0 -514
- data/ext/commonmarker/commonmarker.c +0 -1308
- data/ext/commonmarker/commonmarker.h +0 -16
- data/ext/commonmarker/config.h +0 -76
- data/ext/commonmarker/core-extensions.c +0 -27
- data/ext/commonmarker/entities.inc +0 -2138
- data/ext/commonmarker/ext_scanners.c +0 -879
- data/ext/commonmarker/ext_scanners.h +0 -24
- data/ext/commonmarker/footnotes.c +0 -63
- data/ext/commonmarker/footnotes.h +0 -27
- data/ext/commonmarker/houdini.h +0 -57
- data/ext/commonmarker/houdini_href_e.c +0 -100
- data/ext/commonmarker/houdini_html_e.c +0 -66
- data/ext/commonmarker/houdini_html_u.c +0 -149
- data/ext/commonmarker/html.c +0 -502
- data/ext/commonmarker/html.h +0 -27
- data/ext/commonmarker/inlines.c +0 -1788
- data/ext/commonmarker/inlines.h +0 -29
- data/ext/commonmarker/iterator.c +0 -159
- data/ext/commonmarker/iterator.h +0 -26
- data/ext/commonmarker/latex.c +0 -468
- data/ext/commonmarker/linked_list.c +0 -37
- data/ext/commonmarker/man.c +0 -274
- data/ext/commonmarker/map.c +0 -129
- data/ext/commonmarker/map.h +0 -44
- data/ext/commonmarker/node.c +0 -1045
- data/ext/commonmarker/node.h +0 -167
- data/ext/commonmarker/parser.h +0 -59
- data/ext/commonmarker/plaintext.c +0 -218
- data/ext/commonmarker/plugin.c +0 -36
- data/ext/commonmarker/plugin.h +0 -34
- data/ext/commonmarker/references.c +0 -43
- data/ext/commonmarker/references.h +0 -26
- data/ext/commonmarker/registry.c +0 -63
- data/ext/commonmarker/registry.h +0 -24
- data/ext/commonmarker/render.c +0 -213
- data/ext/commonmarker/render.h +0 -62
- data/ext/commonmarker/scanners.c +0 -14056
- data/ext/commonmarker/scanners.h +0 -70
- data/ext/commonmarker/scanners.re +0 -341
- data/ext/commonmarker/strikethrough.c +0 -167
- data/ext/commonmarker/strikethrough.h +0 -9
- data/ext/commonmarker/syntax_extension.c +0 -149
- data/ext/commonmarker/syntax_extension.h +0 -34
- data/ext/commonmarker/table.c +0 -917
- data/ext/commonmarker/table.h +0 -12
- data/ext/commonmarker/tagfilter.c +0 -60
- data/ext/commonmarker/tagfilter.h +0 -8
- data/ext/commonmarker/tasklist.c +0 -156
- data/ext/commonmarker/tasklist.h +0 -8
- data/ext/commonmarker/utf8.c +0 -317
- data/ext/commonmarker/utf8.h +0 -35
- data/ext/commonmarker/xml.c +0 -182
- data/lib/commonmarker/renderer/html_renderer.rb +0 -256
data/ext/commonmarker/table.c
DELETED
@@ -1,917 +0,0 @@
|
|
1
|
-
#include <cmark-gfm-extension_api.h>
|
2
|
-
#include <html.h>
|
3
|
-
#include <inlines.h>
|
4
|
-
#include <parser.h>
|
5
|
-
#include <references.h>
|
6
|
-
#include <string.h>
|
7
|
-
#include <render.h>
|
8
|
-
|
9
|
-
#include "ext_scanners.h"
|
10
|
-
#include "strikethrough.h"
|
11
|
-
#include "table.h"
|
12
|
-
#include "cmark-gfm-core-extensions.h"
|
13
|
-
|
14
|
-
// Limit to prevent a malicious input from causing a denial of service.
|
15
|
-
#define MAX_AUTOCOMPLETED_CELLS 0x80000
|
16
|
-
|
17
|
-
// Custom node flag, initialized in `create_table_extension`.
|
18
|
-
static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED;
|
19
|
-
|
20
|
-
cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
|
21
|
-
CMARK_NODE_TABLE_CELL;
|
22
|
-
|
23
|
-
typedef struct {
|
24
|
-
cmark_strbuf *buf;
|
25
|
-
int start_offset, end_offset, internal_offset;
|
26
|
-
} node_cell;
|
27
|
-
|
28
|
-
typedef struct {
|
29
|
-
uint16_t n_columns;
|
30
|
-
int paragraph_offset;
|
31
|
-
node_cell *cells;
|
32
|
-
} table_row;
|
33
|
-
|
34
|
-
typedef struct {
|
35
|
-
uint16_t n_columns;
|
36
|
-
uint8_t *alignments;
|
37
|
-
int n_rows;
|
38
|
-
int n_nonempty_cells;
|
39
|
-
} node_table;
|
40
|
-
|
41
|
-
typedef struct {
|
42
|
-
bool is_header;
|
43
|
-
} node_table_row;
|
44
|
-
|
45
|
-
static void free_table_cell(cmark_mem *mem, node_cell *cell) {
|
46
|
-
cmark_strbuf_free((cmark_strbuf *)cell->buf);
|
47
|
-
mem->free(cell->buf);
|
48
|
-
}
|
49
|
-
|
50
|
-
static void free_row_cells(cmark_mem *mem, table_row *row) {
|
51
|
-
while (row->n_columns > 0) {
|
52
|
-
free_table_cell(mem, &row->cells[--row->n_columns]);
|
53
|
-
}
|
54
|
-
mem->free(row->cells);
|
55
|
-
row->cells = NULL;
|
56
|
-
}
|
57
|
-
|
58
|
-
static void free_table_row(cmark_mem *mem, table_row *row) {
|
59
|
-
if (!row)
|
60
|
-
return;
|
61
|
-
|
62
|
-
free_row_cells(mem, row);
|
63
|
-
mem->free(row);
|
64
|
-
}
|
65
|
-
|
66
|
-
static void free_node_table(cmark_mem *mem, void *ptr) {
|
67
|
-
node_table *t = (node_table *)ptr;
|
68
|
-
mem->free(t->alignments);
|
69
|
-
mem->free(t);
|
70
|
-
}
|
71
|
-
|
72
|
-
static void free_node_table_row(cmark_mem *mem, void *ptr) {
|
73
|
-
mem->free(ptr);
|
74
|
-
}
|
75
|
-
|
76
|
-
static int get_n_table_columns(cmark_node *node) {
|
77
|
-
if (!node || node->type != CMARK_NODE_TABLE)
|
78
|
-
return -1;
|
79
|
-
|
80
|
-
return (int)((node_table *)node->as.opaque)->n_columns;
|
81
|
-
}
|
82
|
-
|
83
|
-
static int set_n_table_columns(cmark_node *node, uint16_t n_columns) {
|
84
|
-
if (!node || node->type != CMARK_NODE_TABLE)
|
85
|
-
return 0;
|
86
|
-
|
87
|
-
((node_table *)node->as.opaque)->n_columns = n_columns;
|
88
|
-
return 1;
|
89
|
-
}
|
90
|
-
|
91
|
-
// Increment the number of rows in the table. Also update n_nonempty_cells,
|
92
|
-
// which keeps track of the number of cells which were parsed from the
|
93
|
-
// input file. (If one of the rows is too short, then the trailing cells
|
94
|
-
// are autocompleted. Autocompleted cells are not counted in n_nonempty_cells.)
|
95
|
-
// The purpose of this is to prevent a malicious input from generating a very
|
96
|
-
// large number of autocompleted cells, which could cause a denial of service
|
97
|
-
// vulnerability.
|
98
|
-
static int incr_table_row_count(cmark_node *node, int i) {
|
99
|
-
if (!node || node->type != CMARK_NODE_TABLE) {
|
100
|
-
return 0;
|
101
|
-
}
|
102
|
-
|
103
|
-
((node_table *)node->as.opaque)->n_rows++;
|
104
|
-
((node_table *)node->as.opaque)->n_nonempty_cells += i;
|
105
|
-
return 1;
|
106
|
-
}
|
107
|
-
|
108
|
-
// Calculate the number of autocompleted cells.
|
109
|
-
static int get_n_autocompleted_cells(cmark_node *node) {
|
110
|
-
if (!node || node->type != CMARK_NODE_TABLE) {
|
111
|
-
return 0;
|
112
|
-
}
|
113
|
-
|
114
|
-
const node_table *nt = (node_table *)node->as.opaque;
|
115
|
-
return (nt->n_columns * nt->n_rows) - nt->n_nonempty_cells;
|
116
|
-
}
|
117
|
-
|
118
|
-
static uint8_t *get_table_alignments(cmark_node *node) {
|
119
|
-
if (!node || node->type != CMARK_NODE_TABLE)
|
120
|
-
return 0;
|
121
|
-
|
122
|
-
return ((node_table *)node->as.opaque)->alignments;
|
123
|
-
}
|
124
|
-
|
125
|
-
static int set_table_alignments(cmark_node *node, uint8_t *alignments) {
|
126
|
-
if (!node || node->type != CMARK_NODE_TABLE)
|
127
|
-
return 0;
|
128
|
-
|
129
|
-
((node_table *)node->as.opaque)->alignments = alignments;
|
130
|
-
return 1;
|
131
|
-
}
|
132
|
-
|
133
|
-
static uint8_t get_cell_alignment(cmark_node *node) {
|
134
|
-
if (!node || node->type != CMARK_NODE_TABLE_CELL)
|
135
|
-
return 0;
|
136
|
-
|
137
|
-
const uint8_t *alignments = get_table_alignments(node->parent->parent);
|
138
|
-
int i = node->as.cell_index;
|
139
|
-
return alignments[i];
|
140
|
-
}
|
141
|
-
|
142
|
-
static int set_cell_index(cmark_node *node, int i) {
|
143
|
-
if (!node || node->type != CMARK_NODE_TABLE_CELL)
|
144
|
-
return 0;
|
145
|
-
|
146
|
-
node->as.cell_index = i;
|
147
|
-
return 1;
|
148
|
-
}
|
149
|
-
|
150
|
-
static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsize_t len)
|
151
|
-
{
|
152
|
-
cmark_strbuf *res = (cmark_strbuf *)mem->calloc(1, sizeof(cmark_strbuf));
|
153
|
-
bufsize_t r, w;
|
154
|
-
|
155
|
-
cmark_strbuf_init(mem, res, len + 1);
|
156
|
-
cmark_strbuf_put(res, string, len);
|
157
|
-
cmark_strbuf_putc(res, '\0');
|
158
|
-
|
159
|
-
for (r = 0, w = 0; r < len; ++r) {
|
160
|
-
if (res->ptr[r] == '\\' && res->ptr[r + 1] == '|')
|
161
|
-
r++;
|
162
|
-
|
163
|
-
res->ptr[w++] = res->ptr[r];
|
164
|
-
}
|
165
|
-
|
166
|
-
cmark_strbuf_truncate(res, w);
|
167
|
-
|
168
|
-
return res;
|
169
|
-
}
|
170
|
-
|
171
|
-
// Adds a new cell to the end of the row. A pointer to the new cell is returned
|
172
|
-
// for the caller to initialize.
|
173
|
-
static node_cell* append_row_cell(cmark_mem *mem, table_row *row) {
|
174
|
-
const uint32_t n_columns = row->n_columns + 1;
|
175
|
-
// realloc when n_columns is a power of 2
|
176
|
-
if ((n_columns & (n_columns-1)) == 0) {
|
177
|
-
// make sure we never wrap row->n_columns
|
178
|
-
// offset will != len and our exit will clean up as intended
|
179
|
-
if (n_columns > UINT16_MAX) {
|
180
|
-
return NULL;
|
181
|
-
}
|
182
|
-
// Use realloc to double the size of the buffer.
|
183
|
-
row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell));
|
184
|
-
}
|
185
|
-
row->n_columns = (uint16_t)n_columns;
|
186
|
-
return &row->cells[n_columns-1];
|
187
|
-
}
|
188
|
-
|
189
|
-
static table_row *row_from_string(cmark_syntax_extension *self,
|
190
|
-
cmark_parser *parser, unsigned char *string,
|
191
|
-
int len) {
|
192
|
-
// Parses a single table row. It has the following form:
|
193
|
-
// `delim? table_cell (delim table_cell)* delim? newline`
|
194
|
-
// Note that cells are allowed to be empty.
|
195
|
-
//
|
196
|
-
// From the GitHub-flavored Markdown specification:
|
197
|
-
//
|
198
|
-
// > Each row consists of cells containing arbitrary text, in which inlines
|
199
|
-
// > are parsed, separated by pipes (|). A leading and trailing pipe is also
|
200
|
-
// > recommended for clarity of reading, and if there’s otherwise parsing
|
201
|
-
// > ambiguity.
|
202
|
-
|
203
|
-
table_row *row = NULL;
|
204
|
-
bufsize_t cell_matched = 1, pipe_matched = 1, offset;
|
205
|
-
int expect_more_cells = 1;
|
206
|
-
int row_end_offset = 0;
|
207
|
-
int int_overflow_abort = 0;
|
208
|
-
|
209
|
-
row = (table_row *)parser->mem->calloc(1, sizeof(table_row));
|
210
|
-
row->n_columns = 0;
|
211
|
-
row->cells = NULL;
|
212
|
-
|
213
|
-
// Scan past the (optional) leading pipe.
|
214
|
-
offset = scan_table_cell_end(string, len, 0);
|
215
|
-
|
216
|
-
// Parse the cells of the row. Stop if we reach the end of the input, or if we
|
217
|
-
// cannot detect any more cells.
|
218
|
-
while (offset < len && expect_more_cells) {
|
219
|
-
cell_matched = scan_table_cell(string, len, offset);
|
220
|
-
pipe_matched = scan_table_cell_end(string, len, offset + cell_matched);
|
221
|
-
|
222
|
-
if (cell_matched || pipe_matched) {
|
223
|
-
// We are guaranteed to have a cell, since (1) either we found some
|
224
|
-
// content and cell_matched, or (2) we found an empty cell followed by a
|
225
|
-
// pipe.
|
226
|
-
cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
|
227
|
-
cell_matched);
|
228
|
-
cmark_strbuf_trim(cell_buf);
|
229
|
-
|
230
|
-
node_cell *cell = append_row_cell(parser->mem, row);
|
231
|
-
if (!cell) {
|
232
|
-
int_overflow_abort = 1;
|
233
|
-
cmark_strbuf_free(cell_buf);
|
234
|
-
parser->mem->free(cell_buf);
|
235
|
-
break;
|
236
|
-
}
|
237
|
-
cell->buf = cell_buf;
|
238
|
-
cell->start_offset = offset;
|
239
|
-
cell->end_offset = offset + cell_matched - 1;
|
240
|
-
cell->internal_offset = 0;
|
241
|
-
|
242
|
-
while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') {
|
243
|
-
--cell->start_offset;
|
244
|
-
++cell->internal_offset;
|
245
|
-
}
|
246
|
-
}
|
247
|
-
|
248
|
-
offset += cell_matched + pipe_matched;
|
249
|
-
|
250
|
-
if (pipe_matched) {
|
251
|
-
expect_more_cells = 1;
|
252
|
-
} else {
|
253
|
-
// We've scanned the last cell. Check if we have reached the end of the row
|
254
|
-
row_end_offset = scan_table_row_end(string, len, offset);
|
255
|
-
offset += row_end_offset;
|
256
|
-
|
257
|
-
// If the end of the row is not the end of the input,
|
258
|
-
// the row is not a real row but potentially part of the paragraph
|
259
|
-
// preceding the table.
|
260
|
-
if (row_end_offset && offset != len) {
|
261
|
-
row->paragraph_offset = offset;
|
262
|
-
|
263
|
-
free_row_cells(parser->mem, row);
|
264
|
-
|
265
|
-
// Scan past the (optional) leading pipe.
|
266
|
-
offset += scan_table_cell_end(string, len, offset);
|
267
|
-
|
268
|
-
expect_more_cells = 1;
|
269
|
-
} else {
|
270
|
-
expect_more_cells = 0;
|
271
|
-
}
|
272
|
-
}
|
273
|
-
}
|
274
|
-
|
275
|
-
if (offset != len || row->n_columns == 0 || int_overflow_abort) {
|
276
|
-
free_table_row(parser->mem, row);
|
277
|
-
row = NULL;
|
278
|
-
}
|
279
|
-
|
280
|
-
return row;
|
281
|
-
}
|
282
|
-
|
283
|
-
static void try_inserting_table_header_paragraph(cmark_parser *parser,
|
284
|
-
cmark_node *parent_container,
|
285
|
-
unsigned char *parent_string,
|
286
|
-
int paragraph_offset) {
|
287
|
-
cmark_node *paragraph;
|
288
|
-
cmark_strbuf *paragraph_content;
|
289
|
-
|
290
|
-
paragraph = cmark_node_new_with_mem(CMARK_NODE_PARAGRAPH, parser->mem);
|
291
|
-
|
292
|
-
paragraph_content = unescape_pipes(parser->mem, parent_string, paragraph_offset);
|
293
|
-
cmark_strbuf_trim(paragraph_content);
|
294
|
-
cmark_node_set_string_content(paragraph, (char *) paragraph_content->ptr);
|
295
|
-
cmark_strbuf_free(paragraph_content);
|
296
|
-
parser->mem->free(paragraph_content);
|
297
|
-
|
298
|
-
if (!cmark_node_insert_before(parent_container, paragraph)) {
|
299
|
-
parser->mem->free(paragraph);
|
300
|
-
}
|
301
|
-
}
|
302
|
-
|
303
|
-
static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
|
304
|
-
cmark_parser *parser,
|
305
|
-
cmark_node *parent_container,
|
306
|
-
unsigned char *input, int len) {
|
307
|
-
cmark_node *table_header;
|
308
|
-
table_row *header_row = NULL;
|
309
|
-
table_row *delimiter_row = NULL;
|
310
|
-
node_table_row *ntr;
|
311
|
-
const char *parent_string;
|
312
|
-
uint16_t i;
|
313
|
-
|
314
|
-
if (parent_container->flags & CMARK_NODE__TABLE_VISITED) {
|
315
|
-
return parent_container;
|
316
|
-
}
|
317
|
-
|
318
|
-
if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
|
319
|
-
return parent_container;
|
320
|
-
}
|
321
|
-
|
322
|
-
// Since scan_table_start was successful, we must have a delimiter row.
|
323
|
-
delimiter_row = row_from_string(
|
324
|
-
self, parser, input + cmark_parser_get_first_nonspace(parser),
|
325
|
-
len - cmark_parser_get_first_nonspace(parser));
|
326
|
-
// assert may be optimized out, don't rely on it for security boundaries
|
327
|
-
if (!delimiter_row) {
|
328
|
-
return parent_container;
|
329
|
-
}
|
330
|
-
|
331
|
-
assert(delimiter_row);
|
332
|
-
|
333
|
-
cmark_arena_push();
|
334
|
-
|
335
|
-
// Check for a matching header row. We call `row_from_string` with the entire
|
336
|
-
// (potentially long) parent container as input, but this should be safe since
|
337
|
-
// `row_from_string` bails out early if it does not find a row.
|
338
|
-
parent_string = cmark_node_get_string_content(parent_container);
|
339
|
-
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
|
340
|
-
(int)strlen(parent_string));
|
341
|
-
if (!header_row || header_row->n_columns != delimiter_row->n_columns) {
|
342
|
-
free_table_row(parser->mem, delimiter_row);
|
343
|
-
free_table_row(parser->mem, header_row);
|
344
|
-
cmark_arena_pop();
|
345
|
-
parent_container->flags |= CMARK_NODE__TABLE_VISITED;
|
346
|
-
return parent_container;
|
347
|
-
}
|
348
|
-
|
349
|
-
if (cmark_arena_pop()) {
|
350
|
-
delimiter_row = row_from_string(
|
351
|
-
self, parser, input + cmark_parser_get_first_nonspace(parser),
|
352
|
-
len - cmark_parser_get_first_nonspace(parser));
|
353
|
-
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
|
354
|
-
(int)strlen(parent_string));
|
355
|
-
// row_from_string can return NULL, add additional check to ensure n_columns match
|
356
|
-
if (!delimiter_row || !header_row || header_row->n_columns != delimiter_row->n_columns) {
|
357
|
-
free_table_row(parser->mem, delimiter_row);
|
358
|
-
free_table_row(parser->mem, header_row);
|
359
|
-
return parent_container;
|
360
|
-
}
|
361
|
-
}
|
362
|
-
|
363
|
-
if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
|
364
|
-
free_table_row(parser->mem, header_row);
|
365
|
-
free_table_row(parser->mem, delimiter_row);
|
366
|
-
return parent_container;
|
367
|
-
}
|
368
|
-
|
369
|
-
if (header_row->paragraph_offset) {
|
370
|
-
try_inserting_table_header_paragraph(parser, parent_container, (unsigned char *)parent_string,
|
371
|
-
header_row->paragraph_offset);
|
372
|
-
}
|
373
|
-
|
374
|
-
cmark_node_set_syntax_extension(parent_container, self);
|
375
|
-
parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table));
|
376
|
-
set_n_table_columns(parent_container, header_row->n_columns);
|
377
|
-
|
378
|
-
// allocate alignments based on delimiter_row->n_columns
|
379
|
-
// since we populate the alignments array based on delimiter_row->cells
|
380
|
-
uint8_t *alignments =
|
381
|
-
(uint8_t *)parser->mem->calloc(delimiter_row->n_columns, sizeof(uint8_t));
|
382
|
-
for (i = 0; i < delimiter_row->n_columns; ++i) {
|
383
|
-
node_cell *node = &delimiter_row->cells[i];
|
384
|
-
bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':';
|
385
|
-
|
386
|
-
if (left && right)
|
387
|
-
alignments[i] = 'c';
|
388
|
-
else if (left)
|
389
|
-
alignments[i] = 'l';
|
390
|
-
else if (right)
|
391
|
-
alignments[i] = 'r';
|
392
|
-
}
|
393
|
-
set_table_alignments(parent_container, alignments);
|
394
|
-
|
395
|
-
table_header =
|
396
|
-
cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW,
|
397
|
-
parent_container->start_column);
|
398
|
-
cmark_node_set_syntax_extension(table_header, self);
|
399
|
-
table_header->end_column = parent_container->start_column + (int)strlen(parent_string) - 2;
|
400
|
-
table_header->start_line = table_header->end_line = parent_container->start_line;
|
401
|
-
|
402
|
-
table_header->as.opaque = ntr = (node_table_row *)parser->mem->calloc(1, sizeof(node_table_row));
|
403
|
-
ntr->is_header = true;
|
404
|
-
|
405
|
-
for (i = 0; i < header_row->n_columns; ++i) {
|
406
|
-
node_cell *cell = &header_row->cells[i];
|
407
|
-
cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
|
408
|
-
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
|
409
|
-
header_cell->start_line = header_cell->end_line = parent_container->start_line;
|
410
|
-
header_cell->internal_offset = cell->internal_offset;
|
411
|
-
header_cell->end_column = parent_container->start_column + cell->end_offset;
|
412
|
-
cmark_node_set_string_content(header_cell, (char *) cell->buf->ptr);
|
413
|
-
cmark_node_set_syntax_extension(header_cell, self);
|
414
|
-
set_cell_index(header_cell, i);
|
415
|
-
}
|
416
|
-
|
417
|
-
incr_table_row_count(parent_container, i);
|
418
|
-
|
419
|
-
cmark_parser_advance_offset(
|
420
|
-
parser, (char *)input,
|
421
|
-
(int)strlen((char *)input) - 1 - cmark_parser_get_offset(parser), false);
|
422
|
-
|
423
|
-
free_table_row(parser->mem, header_row);
|
424
|
-
free_table_row(parser->mem, delimiter_row);
|
425
|
-
return parent_container;
|
426
|
-
}
|
427
|
-
|
428
|
-
static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
|
429
|
-
cmark_parser *parser,
|
430
|
-
cmark_node *parent_container,
|
431
|
-
unsigned char *input, int len) {
|
432
|
-
cmark_node *table_row_block;
|
433
|
-
table_row *row;
|
434
|
-
|
435
|
-
if (cmark_parser_is_blank(parser))
|
436
|
-
return NULL;
|
437
|
-
|
438
|
-
if (get_n_autocompleted_cells(parent_container) > MAX_AUTOCOMPLETED_CELLS) {
|
439
|
-
return NULL;
|
440
|
-
}
|
441
|
-
|
442
|
-
table_row_block =
|
443
|
-
cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW,
|
444
|
-
parent_container->start_column);
|
445
|
-
cmark_node_set_syntax_extension(table_row_block, self);
|
446
|
-
table_row_block->end_column = parent_container->end_column;
|
447
|
-
table_row_block->as.opaque = parser->mem->calloc(1, sizeof(node_table_row));
|
448
|
-
|
449
|
-
row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser),
|
450
|
-
len - cmark_parser_get_first_nonspace(parser));
|
451
|
-
|
452
|
-
if (!row) {
|
453
|
-
// clean up the dangling node
|
454
|
-
cmark_node_free(table_row_block);
|
455
|
-
return NULL;
|
456
|
-
}
|
457
|
-
|
458
|
-
{
|
459
|
-
int i, table_columns = get_n_table_columns(parent_container);
|
460
|
-
|
461
|
-
for (i = 0; i < row->n_columns && i < table_columns; ++i) {
|
462
|
-
node_cell *cell = &row->cells[i];
|
463
|
-
cmark_node *node = cmark_parser_add_child(parser, table_row_block,
|
464
|
-
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
|
465
|
-
node->internal_offset = cell->internal_offset;
|
466
|
-
node->end_column = parent_container->start_column + cell->end_offset;
|
467
|
-
cmark_node_set_string_content(node, (char *) cell->buf->ptr);
|
468
|
-
cmark_node_set_syntax_extension(node, self);
|
469
|
-
set_cell_index(node, i);
|
470
|
-
}
|
471
|
-
|
472
|
-
incr_table_row_count(parent_container, i);
|
473
|
-
|
474
|
-
for (; i < table_columns; ++i) {
|
475
|
-
cmark_node *node = cmark_parser_add_child(
|
476
|
-
parser, table_row_block, CMARK_NODE_TABLE_CELL, 0);
|
477
|
-
cmark_node_set_syntax_extension(node, self);
|
478
|
-
set_cell_index(node, i);
|
479
|
-
}
|
480
|
-
}
|
481
|
-
|
482
|
-
free_table_row(parser->mem, row);
|
483
|
-
|
484
|
-
cmark_parser_advance_offset(parser, (char *)input,
|
485
|
-
len - 1 - cmark_parser_get_offset(parser), false);
|
486
|
-
|
487
|
-
return table_row_block;
|
488
|
-
}
|
489
|
-
|
490
|
-
static cmark_node *try_opening_table_block(cmark_syntax_extension *self,
|
491
|
-
int indented, cmark_parser *parser,
|
492
|
-
cmark_node *parent_container,
|
493
|
-
unsigned char *input, int len) {
|
494
|
-
cmark_node_type parent_type = cmark_node_get_type(parent_container);
|
495
|
-
|
496
|
-
if (!indented && parent_type == CMARK_NODE_PARAGRAPH) {
|
497
|
-
return try_opening_table_header(self, parser, parent_container, input, len);
|
498
|
-
} else if (!indented && parent_type == CMARK_NODE_TABLE) {
|
499
|
-
return try_opening_table_row(self, parser, parent_container, input, len);
|
500
|
-
}
|
501
|
-
|
502
|
-
return NULL;
|
503
|
-
}
|
504
|
-
|
505
|
-
static int matches(cmark_syntax_extension *self, cmark_parser *parser,
|
506
|
-
unsigned char *input, int len,
|
507
|
-
cmark_node *parent_container) {
|
508
|
-
int res = 0;
|
509
|
-
|
510
|
-
if (cmark_node_get_type(parent_container) == CMARK_NODE_TABLE) {
|
511
|
-
cmark_arena_push();
|
512
|
-
table_row *new_row = row_from_string(
|
513
|
-
self, parser, input + cmark_parser_get_first_nonspace(parser),
|
514
|
-
len - cmark_parser_get_first_nonspace(parser));
|
515
|
-
if (new_row && new_row->n_columns)
|
516
|
-
res = 1;
|
517
|
-
free_table_row(parser->mem, new_row);
|
518
|
-
cmark_arena_pop();
|
519
|
-
}
|
520
|
-
|
521
|
-
return res;
|
522
|
-
}
|
523
|
-
|
524
|
-
static const char *get_type_string(cmark_syntax_extension *self,
|
525
|
-
cmark_node *node) {
|
526
|
-
if (node->type == CMARK_NODE_TABLE) {
|
527
|
-
return "table";
|
528
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
529
|
-
if (((node_table_row *)node->as.opaque)->is_header)
|
530
|
-
return "table_header";
|
531
|
-
else
|
532
|
-
return "table_row";
|
533
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
534
|
-
return "table_cell";
|
535
|
-
}
|
536
|
-
|
537
|
-
return "<unknown>";
|
538
|
-
}
|
539
|
-
|
540
|
-
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
|
541
|
-
cmark_node_type child_type) {
|
542
|
-
if (node->type == CMARK_NODE_TABLE) {
|
543
|
-
return child_type == CMARK_NODE_TABLE_ROW;
|
544
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
545
|
-
return child_type == CMARK_NODE_TABLE_CELL;
|
546
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
547
|
-
return child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE ||
|
548
|
-
child_type == CMARK_NODE_EMPH || child_type == CMARK_NODE_STRONG ||
|
549
|
-
child_type == CMARK_NODE_LINK || child_type == CMARK_NODE_IMAGE ||
|
550
|
-
child_type == CMARK_NODE_STRIKETHROUGH ||
|
551
|
-
child_type == CMARK_NODE_HTML_INLINE ||
|
552
|
-
child_type == CMARK_NODE_FOOTNOTE_REFERENCE;
|
553
|
-
}
|
554
|
-
return false;
|
555
|
-
}
|
556
|
-
|
557
|
-
static int contains_inlines(cmark_syntax_extension *extension,
|
558
|
-
cmark_node *node) {
|
559
|
-
return node->type == CMARK_NODE_TABLE_CELL;
|
560
|
-
}
|
561
|
-
|
562
|
-
static void commonmark_render(cmark_syntax_extension *extension,
|
563
|
-
cmark_renderer *renderer, cmark_node *node,
|
564
|
-
cmark_event_type ev_type, int options) {
|
565
|
-
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
566
|
-
|
567
|
-
if (node->type == CMARK_NODE_TABLE) {
|
568
|
-
renderer->blankline(renderer);
|
569
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
570
|
-
if (entering) {
|
571
|
-
renderer->cr(renderer);
|
572
|
-
renderer->out(renderer, node, "|", false, LITERAL);
|
573
|
-
}
|
574
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
575
|
-
if (entering) {
|
576
|
-
renderer->out(renderer, node, " ", false, LITERAL);
|
577
|
-
} else {
|
578
|
-
renderer->out(renderer, node, " |", false, LITERAL);
|
579
|
-
if (((node_table_row *)node->parent->as.opaque)->is_header &&
|
580
|
-
!node->next) {
|
581
|
-
int i;
|
582
|
-
uint8_t *alignments = get_table_alignments(node->parent->parent);
|
583
|
-
uint16_t n_cols =
|
584
|
-
((node_table *)node->parent->parent->as.opaque)->n_columns;
|
585
|
-
renderer->cr(renderer);
|
586
|
-
renderer->out(renderer, node, "|", false, LITERAL);
|
587
|
-
for (i = 0; i < n_cols; i++) {
|
588
|
-
switch (alignments[i]) {
|
589
|
-
case 0: renderer->out(renderer, node, " --- |", false, LITERAL); break;
|
590
|
-
case 'l': renderer->out(renderer, node, " :-- |", false, LITERAL); break;
|
591
|
-
case 'c': renderer->out(renderer, node, " :-: |", false, LITERAL); break;
|
592
|
-
case 'r': renderer->out(renderer, node, " --: |", false, LITERAL); break;
|
593
|
-
}
|
594
|
-
}
|
595
|
-
renderer->cr(renderer);
|
596
|
-
}
|
597
|
-
}
|
598
|
-
} else {
|
599
|
-
assert(false);
|
600
|
-
}
|
601
|
-
}
|
602
|
-
|
603
|
-
static void latex_render(cmark_syntax_extension *extension,
|
604
|
-
cmark_renderer *renderer, cmark_node *node,
|
605
|
-
cmark_event_type ev_type, int options) {
|
606
|
-
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
607
|
-
|
608
|
-
if (node->type == CMARK_NODE_TABLE) {
|
609
|
-
if (entering) {
|
610
|
-
int i;
|
611
|
-
uint16_t n_cols;
|
612
|
-
uint8_t *alignments = get_table_alignments(node);
|
613
|
-
|
614
|
-
renderer->cr(renderer);
|
615
|
-
renderer->out(renderer, node, "\\begin{table}", false, LITERAL);
|
616
|
-
renderer->cr(renderer);
|
617
|
-
renderer->out(renderer, node, "\\begin{tabular}{", false, LITERAL);
|
618
|
-
|
619
|
-
n_cols = ((node_table *)node->as.opaque)->n_columns;
|
620
|
-
for (i = 0; i < n_cols; i++) {
|
621
|
-
switch(alignments[i]) {
|
622
|
-
case 0:
|
623
|
-
case 'l':
|
624
|
-
renderer->out(renderer, node, "l", false, LITERAL);
|
625
|
-
break;
|
626
|
-
case 'c':
|
627
|
-
renderer->out(renderer, node, "c", false, LITERAL);
|
628
|
-
break;
|
629
|
-
case 'r':
|
630
|
-
renderer->out(renderer, node, "r", false, LITERAL);
|
631
|
-
break;
|
632
|
-
}
|
633
|
-
}
|
634
|
-
renderer->out(renderer, node, "}", false, LITERAL);
|
635
|
-
renderer->cr(renderer);
|
636
|
-
} else {
|
637
|
-
renderer->out(renderer, node, "\\end{tabular}", false, LITERAL);
|
638
|
-
renderer->cr(renderer);
|
639
|
-
renderer->out(renderer, node, "\\end{table}", false, LITERAL);
|
640
|
-
renderer->cr(renderer);
|
641
|
-
}
|
642
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
643
|
-
if (!entering) {
|
644
|
-
renderer->cr(renderer);
|
645
|
-
}
|
646
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
647
|
-
if (!entering) {
|
648
|
-
if (node->next) {
|
649
|
-
renderer->out(renderer, node, " & ", false, LITERAL);
|
650
|
-
} else {
|
651
|
-
renderer->out(renderer, node, " \\\\", false, LITERAL);
|
652
|
-
}
|
653
|
-
}
|
654
|
-
} else {
|
655
|
-
assert(false);
|
656
|
-
}
|
657
|
-
}
|
658
|
-
|
659
|
-
static const char *xml_attr(cmark_syntax_extension *extension,
|
660
|
-
cmark_node *node) {
|
661
|
-
if (node->type == CMARK_NODE_TABLE_CELL) {
|
662
|
-
if (cmark_gfm_extensions_get_table_row_is_header(node->parent)) {
|
663
|
-
switch (get_cell_alignment(node)) {
|
664
|
-
case 'l': return " align=\"left\"";
|
665
|
-
case 'c': return " align=\"center\"";
|
666
|
-
case 'r': return " align=\"right\"";
|
667
|
-
}
|
668
|
-
}
|
669
|
-
}
|
670
|
-
|
671
|
-
return NULL;
|
672
|
-
}
|
673
|
-
|
674
|
-
static void man_render(cmark_syntax_extension *extension,
|
675
|
-
cmark_renderer *renderer, cmark_node *node,
|
676
|
-
cmark_event_type ev_type, int options) {
|
677
|
-
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
678
|
-
|
679
|
-
if (node->type == CMARK_NODE_TABLE) {
|
680
|
-
if (entering) {
|
681
|
-
int i;
|
682
|
-
uint16_t n_cols;
|
683
|
-
uint8_t *alignments = get_table_alignments(node);
|
684
|
-
|
685
|
-
renderer->cr(renderer);
|
686
|
-
renderer->out(renderer, node, ".TS", false, LITERAL);
|
687
|
-
renderer->cr(renderer);
|
688
|
-
renderer->out(renderer, node, "tab(@);", false, LITERAL);
|
689
|
-
renderer->cr(renderer);
|
690
|
-
|
691
|
-
n_cols = ((node_table *)node->as.opaque)->n_columns;
|
692
|
-
|
693
|
-
for (i = 0; i < n_cols; i++) {
|
694
|
-
switch (alignments[i]) {
|
695
|
-
case 'l':
|
696
|
-
renderer->out(renderer, node, "l", false, LITERAL);
|
697
|
-
break;
|
698
|
-
case 0:
|
699
|
-
case 'c':
|
700
|
-
renderer->out(renderer, node, "c", false, LITERAL);
|
701
|
-
break;
|
702
|
-
case 'r':
|
703
|
-
renderer->out(renderer, node, "r", false, LITERAL);
|
704
|
-
break;
|
705
|
-
}
|
706
|
-
}
|
707
|
-
|
708
|
-
if (n_cols) {
|
709
|
-
renderer->out(renderer, node, ".", false, LITERAL);
|
710
|
-
renderer->cr(renderer);
|
711
|
-
}
|
712
|
-
} else {
|
713
|
-
renderer->out(renderer, node, ".TE", false, LITERAL);
|
714
|
-
renderer->cr(renderer);
|
715
|
-
}
|
716
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
717
|
-
if (!entering) {
|
718
|
-
renderer->cr(renderer);
|
719
|
-
}
|
720
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
721
|
-
if (!entering && node->next) {
|
722
|
-
renderer->out(renderer, node, "@", false, LITERAL);
|
723
|
-
}
|
724
|
-
} else {
|
725
|
-
assert(false);
|
726
|
-
}
|
727
|
-
}
|
728
|
-
|
729
|
-
static void html_table_add_align(cmark_strbuf* html, const char* align, int options) {
|
730
|
-
if (options & CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES) {
|
731
|
-
cmark_strbuf_puts(html, " style=\"text-align: ");
|
732
|
-
cmark_strbuf_puts(html, align);
|
733
|
-
cmark_strbuf_puts(html, "\"");
|
734
|
-
} else {
|
735
|
-
cmark_strbuf_puts(html, " align=\"");
|
736
|
-
cmark_strbuf_puts(html, align);
|
737
|
-
cmark_strbuf_puts(html, "\"");
|
738
|
-
}
|
739
|
-
}
|
740
|
-
|
741
|
-
struct html_table_state {
|
742
|
-
unsigned need_closing_table_body : 1;
|
743
|
-
unsigned in_table_header : 1;
|
744
|
-
};
|
745
|
-
|
746
|
-
static void html_render(cmark_syntax_extension *extension,
|
747
|
-
cmark_html_renderer *renderer, cmark_node *node,
|
748
|
-
cmark_event_type ev_type, int options) {
|
749
|
-
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
750
|
-
cmark_strbuf *html = renderer->html;
|
751
|
-
|
752
|
-
// XXX: we just monopolise renderer->opaque.
|
753
|
-
struct html_table_state *table_state =
|
754
|
-
(struct html_table_state *)&renderer->opaque;
|
755
|
-
|
756
|
-
if (node->type == CMARK_NODE_TABLE) {
|
757
|
-
if (entering) {
|
758
|
-
cmark_html_render_cr(html);
|
759
|
-
cmark_strbuf_puts(html, "<table");
|
760
|
-
cmark_html_render_sourcepos(node, html, options);
|
761
|
-
cmark_strbuf_putc(html, '>');
|
762
|
-
table_state->need_closing_table_body = false;
|
763
|
-
} else {
|
764
|
-
if (table_state->need_closing_table_body) {
|
765
|
-
cmark_html_render_cr(html);
|
766
|
-
cmark_strbuf_puts(html, "</tbody>");
|
767
|
-
cmark_html_render_cr(html);
|
768
|
-
}
|
769
|
-
table_state->need_closing_table_body = false;
|
770
|
-
cmark_html_render_cr(html);
|
771
|
-
cmark_strbuf_puts(html, "</table>");
|
772
|
-
cmark_html_render_cr(html);
|
773
|
-
}
|
774
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
775
|
-
if (entering) {
|
776
|
-
cmark_html_render_cr(html);
|
777
|
-
if (((node_table_row *)node->as.opaque)->is_header) {
|
778
|
-
table_state->in_table_header = 1;
|
779
|
-
cmark_strbuf_puts(html, "<thead>");
|
780
|
-
cmark_html_render_cr(html);
|
781
|
-
} else if (!table_state->need_closing_table_body) {
|
782
|
-
cmark_strbuf_puts(html, "<tbody>");
|
783
|
-
cmark_html_render_cr(html);
|
784
|
-
table_state->need_closing_table_body = 1;
|
785
|
-
}
|
786
|
-
cmark_strbuf_puts(html, "<tr");
|
787
|
-
cmark_html_render_sourcepos(node, html, options);
|
788
|
-
cmark_strbuf_putc(html, '>');
|
789
|
-
} else {
|
790
|
-
cmark_html_render_cr(html);
|
791
|
-
cmark_strbuf_puts(html, "</tr>");
|
792
|
-
if (((node_table_row *)node->as.opaque)->is_header) {
|
793
|
-
cmark_html_render_cr(html);
|
794
|
-
cmark_strbuf_puts(html, "</thead>");
|
795
|
-
table_state->in_table_header = false;
|
796
|
-
}
|
797
|
-
}
|
798
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
799
|
-
if (entering) {
|
800
|
-
cmark_html_render_cr(html);
|
801
|
-
if (table_state->in_table_header) {
|
802
|
-
cmark_strbuf_puts(html, "<th");
|
803
|
-
} else {
|
804
|
-
cmark_strbuf_puts(html, "<td");
|
805
|
-
}
|
806
|
-
|
807
|
-
switch (get_cell_alignment(node)) {
|
808
|
-
case 'l': html_table_add_align(html, "left", options); break;
|
809
|
-
case 'c': html_table_add_align(html, "center", options); break;
|
810
|
-
case 'r': html_table_add_align(html, "right", options); break;
|
811
|
-
}
|
812
|
-
|
813
|
-
cmark_html_render_sourcepos(node, html, options);
|
814
|
-
cmark_strbuf_putc(html, '>');
|
815
|
-
} else {
|
816
|
-
if (table_state->in_table_header) {
|
817
|
-
cmark_strbuf_puts(html, "</th>");
|
818
|
-
} else {
|
819
|
-
cmark_strbuf_puts(html, "</td>");
|
820
|
-
}
|
821
|
-
}
|
822
|
-
} else {
|
823
|
-
assert(false);
|
824
|
-
}
|
825
|
-
}
|
826
|
-
|
827
|
-
static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) {
|
828
|
-
if (node->type == CMARK_NODE_TABLE) {
|
829
|
-
node->as.opaque = mem->calloc(1, sizeof(node_table));
|
830
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
831
|
-
node->as.opaque = mem->calloc(1, sizeof(node_table_row));
|
832
|
-
} else if (node->type == CMARK_NODE_TABLE_CELL) {
|
833
|
-
node->as.opaque = mem->calloc(1, sizeof(node_cell));
|
834
|
-
}
|
835
|
-
}
|
836
|
-
|
837
|
-
static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) {
|
838
|
-
if (node->type == CMARK_NODE_TABLE) {
|
839
|
-
free_node_table(mem, node->as.opaque);
|
840
|
-
} else if (node->type == CMARK_NODE_TABLE_ROW) {
|
841
|
-
free_node_table_row(mem, node->as.opaque);
|
842
|
-
}
|
843
|
-
}
|
844
|
-
|
845
|
-
static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
|
846
|
-
return
|
847
|
-
node->type != CMARK_NODE_TABLE &&
|
848
|
-
node->type != CMARK_NODE_TABLE_ROW &&
|
849
|
-
node->type != CMARK_NODE_TABLE_CELL &&
|
850
|
-
c == '|';
|
851
|
-
}
|
852
|
-
|
853
|
-
cmark_syntax_extension *create_table_extension(void) {
|
854
|
-
cmark_syntax_extension *self = cmark_syntax_extension_new("table");
|
855
|
-
|
856
|
-
cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED);
|
857
|
-
cmark_syntax_extension_set_match_block_func(self, matches);
|
858
|
-
cmark_syntax_extension_set_open_block_func(self, try_opening_table_block);
|
859
|
-
cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
|
860
|
-
cmark_syntax_extension_set_can_contain_func(self, can_contain);
|
861
|
-
cmark_syntax_extension_set_contains_inlines_func(self, contains_inlines);
|
862
|
-
cmark_syntax_extension_set_commonmark_render_func(self, commonmark_render);
|
863
|
-
cmark_syntax_extension_set_plaintext_render_func(self, commonmark_render);
|
864
|
-
cmark_syntax_extension_set_latex_render_func(self, latex_render);
|
865
|
-
cmark_syntax_extension_set_xml_attr_func(self, xml_attr);
|
866
|
-
cmark_syntax_extension_set_man_render_func(self, man_render);
|
867
|
-
cmark_syntax_extension_set_html_render_func(self, html_render);
|
868
|
-
cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc);
|
869
|
-
cmark_syntax_extension_set_opaque_free_func(self, opaque_free);
|
870
|
-
cmark_syntax_extension_set_commonmark_escape_func(self, escape);
|
871
|
-
CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0);
|
872
|
-
CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0);
|
873
|
-
CMARK_NODE_TABLE_CELL = cmark_syntax_extension_add_node(0);
|
874
|
-
|
875
|
-
return self;
|
876
|
-
}
|
877
|
-
|
878
|
-
uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node) {
|
879
|
-
if (node->type != CMARK_NODE_TABLE)
|
880
|
-
return 0;
|
881
|
-
|
882
|
-
return ((node_table *)node->as.opaque)->n_columns;
|
883
|
-
}
|
884
|
-
|
885
|
-
uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node) {
|
886
|
-
if (node->type != CMARK_NODE_TABLE)
|
887
|
-
return 0;
|
888
|
-
|
889
|
-
return ((node_table *)node->as.opaque)->alignments;
|
890
|
-
}
|
891
|
-
|
892
|
-
int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns) {
|
893
|
-
return set_n_table_columns(node, n_columns);
|
894
|
-
}
|
895
|
-
|
896
|
-
int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments) {
|
897
|
-
uint8_t *a = (uint8_t *)cmark_node_mem(node)->calloc(1, ncols);
|
898
|
-
memcpy(a, alignments, ncols);
|
899
|
-
return set_table_alignments(node, a);
|
900
|
-
}
|
901
|
-
|
902
|
-
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node)
|
903
|
-
{
|
904
|
-
if (!node || node->type != CMARK_NODE_TABLE_ROW)
|
905
|
-
return 0;
|
906
|
-
|
907
|
-
return ((node_table_row *)node->as.opaque)->is_header;
|
908
|
-
}
|
909
|
-
|
910
|
-
int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header)
|
911
|
-
{
|
912
|
-
if (!node || node->type != CMARK_NODE_TABLE_ROW)
|
913
|
-
return 0;
|
914
|
-
|
915
|
-
((node_table_row *)node->as.opaque)->is_header = (is_header != 0);
|
916
|
-
return 1;
|
917
|
-
}
|