Skip to content

Commit 8889e1b

Browse files
Update cmark-gfm + add support for front matter.
1 parent 7a2ecad commit 8889e1b

39 files changed

+673
-60
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "cmark-gfm"]
22
path = cmark-gfm
3-
url = https://github.com/github/cmark-gfm.git
3+
url = https://github.com/socketry/cmark-gfm.git
44
ignore = dirty

bake.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def clean
4646
end
4747

4848
def format
49-
system("clang-format -style llvm -i ext/markly/*.c ext/markly/*.h")
49+
system("clang-format -style llvm -i ext/markly/*.c ext/markly/*.h ext/markly/extensions/*.c ext/markly/extensions/*.h")
5050
end
5151

5252
def benchmark
@@ -71,9 +71,9 @@ def synchronize_upstream
7171
cmark_gfm = root/"cmark-gfm"
7272

7373
(cmark_gfm/"src").glob("**/*").copy(ext_markly)
74-
(cmark_gfm/"extensions").glob("**/*").copy(ext_markly)
74+
(cmark_gfm/"extensions").glob("**/*").copy(ext_markly/"extensions")
7575
(cmark_gfm/"build/src").glob("config.h").copy(ext_markly)
7676
(cmark_gfm/"build/src").glob("cmark-gfm_export.h").copy(ext_markly)
7777
(cmark_gfm/"build/src").glob("cmark-gfm_version.h").copy(ext_markly)
78-
(cmark_gfm/"build/extensions").glob("cmark-gfm-extensions_export.h").copy(ext_markly)
78+
(cmark_gfm/"build/extensions").glob("cmark-gfm-extensions_export.h").copy(ext_markly/"extensions")
7979
end

ext/markly/blocks.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "houdini.h"
2424
#include "buffer.h"
2525
#include "footnotes.h"
26+
#include "front_matter.h"
2627

2728
#define CODE_INDENT 4
2829
#define TAB_STOP 4
@@ -68,16 +69,12 @@ static CMARK_INLINE bool S_is_line_end_char(char c) {
6869
return (c == '\n' || c == '\r');
6970
}
7071

71-
static CMARK_INLINE bool S_is_space_or_tab(char c) {
72-
return (c == ' ' || c == '\t');
73-
}
74-
7572
// Returns true if block is being finalized on the same line it ends.
7673
// This happens for:
7774
// - Document node (special case)
7875
// - Fenced code blocks (end on the closing fence line)
7976
// - Setext headings (end on the underline)
80-
// - HTML blocks types 1-5 per CommonMark spec §4.6 (end on the line
77+
// - HTML block types 1-5 per CommonMark spec §4.6 (end on the line
8178
// containing the closing marker)
8279
// - Any block finalized on the same line it started (e.g., single-line blocks)
8380
static CMARK_INLINE bool S_ends_on_current_line(cmark_parser *parser, cmark_node *b) {
@@ -100,6 +97,10 @@ static CMARK_INLINE bool S_ends_on_current_line(cmark_parser *parser, cmark_node
10097
b->start_line == parser->line_number;
10198
}
10299

100+
static CMARK_INLINE bool S_is_space_or_tab(char c) {
101+
return (c == ' ' || c == '\t');
102+
}
103+
103104
static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
104105
size_t len, bool eof);
105106

@@ -159,6 +160,8 @@ static void cmark_parser_reset(cmark_parser *parser) {
159160

160161
cmark_strbuf_init(parser->mem, &parser->curline, 256);
161162
cmark_strbuf_init(parser->mem, &parser->linebuf, 0);
163+
cmark_strbuf_init(parser->mem, &parser->front_matter_buf, 0);
164+
cmark_strbuf_init(parser->mem, &parser->front_matter_info, 0);
162165

163166
cmark_node *document = make_document(parser->mem);
164167

@@ -189,6 +192,8 @@ void cmark_parser_free(cmark_parser *parser) {
189192
cmark_parser_dispose(parser);
190193
cmark_strbuf_free(&parser->curline);
191194
cmark_strbuf_free(&parser->linebuf);
195+
cmark_strbuf_free(&parser->front_matter_buf);
196+
cmark_strbuf_free(&parser->front_matter_info);
192197
cmark_llist_free(parser->mem, parser->syntax_extensions);
193198
cmark_llist_free(parser->mem, parser->inline_syntax_extensions);
194199
mem->free(parser);
@@ -1244,7 +1249,8 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
12441249
parser->first_nonspace + 1);
12451250
S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
12461251
} else if (!indented &&
1247-
parser->options & CMARK_OPT_FOOTNOTES &&
1252+
(parser->options & CMARK_OPT_FOOTNOTES) &&
1253+
depth < MAX_LIST_DEPTH &&
12481254
(matched = scan_footnote_definition(input, parser->first_nonspace))) {
12491255
cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2);
12501256

@@ -1516,6 +1522,10 @@ static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
15161522

15171523
parser->line_number++;
15181524

1525+
if ((parser->options & CMARK_OPT_FRONT_MATTER) &&
1526+
cmark_front_matter_process_line(parser, &input))
1527+
goto finished;
1528+
15191529
last_matched_container = check_open_blocks(parser, &input, &all_matched);
15201530

15211531
if (!last_matched_container)
@@ -1556,12 +1566,20 @@ cmark_node *cmark_parser_finish(cmark_parser *parser) {
15561566
cmark_strbuf_clear(&parser->linebuf);
15571567
}
15581568

1569+
// If front matter scanning was still active when the document ended, no
1570+
// closing delimiter was found. The entire document (after the opening ---)
1571+
// is treated as front matter.
1572+
if ((parser->options & CMARK_OPT_FRONT_MATTER) && parser->front_matter_scanning)
1573+
cmark_front_matter_process_line(parser, NULL);
1574+
15591575
finalize_document(parser);
15601576

15611577
cmark_consolidate_text_nodes(parser->root);
15621578

15631579
cmark_strbuf_free(&parser->curline);
15641580
cmark_strbuf_free(&parser->linebuf);
1581+
cmark_strbuf_free(&parser->front_matter_buf);
1582+
cmark_strbuf_free(&parser->front_matter_info);
15651583

15661584
#if CMARK_DEBUG_NODES
15671585
if (cmark_node_check(parser->root, stderr)) {

ext/markly/cmark-gfm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ typedef enum {
5353
CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009,
5454
CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a,
5555
CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b,
56+
CMARK_NODE_FRONT_MATTER = CMARK_NODE_TYPE_BLOCK | 0x000c,
5657

5758
/* Inline */
5859
CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001,
@@ -768,6 +769,13 @@ char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmar
768769
*/
769770
#define CMARK_OPT_FULL_INFO_STRING (1 << 16)
770771

772+
/** Parse front matter ("---" delimited block at the start of the document)
773+
* and expose it as a CMARK_NODE_FRONT_MATTER node. The raw content between
774+
* the delimiters is available via cmark_node_get_literal(); how it is
775+
* interpreted (e.g. as YAML, TOML, JSON) is left to the caller.
776+
*/
777+
#define CMARK_OPT_FRONT_MATTER (1 << 18)
778+
771779
/**
772780
* ## Version information
773781
*/

ext/markly/cmark.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "cmark-gfm.h"
88
#include "buffer.h"
99

10-
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
10+
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FRONT_MATTER;
1111
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
1212

1313
int cmark_version(void) { return CMARK_GFM_VERSION; }

ext/markly/commonmark.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,19 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
492492
}
493493
break;
494494

495+
case CMARK_NODE_FRONT_MATTER:
496+
if (entering) {
497+
const char *info = cmark_node_get_fence_info(node);
498+
BLANKLINE();
499+
LIT("---");
500+
if (info && *info) { LIT(" "); OUT(info, false, LITERAL); }
501+
LIT("\n");
502+
OUT(cmark_node_get_literal(node), false, LITERAL);
503+
LIT("---\n");
504+
BLANKLINE();
505+
}
506+
break;
507+
495508
default:
496509
assert(false);
497510
break;

ext/markly/extconf.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
append_cflags(["-O3", "-Wall", "-Wno-unknown-pragmas", "-std=c99"])
1414

15+
# Include the extensions/ subdirectory, mirroring the cmark-gfm source layout.
16+
$INCFLAGS << " -I$(srcdir)/extensions"
17+
$VPATH << "$(srcdir)/extensions"
18+
$srcs = (Dir["#{$srcdir}/*.c"] + Dir["#{$srcdir}/extensions/*.c"]).map { |f| File.basename(f) }
19+
1520
gem_name = File.basename(__dir__)
1621
extension_name = "markly"
1722

0 commit comments

Comments
 (0)