commonmarker 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of commonmarker might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/Rakefile +0 -5
- data/ext/commonmarker/cmark/CMakeLists.txt +1 -1
- data/ext/commonmarker/cmark/Makefile +12 -7
- data/ext/commonmarker/cmark/README.md +12 -8
- data/ext/commonmarker/cmark/api_test/main.c +18 -2
- data/ext/commonmarker/cmark/benchmarks.md +4 -4
- data/ext/commonmarker/cmark/build/CMakeFiles/CMakeError.log +12 -12
- data/ext/commonmarker/cmark/build/CMakeFiles/CMakeOutput.log +106 -106
- data/ext/commonmarker/cmark/build/CMakeFiles/Makefile2 +7 -7
- data/ext/commonmarker/cmark/build/CMakeFiles/progress.marks +1 -1
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/build.make +1 -1
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/api_test/CMakeFiles/progress.marks +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/DependInfo.cmake +2 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/build.make +61 -9
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/cmake_clean.cmake +2 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/progress.make +2 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/DependInfo.cmake +3 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/build.make +81 -29
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/cmake_clean.cmake +3 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/progress.make +19 -17
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/C.includecache +56 -10
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/DependInfo.cmake +2 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/blocks.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/build.make +60 -8
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/cmake_clean.cmake +2 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/cmark.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/commonmark.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.internal +27 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/depend.make +27 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/flags.make +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/html.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/inlines.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/latex.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/link.txt +1 -1
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/man.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/progress.make +19 -17
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/render.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/scanners.c.o +0 -0
- data/ext/commonmarker/cmark/build/src/CMakeFiles/progress.marks +1 -1
- data/ext/commonmarker/cmark/build/src/Makefile +66 -0
- data/ext/commonmarker/cmark/build/src/cmake_install.cmake +3 -3
- data/ext/commonmarker/cmark/build/src/cmark_version.h +2 -2
- data/ext/commonmarker/cmark/build/src/libcmark.a +0 -0
- data/ext/commonmarker/cmark/build/src/libcmark.pc +1 -1
- data/ext/commonmarker/cmark/changelog.txt +144 -0
- data/ext/commonmarker/cmark/man/make_man_page.py +3 -3
- data/ext/commonmarker/cmark/man/man1/cmark.1 +10 -2
- data/ext/commonmarker/cmark/man/man3/cmark.3 +106 -85
- data/ext/commonmarker/cmark/src/CMakeLists.txt +5 -2
- data/ext/commonmarker/cmark/src/blocks.c +76 -9
- data/ext/commonmarker/cmark/src/cmark.c +9 -2
- data/ext/commonmarker/cmark/src/cmark.h +16 -3
- data/ext/commonmarker/cmark/src/commonmark.c +162 -309
- data/ext/commonmarker/cmark/src/html.c +30 -10
- data/ext/commonmarker/cmark/src/inlines.c +80 -72
- data/ext/commonmarker/cmark/src/latex.c +430 -0
- data/ext/commonmarker/cmark/src/main.c +12 -4
- data/ext/commonmarker/cmark/src/man.c +118 -156
- data/ext/commonmarker/cmark/src/node.h +1 -0
- data/ext/commonmarker/cmark/src/render.c +186 -0
- data/ext/commonmarker/cmark/src/render.h +66 -0
- data/ext/commonmarker/cmark/src/scanners.c +14586 -8944
- data/ext/commonmarker/cmark/src/scanners.h +16 -2
- data/ext/commonmarker/cmark/src/scanners.re +93 -9
- data/ext/commonmarker/cmark/test/__pycache__/cmark.cpython-34.pyc +0 -0
- data/ext/commonmarker/cmark/test/__pycache__/normalize.cpython-34.pyc +0 -0
- data/ext/commonmarker/cmark/test/smart_punct.txt +74 -10
- data/ext/commonmarker/cmark/test/spec.txt +726 -92
- data/ext/commonmarker/cmark/test/spec_tests.py +16 -13
- data/lib/commonmarker/config.rb +2 -0
- data/lib/commonmarker/version.rb +1 -1
- data/test/test_helper.rb +1 -1
- data/test/test_spec.rb +11 -10
- metadata +9 -6
- data/ext/commonmarker/cmark/algorithm.md +0 -116
- data/ext/commonmarker/cmark/src/debug.h +0 -36
- data/test/spec_tests.json +0 -4482
@@ -9,13 +9,13 @@ set(HEADERS
|
|
9
9
|
iterator.h
|
10
10
|
chunk.h
|
11
11
|
references.h
|
12
|
-
debug.h
|
13
12
|
bench.h
|
14
13
|
utf8.h
|
15
14
|
scanners.h
|
16
15
|
inlines.h
|
17
16
|
houdini.h
|
18
17
|
cmark_ctype.h
|
18
|
+
render.h
|
19
19
|
)
|
20
20
|
set(LIBRARY_SOURCES
|
21
21
|
cmark.c
|
@@ -28,10 +28,12 @@ set(LIBRARY_SOURCES
|
|
28
28
|
utf8.c
|
29
29
|
buffer.c
|
30
30
|
references.c
|
31
|
+
render.c
|
31
32
|
man.c
|
32
33
|
xml.c
|
33
34
|
html.c
|
34
35
|
commonmark.c
|
36
|
+
latex.c
|
35
37
|
houdini_href_e.c
|
36
38
|
houdini_html_e.c
|
37
39
|
houdini_html_u.c
|
@@ -86,7 +88,8 @@ set_target_properties(${LIBRARY} PROPERTIES
|
|
86
88
|
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
87
89
|
VERSION ${PROJECT_VERSION})
|
88
90
|
set_target_properties(${STATICLIBRARY} PROPERTIES
|
89
|
-
COMPILE_FLAGS -DCMARK_STATIC_DEFINE
|
91
|
+
COMPILE_FLAGS -DCMARK_STATIC_DEFINE
|
92
|
+
POSITION_INDEPENDENT_CODE ON)
|
90
93
|
|
91
94
|
if (MSVC)
|
92
95
|
set_target_properties(${STATICLIBRARY} PROPERTIES
|
@@ -13,7 +13,6 @@
|
|
13
13
|
#include "inlines.h"
|
14
14
|
#include "houdini.h"
|
15
15
|
#include "buffer.h"
|
16
|
-
#include "debug.h"
|
17
16
|
|
18
17
|
#define CODE_INDENT 4
|
19
18
|
#define TAB_STOP 4
|
@@ -401,11 +400,16 @@ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos, cmark_list
|
|
401
400
|
}
|
402
401
|
} else if (cmark_isdigit(c)) {
|
403
402
|
int start = 0;
|
403
|
+
int digits = 0;
|
404
404
|
|
405
405
|
do {
|
406
406
|
start = (10 * start) + (peek_at(input, pos) - '0');
|
407
407
|
pos++;
|
408
|
-
|
408
|
+
digits++;
|
409
|
+
// We limit to 9 digits to avoid overflow,
|
410
|
+
// assuming max int is 2^31 - 1
|
411
|
+
// This also seems to be the limit for 'start' in some browsers.
|
412
|
+
} while (digits < 9 && cmark_isdigit(peek_at(input, pos)));
|
409
413
|
|
410
414
|
c = peek_at(input, pos);
|
411
415
|
if (c == '.' || c == ')') {
|
@@ -560,8 +564,9 @@ static void chop_trailing_hashtags(cmark_chunk *ch)
|
|
560
564
|
while (n >= 0 && peek_at(ch, n) == '#')
|
561
565
|
n--;
|
562
566
|
|
563
|
-
// Check for a
|
564
|
-
if (n != orig_n && n >= 0 &&
|
567
|
+
// Check for a space before the final #s:
|
568
|
+
if (n != orig_n && n >= 0 &&
|
569
|
+
(peek_at(ch, n) == ' ' || peek_at(ch, n) == '\t')) {
|
565
570
|
ch->len = n;
|
566
571
|
cmark_chunk_rtrim(ch);
|
567
572
|
}
|
@@ -722,8 +727,26 @@ S_process_line(cmark_parser *parser, const unsigned char *buffer, bufsize_t byte
|
|
722
727
|
|
723
728
|
} else if (container->type == NODE_HTML) {
|
724
729
|
|
725
|
-
|
726
|
-
|
730
|
+
switch (container->as.html_block_type) {
|
731
|
+
case 1:
|
732
|
+
case 2:
|
733
|
+
case 3:
|
734
|
+
case 4:
|
735
|
+
case 5:
|
736
|
+
// these types of blocks can accept blanks
|
737
|
+
break;
|
738
|
+
case 6:
|
739
|
+
case 7:
|
740
|
+
if (parser->blank) {
|
741
|
+
all_matched = false;
|
742
|
+
}
|
743
|
+
break;
|
744
|
+
default:
|
745
|
+
fprintf(stderr,
|
746
|
+
"Error (%s:%d): Unknown HTML block type %d\n",
|
747
|
+
__FILE__, __LINE__,
|
748
|
+
container->as.html_block_type);
|
749
|
+
exit(1);
|
727
750
|
}
|
728
751
|
|
729
752
|
} else if (container->type == NODE_PARAGRAPH) {
|
@@ -789,9 +812,13 @@ S_process_line(cmark_parser *parser, const unsigned char *buffer, bufsize_t byte
|
|
789
812
|
container->as.code.info = cmark_chunk_literal("");
|
790
813
|
S_advance_offset(parser, &input, parser->first_nonspace + matched - parser->offset, false);
|
791
814
|
|
792
|
-
} else if (!indented &&
|
815
|
+
} else if (!indented &&
|
816
|
+
((matched = scan_html_block_start(&input, parser->first_nonspace)) ||
|
817
|
+
(container->type != NODE_PARAGRAPH &&
|
818
|
+
(matched = scan_html_block_start_7(&input, parser->first_nonspace))))) {
|
793
819
|
|
794
820
|
container = add_child(parser, container, NODE_HTML, parser->first_nonspace + 1);
|
821
|
+
container->as.html_block_type = matched;
|
795
822
|
// note, we don't adjust parser->offset because the tag is part of the text
|
796
823
|
|
797
824
|
} else if (!indented &&
|
@@ -923,11 +950,51 @@ S_process_line(cmark_parser *parser, const unsigned char *buffer, bufsize_t byte
|
|
923
950
|
assert(parser->current != NULL);
|
924
951
|
}
|
925
952
|
|
926
|
-
if (container->type == NODE_CODE_BLOCK
|
927
|
-
|
953
|
+
if (container->type == NODE_CODE_BLOCK) {
|
954
|
+
|
955
|
+
add_line(container, &input, parser->offset);
|
956
|
+
|
957
|
+
} else if (container->type == NODE_HTML) {
|
928
958
|
|
929
959
|
add_line(container, &input, parser->offset);
|
930
960
|
|
961
|
+
int matches_end_condition;
|
962
|
+
switch (container->as.html_block_type) {
|
963
|
+
case 1:
|
964
|
+
// </script>, </style>, </pre>
|
965
|
+
matches_end_condition =
|
966
|
+
scan_html_block_end_1(&input, parser->first_nonspace);
|
967
|
+
break;
|
968
|
+
case 2:
|
969
|
+
// -->
|
970
|
+
matches_end_condition =
|
971
|
+
scan_html_block_end_2(&input, parser->first_nonspace);
|
972
|
+
break;
|
973
|
+
case 3:
|
974
|
+
// ?>
|
975
|
+
matches_end_condition =
|
976
|
+
scan_html_block_end_3(&input, parser->first_nonspace);
|
977
|
+
break;
|
978
|
+
case 4:
|
979
|
+
// >
|
980
|
+
matches_end_condition =
|
981
|
+
scan_html_block_end_4(&input, parser->first_nonspace);
|
982
|
+
break;
|
983
|
+
case 5:
|
984
|
+
// ]]>
|
985
|
+
matches_end_condition =
|
986
|
+
scan_html_block_end_5(&input, parser->first_nonspace);
|
987
|
+
break;
|
988
|
+
default:
|
989
|
+
matches_end_condition = 0;
|
990
|
+
break;
|
991
|
+
}
|
992
|
+
|
993
|
+
if (matches_end_condition) {
|
994
|
+
container = finalize(parser, container);
|
995
|
+
assert(parser->current != NULL);
|
996
|
+
}
|
997
|
+
|
931
998
|
} else if (parser->blank) {
|
932
999
|
|
933
1000
|
// ??? do nothing
|
@@ -6,8 +6,15 @@
|
|
6
6
|
#include "cmark.h"
|
7
7
|
#include "buffer.h"
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
int cmark_version()
|
10
|
+
{
|
11
|
+
return CMARK_VERSION;
|
12
|
+
}
|
13
|
+
|
14
|
+
const char *cmark_version_string()
|
15
|
+
{
|
16
|
+
return CMARK_VERSION_STRING;
|
17
|
+
}
|
11
18
|
|
12
19
|
char *cmark_markdown_to_html(const char *text, size_t len, int options)
|
13
20
|
{
|
@@ -479,13 +479,18 @@ char *cmark_render_html(cmark_node *root, int options);
|
|
479
479
|
/** Render a 'node' tree as a groff man page, without the header.
|
480
480
|
*/
|
481
481
|
CMARK_EXPORT
|
482
|
-
char *cmark_render_man(cmark_node *root, int options);
|
482
|
+
char *cmark_render_man(cmark_node *root, int options, int width);
|
483
483
|
|
484
484
|
/** Render a 'node' tree as a commonmark document.
|
485
485
|
*/
|
486
486
|
CMARK_EXPORT
|
487
487
|
char *cmark_render_commonmark(cmark_node *root, int options, int width);
|
488
488
|
|
489
|
+
/** Render a 'node' tree as a LaTeX document.
|
490
|
+
*/
|
491
|
+
CMARK_EXPORT
|
492
|
+
char *cmark_render_latex(cmark_node *root, int options, int width);
|
493
|
+
|
489
494
|
/** Default writer options.
|
490
495
|
*/
|
491
496
|
#define CMARK_OPT_DEFAULT 0
|
@@ -511,6 +516,14 @@ char *cmark_render_commonmark(cmark_node *root, int options, int width);
|
|
511
516
|
*/
|
512
517
|
#define CMARK_OPT_VALIDATE_UTF8 16
|
513
518
|
|
519
|
+
/** Suppress raw HTML and unsafe links (`javascript:`, `vbscript:`,
|
520
|
+
* `file:`, and `data:`, except for `image/png`, `image/gif`,
|
521
|
+
* `image/jpeg`, or `image/webp` mime types). Raw HTML is replaced
|
522
|
+
* by a placeholder HTML comment. Unsafe links are replaced by
|
523
|
+
* empty strings.
|
524
|
+
*/
|
525
|
+
#define CMARK_OPT_SAFE 32
|
526
|
+
|
514
527
|
/**
|
515
528
|
* ## Version information
|
516
529
|
*/
|
@@ -525,13 +538,13 @@ char *cmark_render_commonmark(cmark_node *root, int options, int width);
|
|
525
538
|
* In hexadecimal format, the number 0x010203 represents version 1.2.3.
|
526
539
|
*/
|
527
540
|
CMARK_EXPORT
|
528
|
-
|
541
|
+
int cmark_version();
|
529
542
|
|
530
543
|
/** The library version string for runtime checks. Also available as
|
531
544
|
* macro CMARK_VERSION_STRING for compile time checks.
|
532
545
|
*/
|
533
546
|
CMARK_EXPORT
|
534
|
-
|
547
|
+
const char *cmark_version_string();
|
535
548
|
|
536
549
|
/** # AUTHORS
|
537
550
|
*
|
@@ -10,192 +10,63 @@
|
|
10
10
|
#include "buffer.h"
|
11
11
|
#include "utf8.h"
|
12
12
|
#include "scanners.h"
|
13
|
+
#include "render.h"
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
cmark_strbuf* prefix;
|
20
|
-
int column;
|
21
|
-
int width;
|
22
|
-
int need_cr;
|
23
|
-
bufsize_t last_breakable;
|
24
|
-
bool begin_line;
|
25
|
-
bool no_wrap;
|
26
|
-
bool in_tight_list_item;
|
27
|
-
};
|
28
|
-
|
29
|
-
static inline void cr(struct render_state *state)
|
30
|
-
{
|
31
|
-
if (state->need_cr < 1) {
|
32
|
-
state->need_cr = 1;
|
33
|
-
}
|
34
|
-
}
|
15
|
+
#define safe_strlen(s) cmark_strbuf_safe_strlen(s)
|
16
|
+
#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
|
17
|
+
#define LIT(s) renderer->out(renderer, s, false, LITERAL)
|
18
|
+
#define CR() renderer->cr(renderer)
|
19
|
+
#define BLANKLINE() renderer->blankline(renderer)
|
35
20
|
|
36
|
-
|
37
|
-
{
|
38
|
-
if (state->need_cr < 2) {
|
39
|
-
state->need_cr = 2;
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
|
-
typedef enum {
|
44
|
-
LITERAL,
|
45
|
-
NORMAL,
|
46
|
-
TITLE,
|
47
|
-
URL
|
48
|
-
} escaping;
|
49
|
-
|
50
|
-
static inline bool
|
51
|
-
needs_escaping(escaping escape,
|
52
|
-
int32_t c,
|
53
|
-
unsigned char next_c,
|
54
|
-
struct render_state *state)
|
55
|
-
{
|
56
|
-
if (escape == NORMAL) {
|
57
|
-
return (c == '*' || c == '_' || c == '[' || c == ']' ||
|
58
|
-
c == '<' || c == '>' || c == '\\' || c == '`' ||
|
59
|
-
(c == '&' && isalpha(next_c)) ||
|
60
|
-
(c == '!' && next_c == '[') ||
|
61
|
-
(state->begin_line &&
|
62
|
-
(c == '-' || c == '+' || c == '#' || c == '=')) ||
|
63
|
-
(c == '#' && (isspace(next_c) || next_c == '\0')) ||
|
64
|
-
((c == '.' || c == ')') &&
|
65
|
-
isdigit(state->buffer->ptr[state->buffer->size - 1])));
|
66
|
-
} else if (escape == TITLE) {
|
67
|
-
return (c == '`' || c == '<' || c == '>' || c == '"' ||
|
68
|
-
c == '\\');
|
69
|
-
} else if (escape == URL) {
|
70
|
-
return (c == '`' || c == '<' || c == '>' || isspace(c) ||
|
71
|
-
c == '\\' || c == ')' || c == '(');
|
72
|
-
} else {
|
73
|
-
return false;
|
74
|
-
}
|
75
|
-
}
|
21
|
+
// Functions to convert cmark_nodes to commonmark strings.
|
76
22
|
|
77
|
-
static inline void
|
78
|
-
|
79
|
-
|
80
|
-
|
23
|
+
static inline void outc(cmark_renderer *renderer,
|
24
|
+
cmark_escaping escape,
|
25
|
+
int32_t c,
|
26
|
+
unsigned char nextc)
|
81
27
|
{
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
28
|
+
bool needs_escaping = false;
|
29
|
+
needs_escaping =
|
30
|
+
escape != LITERAL &&
|
31
|
+
((escape == NORMAL &&
|
32
|
+
(c == '*' || c == '_' || c == '[' || c == ']' || c == '#' ||
|
33
|
+
c == '<' || c == '>' || c == '\\' || c == '`' || c == '!' ||
|
34
|
+
(c == '&' && isalpha(nextc)) ||
|
35
|
+
(c == '!' && nextc == '[') ||
|
36
|
+
(renderer->begin_line &&
|
37
|
+
(c == '-' || c == '+' || c == '=')) ||
|
38
|
+
((c == '.' || c == ')') &&
|
39
|
+
isdigit(renderer->buffer->ptr[renderer->buffer->size - 1])))) ||
|
40
|
+
(escape == URL &&
|
41
|
+
(c == '`' || c == '<' || c == '>' || isspace(c) ||
|
42
|
+
c == '\\' || c == ')' || c == '(')) ||
|
43
|
+
(escape == TITLE &&
|
44
|
+
(c == '`' || c == '<' || c == '>' || c == '"' ||
|
45
|
+
c == '\\')));
|
46
|
+
|
47
|
+
if (needs_escaping) {
|
48
|
+
if (isspace(c)) {
|
49
|
+
// use percent encoding for spaces
|
50
|
+
cmark_strbuf_printf(renderer->buffer, "%%%2x", c);
|
51
|
+
renderer->column += 3;
|
99
52
|
} else {
|
100
|
-
|
101
|
-
|
102
|
-
cmark_strbuf_put(state->buffer, state->prefix->ptr,
|
103
|
-
state->prefix->size);
|
104
|
-
}
|
105
|
-
}
|
106
|
-
state->column = 0;
|
107
|
-
state->begin_line = true;
|
108
|
-
state->need_cr -= 1;
|
109
|
-
}
|
110
|
-
|
111
|
-
while (i < length) {
|
112
|
-
if (state->begin_line) {
|
113
|
-
cmark_strbuf_put(state->buffer, state->prefix->ptr,
|
114
|
-
state->prefix->size);
|
115
|
-
// note: this assumes prefix is ascii:
|
116
|
-
state->column = state->prefix->size;
|
117
|
-
}
|
118
|
-
|
119
|
-
len = utf8proc_iterate(source + i, length - i, &c);
|
120
|
-
if (len == -1) { // error condition
|
121
|
-
return; // return without rendering rest of string
|
53
|
+
cmark_render_ascii(renderer, "\\");
|
54
|
+
cmark_render_code_point(renderer, c);
|
122
55
|
}
|
123
|
-
|
124
|
-
|
125
|
-
if (!state->begin_line) {
|
126
|
-
cmark_strbuf_putc(state->buffer, ' ');
|
127
|
-
state->column += 1;
|
128
|
-
state->begin_line = false;
|
129
|
-
state->last_breakable = state->buffer->size -
|
130
|
-
1;
|
131
|
-
// skip following spaces
|
132
|
-
while (source[i + 1] == ' ') {
|
133
|
-
i++;
|
134
|
-
}
|
135
|
-
}
|
136
|
-
|
137
|
-
} else if (c == 10) {
|
138
|
-
cmark_strbuf_putc(state->buffer, '\n');
|
139
|
-
state->column = 0;
|
140
|
-
state->begin_line = true;
|
141
|
-
state->last_breakable = 0;
|
142
|
-
} else if (needs_escaping(escape, c, nextc, state)) {
|
143
|
-
if (isspace(c)) {
|
144
|
-
// use percent encoding for spaces
|
145
|
-
cmark_strbuf_printf(state->buffer, "%%%2x", c);
|
146
|
-
state->column += 3;
|
147
|
-
} else {
|
148
|
-
cmark_strbuf_putc(state->buffer, '\\');
|
149
|
-
utf8proc_encode_char(c, state->buffer);
|
150
|
-
state->column += 2;
|
151
|
-
}
|
152
|
-
state->begin_line = false;
|
153
|
-
} else {
|
154
|
-
utf8proc_encode_char(c, state->buffer);
|
155
|
-
state->column += 1;
|
156
|
-
state->begin_line = false;
|
157
|
-
}
|
158
|
-
|
159
|
-
// If adding the character went beyond width, look for an
|
160
|
-
// earlier place where the line could be broken:
|
161
|
-
if (state->width > 0 &&
|
162
|
-
state->column > state->width &&
|
163
|
-
!state->begin_line &&
|
164
|
-
state->last_breakable > 0) {
|
165
|
-
|
166
|
-
// copy from last_breakable to remainder
|
167
|
-
cmark_chunk_set_cstr(&remainder, (char *) state->buffer->ptr + state->last_breakable + 1);
|
168
|
-
// truncate at last_breakable
|
169
|
-
cmark_strbuf_truncate(state->buffer, state->last_breakable);
|
170
|
-
// add newline, prefix, and remainder
|
171
|
-
cmark_strbuf_putc(state->buffer, '\n');
|
172
|
-
cmark_strbuf_put(state->buffer, state->prefix->ptr,
|
173
|
-
state->prefix->size);
|
174
|
-
cmark_strbuf_put(state->buffer, remainder.data, remainder.len);
|
175
|
-
state->column = state->prefix->size + remainder.len;
|
176
|
-
cmark_chunk_free(&remainder);
|
177
|
-
state->last_breakable = 0;
|
178
|
-
state->begin_line = false;
|
179
|
-
}
|
180
|
-
|
181
|
-
i += len;
|
56
|
+
} else {
|
57
|
+
cmark_render_code_point(renderer, c);
|
182
58
|
}
|
183
59
|
}
|
184
60
|
|
185
|
-
static void lit(struct render_state *state, char *s, bool wrap)
|
186
|
-
{
|
187
|
-
cmark_chunk str = cmark_chunk_literal(s);
|
188
|
-
out(state, str, wrap, LITERAL);
|
189
|
-
}
|
190
|
-
|
191
61
|
static int
|
192
|
-
longest_backtick_sequence(
|
62
|
+
longest_backtick_sequence(const char *code)
|
193
63
|
{
|
194
64
|
int longest = 0;
|
195
65
|
int current = 0;
|
196
|
-
|
197
|
-
|
198
|
-
|
66
|
+
size_t i = 0;
|
67
|
+
size_t code_len = safe_strlen(code);
|
68
|
+
while (i <= code_len) {
|
69
|
+
if (code[i] == '`') {
|
199
70
|
current++;
|
200
71
|
} else {
|
201
72
|
if (current > longest) {
|
@@ -209,13 +80,14 @@ longest_backtick_sequence(cmark_chunk *code)
|
|
209
80
|
}
|
210
81
|
|
211
82
|
static int
|
212
|
-
shortest_unused_backtick_sequence(
|
83
|
+
shortest_unused_backtick_sequence(const char *code)
|
213
84
|
{
|
214
85
|
int32_t used = 1;
|
215
86
|
int current = 0;
|
216
|
-
|
217
|
-
|
218
|
-
|
87
|
+
size_t i = 0;
|
88
|
+
size_t code_len = safe_strlen(code);
|
89
|
+
while (i <= code_len) {
|
90
|
+
if (code[i] == '`') {
|
219
91
|
current++;
|
220
92
|
} else {
|
221
93
|
if (current) {
|
@@ -240,6 +112,8 @@ is_autolink(cmark_node *node)
|
|
240
112
|
cmark_chunk *title;
|
241
113
|
cmark_chunk *url;
|
242
114
|
cmark_node *link_text;
|
115
|
+
char *realurl;
|
116
|
+
int realurllen;
|
243
117
|
|
244
118
|
if (node->type != CMARK_NODE_LINK) {
|
245
119
|
return false;
|
@@ -258,8 +132,14 @@ is_autolink(cmark_node *node)
|
|
258
132
|
|
259
133
|
link_text = node->first_child;
|
260
134
|
cmark_consolidate_text_nodes(link_text);
|
261
|
-
|
262
|
-
|
135
|
+
realurl = (char*)url->data;
|
136
|
+
realurllen = url->len;
|
137
|
+
if (strncmp(realurl, "mailto:", 7) == 0) {
|
138
|
+
realurl += 7;
|
139
|
+
realurllen -= 7;
|
140
|
+
}
|
141
|
+
return (realurllen == link_text->as.literal.len &&
|
142
|
+
strncmp(realurl,
|
263
143
|
(char*)link_text->as.literal.data,
|
264
144
|
link_text->as.literal.len) == 0);
|
265
145
|
}
|
@@ -278,18 +158,19 @@ get_containing_block(cmark_node *node)
|
|
278
158
|
}
|
279
159
|
|
280
160
|
static int
|
281
|
-
S_render_node(
|
282
|
-
|
161
|
+
S_render_node(cmark_renderer *renderer,
|
162
|
+
cmark_node *node,
|
163
|
+
cmark_event_type ev_type,
|
164
|
+
int options)
|
283
165
|
{
|
284
166
|
cmark_node *tmp;
|
285
|
-
cmark_chunk *code;
|
286
167
|
int list_number;
|
287
168
|
cmark_delim_type list_delim;
|
288
169
|
int numticks;
|
289
170
|
int i;
|
290
171
|
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
291
|
-
|
292
|
-
|
172
|
+
const char *info, *code, *title;
|
173
|
+
size_t info_len, code_len;
|
293
174
|
cmark_strbuf listmarker = GH_BUF_INIT;
|
294
175
|
char *emph_delim;
|
295
176
|
bufsize_t marker_width;
|
@@ -300,7 +181,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
300
181
|
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL &&
|
301
182
|
entering)) {
|
302
183
|
tmp = get_containing_block(node);
|
303
|
-
|
184
|
+
renderer->in_tight_list_item =
|
304
185
|
(tmp->type == CMARK_NODE_ITEM &&
|
305
186
|
cmark_node_get_list_tight(tmp->parent)) ||
|
306
187
|
(tmp &&
|
@@ -311,19 +192,16 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
311
192
|
|
312
193
|
switch (node->type) {
|
313
194
|
case CMARK_NODE_DOCUMENT:
|
314
|
-
if (!entering) {
|
315
|
-
cmark_strbuf_putc(state->buffer, '\n');
|
316
|
-
}
|
317
195
|
break;
|
318
196
|
|
319
197
|
case CMARK_NODE_BLOCK_QUOTE:
|
320
198
|
if (entering) {
|
321
|
-
|
322
|
-
cmark_strbuf_puts(
|
199
|
+
LIT("> ");
|
200
|
+
cmark_strbuf_puts(renderer->prefix, "> ");
|
323
201
|
} else {
|
324
|
-
cmark_strbuf_truncate(
|
325
|
-
|
326
|
-
|
202
|
+
cmark_strbuf_truncate(renderer->prefix,
|
203
|
+
renderer->prefix->size - 2);
|
204
|
+
BLANKLINE();
|
327
205
|
}
|
328
206
|
break;
|
329
207
|
|
@@ -333,8 +211,7 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
333
211
|
node->next->type == CMARK_NODE_LIST)) {
|
334
212
|
// this ensures 2 blank lines after list,
|
335
213
|
// if before code block or list:
|
336
|
-
|
337
|
-
state->need_cr = 0;
|
214
|
+
LIT("\n");
|
338
215
|
}
|
339
216
|
break;
|
340
217
|
|
@@ -363,19 +240,19 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
363
240
|
if (entering) {
|
364
241
|
if (cmark_node_get_list_type(node->parent) ==
|
365
242
|
CMARK_BULLET_LIST) {
|
366
|
-
|
367
|
-
cmark_strbuf_puts(
|
243
|
+
LIT("* ");
|
244
|
+
cmark_strbuf_puts(renderer->prefix, " ");
|
368
245
|
} else {
|
369
|
-
|
246
|
+
LIT((char *)listmarker.ptr);
|
370
247
|
for (i = marker_width; i--;) {
|
371
|
-
cmark_strbuf_putc(
|
248
|
+
cmark_strbuf_putc(renderer->prefix, ' ');
|
372
249
|
}
|
373
250
|
}
|
374
251
|
} else {
|
375
|
-
cmark_strbuf_truncate(
|
376
|
-
|
252
|
+
cmark_strbuf_truncate(renderer->prefix,
|
253
|
+
renderer->prefix->size -
|
377
254
|
marker_width);
|
378
|
-
|
255
|
+
CR();
|
379
256
|
}
|
380
257
|
cmark_strbuf_free(&listmarker);
|
381
258
|
break;
|
@@ -383,119 +260,123 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
383
260
|
case CMARK_NODE_HEADER:
|
384
261
|
if (entering) {
|
385
262
|
for (int i = cmark_node_get_header_level(node); i > 0; i--) {
|
386
|
-
|
263
|
+
LIT("#");
|
387
264
|
}
|
388
|
-
|
389
|
-
|
265
|
+
LIT(" ");
|
266
|
+
renderer->no_wrap = true;
|
390
267
|
} else {
|
391
|
-
|
392
|
-
|
268
|
+
renderer->no_wrap = false;
|
269
|
+
BLANKLINE();
|
393
270
|
}
|
394
271
|
break;
|
395
272
|
|
396
273
|
case CMARK_NODE_CODE_BLOCK:
|
397
|
-
|
398
|
-
info =
|
399
|
-
|
274
|
+
BLANKLINE();
|
275
|
+
info = cmark_node_get_fence_info(node);
|
276
|
+
info_len = safe_strlen(info);
|
277
|
+
code = cmark_node_get_literal(node);
|
278
|
+
code_len = safe_strlen(code);
|
400
279
|
// use indented form if no info, and code doesn't
|
401
280
|
// begin or end with a blank line, and code isn't
|
402
281
|
// first thing in a list item
|
403
|
-
if (
|
404
|
-
(
|
405
|
-
!isspace(code
|
406
|
-
!(isspace(code
|
407
|
-
isspace(code
|
282
|
+
if (info_len == 0 &&
|
283
|
+
(code_len > 2 &&
|
284
|
+
!isspace(code[0]) &&
|
285
|
+
!(isspace(code[code_len - 1]) &&
|
286
|
+
isspace(code[code_len - 2]))) &&
|
408
287
|
!(node->prev == NULL && node->parent &&
|
409
288
|
node->parent->type == CMARK_NODE_ITEM)) {
|
410
|
-
|
411
|
-
cmark_strbuf_puts(
|
412
|
-
|
413
|
-
cmark_strbuf_truncate(
|
414
|
-
|
289
|
+
LIT(" ");
|
290
|
+
cmark_strbuf_puts(renderer->prefix, " ");
|
291
|
+
OUT(cmark_node_get_literal(node), false, LITERAL);
|
292
|
+
cmark_strbuf_truncate(renderer->prefix,
|
293
|
+
renderer->prefix->size - 4);
|
415
294
|
} else {
|
416
295
|
numticks = longest_backtick_sequence(code) + 1;
|
417
296
|
if (numticks < 3) {
|
418
297
|
numticks = 3;
|
419
298
|
}
|
420
299
|
for (i = 0; i < numticks; i++) {
|
421
|
-
|
300
|
+
LIT("`");
|
422
301
|
}
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
302
|
+
LIT(" ");
|
303
|
+
OUT(info, false, LITERAL);
|
304
|
+
CR();
|
305
|
+
OUT(cmark_node_get_literal(node), false, LITERAL);
|
306
|
+
CR();
|
428
307
|
for (i = 0; i < numticks; i++) {
|
429
|
-
|
308
|
+
LIT("`");
|
430
309
|
}
|
431
310
|
}
|
432
|
-
|
311
|
+
BLANKLINE();
|
433
312
|
break;
|
434
313
|
|
435
314
|
case CMARK_NODE_HTML:
|
436
|
-
|
437
|
-
|
438
|
-
|
315
|
+
BLANKLINE();
|
316
|
+
OUT(cmark_node_get_literal(node), false, LITERAL);
|
317
|
+
BLANKLINE();
|
439
318
|
break;
|
440
319
|
|
441
320
|
case CMARK_NODE_HRULE:
|
442
|
-
|
443
|
-
|
444
|
-
|
321
|
+
BLANKLINE();
|
322
|
+
LIT("-----");
|
323
|
+
BLANKLINE();
|
445
324
|
break;
|
446
325
|
|
447
326
|
case CMARK_NODE_PARAGRAPH:
|
448
327
|
if (!entering) {
|
449
|
-
|
328
|
+
BLANKLINE();
|
450
329
|
}
|
451
330
|
break;
|
452
331
|
|
453
332
|
case CMARK_NODE_TEXT:
|
454
|
-
|
333
|
+
OUT(cmark_node_get_literal(node), true, NORMAL);
|
455
334
|
break;
|
456
335
|
|
457
336
|
case CMARK_NODE_LINEBREAK:
|
458
|
-
if (!(CMARK_OPT_HARDBREAKS &
|
459
|
-
|
337
|
+
if (!(CMARK_OPT_HARDBREAKS & options)) {
|
338
|
+
LIT("\\");
|
460
339
|
}
|
461
|
-
|
340
|
+
CR();
|
462
341
|
break;
|
463
342
|
|
464
343
|
case CMARK_NODE_SOFTBREAK:
|
465
|
-
if (
|
466
|
-
|
344
|
+
if (renderer->width == 0 &&
|
345
|
+
!(CMARK_OPT_HARDBREAKS & options)) {
|
346
|
+
CR();
|
467
347
|
} else {
|
468
|
-
|
348
|
+
OUT(" ", true, LITERAL);
|
469
349
|
}
|
470
350
|
break;
|
471
351
|
|
472
352
|
case CMARK_NODE_CODE:
|
473
|
-
code =
|
353
|
+
code = cmark_node_get_literal(node);
|
354
|
+
code_len = safe_strlen(code);
|
474
355
|
numticks = shortest_unused_backtick_sequence(code);
|
475
356
|
for (i = 0; i < numticks; i++) {
|
476
|
-
|
357
|
+
LIT("`");
|
477
358
|
}
|
478
|
-
if (
|
479
|
-
|
359
|
+
if (code_len == 0 || code[0] == '`') {
|
360
|
+
LIT(" ");
|
480
361
|
}
|
481
|
-
|
482
|
-
if (
|
483
|
-
|
362
|
+
OUT(cmark_node_get_literal(node), true, LITERAL);
|
363
|
+
if (code_len == 0 || code[code_len - 1] == '`') {
|
364
|
+
LIT(" ");
|
484
365
|
}
|
485
366
|
for (i = 0; i < numticks; i++) {
|
486
|
-
|
367
|
+
LIT("`");
|
487
368
|
}
|
488
369
|
break;
|
489
370
|
|
490
371
|
case CMARK_NODE_INLINE_HTML:
|
491
|
-
|
372
|
+
OUT(cmark_node_get_literal(node), false, LITERAL);
|
492
373
|
break;
|
493
374
|
|
494
375
|
case CMARK_NODE_STRONG:
|
495
376
|
if (entering) {
|
496
|
-
|
377
|
+
LIT("**");
|
497
378
|
} else {
|
498
|
-
|
379
|
+
LIT("**");
|
499
380
|
}
|
500
381
|
break;
|
501
382
|
|
@@ -509,62 +390,56 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
509
390
|
emph_delim = "*";
|
510
391
|
}
|
511
392
|
if (entering) {
|
512
|
-
|
393
|
+
LIT(emph_delim);
|
513
394
|
} else {
|
514
|
-
|
395
|
+
LIT(emph_delim);
|
515
396
|
}
|
516
397
|
break;
|
517
398
|
|
518
399
|
case CMARK_NODE_LINK:
|
519
400
|
if (is_autolink(node)) {
|
520
401
|
if (entering) {
|
521
|
-
|
402
|
+
LIT("<");
|
522
403
|
if (strncmp(cmark_node_get_url(node),
|
523
404
|
"mailto:", 7) == 0) {
|
524
|
-
|
525
|
-
(char *)cmark_node_get_url(node) + 7,
|
526
|
-
false);
|
405
|
+
LIT((char *)cmark_node_get_url(node) + 7);
|
527
406
|
} else {
|
528
|
-
|
529
|
-
(char *)cmark_node_get_url(node),
|
530
|
-
false);
|
407
|
+
LIT((char *)cmark_node_get_url(node));
|
531
408
|
}
|
532
|
-
|
409
|
+
LIT(">");
|
533
410
|
// return signal to skip contents of node...
|
534
411
|
return 0;
|
535
412
|
}
|
536
413
|
} else {
|
537
414
|
if (entering) {
|
538
|
-
|
415
|
+
LIT("[");
|
539
416
|
} else {
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
out(state, *title, false, TITLE);
|
548
|
-
lit(state, "\"", false);
|
417
|
+
LIT("](");
|
418
|
+
OUT(cmark_node_get_url(node), false, URL);
|
419
|
+
title = cmark_node_get_title(node);
|
420
|
+
if (safe_strlen(title) > 0) {
|
421
|
+
LIT(" \"");
|
422
|
+
OUT(title, false, TITLE);
|
423
|
+
LIT("\"");
|
549
424
|
}
|
550
|
-
|
425
|
+
LIT(")");
|
551
426
|
}
|
552
427
|
}
|
553
428
|
break;
|
554
429
|
|
555
430
|
case CMARK_NODE_IMAGE:
|
556
431
|
if (entering) {
|
557
|
-
|
432
|
+
LIT("![");
|
558
433
|
} else {
|
559
|
-
|
560
|
-
|
561
|
-
title =
|
562
|
-
if (title
|
563
|
-
|
564
|
-
|
565
|
-
|
434
|
+
LIT("](");
|
435
|
+
OUT(cmark_node_get_url(node), false, URL);
|
436
|
+
title = cmark_node_get_title(node);
|
437
|
+
if (safe_strlen(title) > 0) {
|
438
|
+
OUT(" \"", true, LITERAL);
|
439
|
+
OUT(title, false, TITLE);
|
440
|
+
LIT("\"");
|
566
441
|
}
|
567
|
-
|
442
|
+
LIT(")");
|
568
443
|
}
|
569
444
|
break;
|
570
445
|
|
@@ -578,32 +453,10 @@ S_render_node(cmark_node *node, cmark_event_type ev_type,
|
|
578
453
|
|
579
454
|
char *cmark_render_commonmark(cmark_node *root, int options, int width)
|
580
455
|
{
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
if (CMARK_OPT_HARDBREAKS & options) {
|
456
|
+
if (options & CMARK_OPT_HARDBREAKS) {
|
457
|
+
// disable breaking on width, since it has
|
458
|
+
// a different meaning with OPT_HARDBREAKS
|
585
459
|
width = 0;
|
586
460
|
}
|
587
|
-
|
588
|
-
options, &commonmark, &prefix, 0, width,
|
589
|
-
0, 0, true, false, false
|
590
|
-
};
|
591
|
-
cmark_node *cur;
|
592
|
-
cmark_event_type ev_type;
|
593
|
-
cmark_iter *iter = cmark_iter_new(root);
|
594
|
-
|
595
|
-
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
596
|
-
cur = cmark_iter_get_node(iter);
|
597
|
-
if (!S_render_node(cur, ev_type, &state)) {
|
598
|
-
// a false value causes us to skip processing
|
599
|
-
// the node's contents. this is used for
|
600
|
-
// autolinks.
|
601
|
-
cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT);
|
602
|
-
}
|
603
|
-
}
|
604
|
-
result = (char *)cmark_strbuf_detach(&commonmark);
|
605
|
-
|
606
|
-
cmark_strbuf_free(&prefix);
|
607
|
-
cmark_iter_free(iter);
|
608
|
-
return result;
|
461
|
+
return cmark_render(root, options, width, outc, S_render_node);
|
609
462
|
}
|