markly 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/markly +94 -0
- data/ext/markly/arena.c +103 -0
- data/ext/markly/autolink.c +425 -0
- data/ext/markly/autolink.h +8 -0
- data/ext/markly/blocks.c +1585 -0
- data/ext/markly/buffer.c +278 -0
- data/ext/markly/buffer.h +116 -0
- data/ext/markly/case_fold_switch.inc +4327 -0
- data/ext/markly/chunk.h +135 -0
- data/ext/markly/cmark-gfm-core-extensions.h +54 -0
- data/ext/markly/cmark-gfm-extension_api.h +736 -0
- data/ext/markly/cmark-gfm-extensions_export.h +42 -0
- data/ext/markly/cmark-gfm.h +817 -0
- data/ext/markly/cmark-gfm_export.h +42 -0
- data/ext/markly/cmark-gfm_version.h +7 -0
- data/ext/markly/cmark.c +55 -0
- data/ext/markly/cmark_ctype.c +44 -0
- data/ext/markly/cmark_ctype.h +33 -0
- data/ext/markly/commonmark.c +519 -0
- data/ext/markly/config.h +76 -0
- data/ext/markly/core-extensions.c +27 -0
- data/ext/markly/entities.inc +2138 -0
- data/ext/markly/ext_scanners.c +1159 -0
- data/ext/markly/ext_scanners.h +24 -0
- data/ext/markly/extconf.rb +7 -0
- data/ext/markly/footnotes.c +40 -0
- data/ext/markly/footnotes.h +25 -0
- data/ext/markly/houdini.h +57 -0
- data/ext/markly/houdini_href_e.c +100 -0
- data/ext/markly/houdini_html_e.c +66 -0
- data/ext/markly/houdini_html_u.c +149 -0
- data/ext/markly/html.c +465 -0
- data/ext/markly/html.h +27 -0
- data/ext/markly/inlines.c +1633 -0
- data/ext/markly/inlines.h +29 -0
- data/ext/markly/iterator.c +159 -0
- data/ext/markly/iterator.h +26 -0
- data/ext/markly/latex.c +466 -0
- data/ext/markly/linked_list.c +37 -0
- data/ext/markly/man.c +278 -0
- data/ext/markly/map.c +122 -0
- data/ext/markly/map.h +41 -0
- data/ext/markly/markly.c +1226 -0
- data/ext/markly/markly.h +16 -0
- data/ext/markly/node.c +979 -0
- data/ext/markly/node.h +118 -0
- data/ext/markly/parser.h +58 -0
- data/ext/markly/plaintext.c +235 -0
- data/ext/markly/plugin.c +36 -0
- data/ext/markly/plugin.h +34 -0
- data/ext/markly/references.c +42 -0
- data/ext/markly/references.h +26 -0
- data/ext/markly/registry.c +63 -0
- data/ext/markly/registry.h +24 -0
- data/ext/markly/render.c +205 -0
- data/ext/markly/render.h +62 -0
- data/ext/markly/scanners.c +20382 -0
- data/ext/markly/scanners.h +62 -0
- data/ext/markly/scanners.re +326 -0
- data/ext/markly/strikethrough.c +167 -0
- data/ext/markly/strikethrough.h +9 -0
- data/ext/markly/syntax_extension.c +149 -0
- data/ext/markly/syntax_extension.h +34 -0
- data/ext/markly/table.c +803 -0
- data/ext/markly/table.h +12 -0
- data/ext/markly/tagfilter.c +60 -0
- data/ext/markly/tagfilter.h +8 -0
- data/ext/markly/tasklist.c +156 -0
- data/ext/markly/tasklist.h +8 -0
- data/ext/markly/utf8.c +317 -0
- data/ext/markly/utf8.h +35 -0
- data/ext/markly/xml.c +181 -0
- data/lib/markly.rb +43 -0
- data/lib/markly/flags.rb +37 -0
- data/lib/markly/markly.so +0 -0
- data/lib/markly/node.rb +70 -0
- data/lib/markly/node/inspect.rb +59 -0
- data/lib/markly/renderer.rb +133 -0
- data/lib/markly/renderer/html_renderer.rb +252 -0
- data/lib/markly/version.rb +5 -0
- metadata +211 -0
data/ext/markly/utf8.h
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#ifndef CMARK_UTF8_H
|
2
|
+
#define CMARK_UTF8_H
|
3
|
+
|
4
|
+
#include <stdint.h>
|
5
|
+
#include "buffer.h"
|
6
|
+
|
7
|
+
#ifdef __cplusplus
|
8
|
+
extern "C" {
|
9
|
+
#endif
|
10
|
+
|
11
|
+
CMARK_GFM_EXPORT
|
12
|
+
void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
|
13
|
+
bufsize_t len);
|
14
|
+
|
15
|
+
CMARK_GFM_EXPORT
|
16
|
+
void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf);
|
17
|
+
|
18
|
+
CMARK_GFM_EXPORT
|
19
|
+
int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst);
|
20
|
+
|
21
|
+
CMARK_GFM_EXPORT
|
22
|
+
void cmark_utf8proc_check(cmark_strbuf *dest, const uint8_t *line,
|
23
|
+
bufsize_t size);
|
24
|
+
|
25
|
+
CMARK_GFM_EXPORT
|
26
|
+
int cmark_utf8proc_is_space(int32_t uc);
|
27
|
+
|
28
|
+
CMARK_GFM_EXPORT
|
29
|
+
int cmark_utf8proc_is_punctuation(int32_t uc);
|
30
|
+
|
31
|
+
#ifdef __cplusplus
|
32
|
+
}
|
33
|
+
#endif
|
34
|
+
|
35
|
+
#endif
|
data/ext/markly/xml.c
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <assert.h>
|
5
|
+
|
6
|
+
#include "config.h"
|
7
|
+
#include "cmark-gfm.h"
|
8
|
+
#include "node.h"
|
9
|
+
#include "buffer.h"
|
10
|
+
#include "houdini.h"
|
11
|
+
#include "syntax_extension.h"
|
12
|
+
|
13
|
+
#define BUFFER_SIZE 100
|
14
|
+
|
15
|
+
// Functions to convert cmark_nodes to XML strings.
|
16
|
+
|
17
|
+
static void escape_xml(cmark_strbuf *dest, const unsigned char *source,
|
18
|
+
bufsize_t length) {
|
19
|
+
houdini_escape_html0(dest, source, length, 0);
|
20
|
+
}
|
21
|
+
|
22
|
+
struct render_state {
|
23
|
+
cmark_strbuf *xml;
|
24
|
+
int indent;
|
25
|
+
};
|
26
|
+
|
27
|
+
static CMARK_INLINE void indent(struct render_state *state) {
|
28
|
+
int i;
|
29
|
+
for (i = 0; i < state->indent; i++) {
|
30
|
+
cmark_strbuf_putc(state->xml, ' ');
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
static int S_render_node(cmark_node *node, cmark_event_type ev_type,
|
35
|
+
struct render_state *state, int options) {
|
36
|
+
cmark_strbuf *xml = state->xml;
|
37
|
+
bool literal = false;
|
38
|
+
cmark_delim_type delim;
|
39
|
+
bool entering = (ev_type == CMARK_EVENT_ENTER);
|
40
|
+
char buffer[BUFFER_SIZE];
|
41
|
+
|
42
|
+
if (entering) {
|
43
|
+
indent(state);
|
44
|
+
cmark_strbuf_putc(xml, '<');
|
45
|
+
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
46
|
+
|
47
|
+
if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) {
|
48
|
+
snprintf(buffer, BUFFER_SIZE, " sourcepos=\"%d:%d-%d:%d\"",
|
49
|
+
node->start_line, node->start_column, node->end_line,
|
50
|
+
node->end_column);
|
51
|
+
cmark_strbuf_puts(xml, buffer);
|
52
|
+
}
|
53
|
+
|
54
|
+
if (node->extension && node->extension->xml_attr_func) {
|
55
|
+
const char* r = node->extension->xml_attr_func(node->extension, node);
|
56
|
+
if (r != NULL)
|
57
|
+
cmark_strbuf_puts(xml, r);
|
58
|
+
}
|
59
|
+
|
60
|
+
literal = false;
|
61
|
+
|
62
|
+
switch (node->type) {
|
63
|
+
case CMARK_NODE_DOCUMENT:
|
64
|
+
cmark_strbuf_puts(xml, " xmlns=\"http://commonmark.org/xml/1.0\"");
|
65
|
+
break;
|
66
|
+
case CMARK_NODE_TEXT:
|
67
|
+
case CMARK_NODE_CODE:
|
68
|
+
case CMARK_NODE_HTML_BLOCK:
|
69
|
+
case CMARK_NODE_HTML_INLINE:
|
70
|
+
cmark_strbuf_puts(xml, " xml:space=\"preserve\">");
|
71
|
+
escape_xml(xml, node->as.literal.data, node->as.literal.len);
|
72
|
+
cmark_strbuf_puts(xml, "</");
|
73
|
+
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
74
|
+
literal = true;
|
75
|
+
break;
|
76
|
+
case CMARK_NODE_LIST:
|
77
|
+
switch (cmark_node_get_list_type(node)) {
|
78
|
+
case CMARK_ORDERED_LIST:
|
79
|
+
cmark_strbuf_puts(xml, " type=\"ordered\"");
|
80
|
+
snprintf(buffer, BUFFER_SIZE, " start=\"%d\"",
|
81
|
+
cmark_node_get_list_start(node));
|
82
|
+
cmark_strbuf_puts(xml, buffer);
|
83
|
+
delim = cmark_node_get_list_delim(node);
|
84
|
+
if (delim == CMARK_PAREN_DELIM) {
|
85
|
+
cmark_strbuf_puts(xml, " delim=\"paren\"");
|
86
|
+
} else if (delim == CMARK_PERIOD_DELIM) {
|
87
|
+
cmark_strbuf_puts(xml, " delim=\"period\"");
|
88
|
+
}
|
89
|
+
break;
|
90
|
+
case CMARK_BULLET_LIST:
|
91
|
+
cmark_strbuf_puts(xml, " type=\"bullet\"");
|
92
|
+
break;
|
93
|
+
default:
|
94
|
+
break;
|
95
|
+
}
|
96
|
+
snprintf(buffer, BUFFER_SIZE, " tight=\"%s\"",
|
97
|
+
(cmark_node_get_list_tight(node) ? "true" : "false"));
|
98
|
+
cmark_strbuf_puts(xml, buffer);
|
99
|
+
break;
|
100
|
+
case CMARK_NODE_HEADING:
|
101
|
+
snprintf(buffer, BUFFER_SIZE, " level=\"%d\"", node->as.heading.level);
|
102
|
+
cmark_strbuf_puts(xml, buffer);
|
103
|
+
break;
|
104
|
+
case CMARK_NODE_CODE_BLOCK:
|
105
|
+
if (node->as.code.info.len > 0) {
|
106
|
+
cmark_strbuf_puts(xml, " info=\"");
|
107
|
+
escape_xml(xml, node->as.code.info.data, node->as.code.info.len);
|
108
|
+
cmark_strbuf_putc(xml, '"');
|
109
|
+
}
|
110
|
+
cmark_strbuf_puts(xml, " xml:space=\"preserve\">");
|
111
|
+
escape_xml(xml, node->as.code.literal.data, node->as.code.literal.len);
|
112
|
+
cmark_strbuf_puts(xml, "</");
|
113
|
+
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
114
|
+
literal = true;
|
115
|
+
break;
|
116
|
+
case CMARK_NODE_CUSTOM_BLOCK:
|
117
|
+
case CMARK_NODE_CUSTOM_INLINE:
|
118
|
+
cmark_strbuf_puts(xml, " on_enter=\"");
|
119
|
+
escape_xml(xml, node->as.custom.on_enter.data,
|
120
|
+
node->as.custom.on_enter.len);
|
121
|
+
cmark_strbuf_putc(xml, '"');
|
122
|
+
cmark_strbuf_puts(xml, " on_exit=\"");
|
123
|
+
escape_xml(xml, node->as.custom.on_exit.data,
|
124
|
+
node->as.custom.on_exit.len);
|
125
|
+
cmark_strbuf_putc(xml, '"');
|
126
|
+
break;
|
127
|
+
case CMARK_NODE_LINK:
|
128
|
+
case CMARK_NODE_IMAGE:
|
129
|
+
cmark_strbuf_puts(xml, " destination=\"");
|
130
|
+
escape_xml(xml, node->as.link.url.data, node->as.link.url.len);
|
131
|
+
cmark_strbuf_putc(xml, '"');
|
132
|
+
cmark_strbuf_puts(xml, " title=\"");
|
133
|
+
escape_xml(xml, node->as.link.title.data, node->as.link.title.len);
|
134
|
+
cmark_strbuf_putc(xml, '"');
|
135
|
+
break;
|
136
|
+
default:
|
137
|
+
break;
|
138
|
+
}
|
139
|
+
if (node->first_child) {
|
140
|
+
state->indent += 2;
|
141
|
+
} else if (!literal) {
|
142
|
+
cmark_strbuf_puts(xml, " /");
|
143
|
+
}
|
144
|
+
cmark_strbuf_puts(xml, ">\n");
|
145
|
+
|
146
|
+
} else if (node->first_child) {
|
147
|
+
state->indent -= 2;
|
148
|
+
indent(state);
|
149
|
+
cmark_strbuf_puts(xml, "</");
|
150
|
+
cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
|
151
|
+
cmark_strbuf_puts(xml, ">\n");
|
152
|
+
}
|
153
|
+
|
154
|
+
return 1;
|
155
|
+
}
|
156
|
+
|
157
|
+
char *cmark_render_xml(cmark_node *root, int options) {
|
158
|
+
return cmark_render_xml_with_mem(root, options, cmark_node_mem(root));
|
159
|
+
}
|
160
|
+
|
161
|
+
char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem) {
|
162
|
+
char *result;
|
163
|
+
cmark_strbuf xml = CMARK_BUF_INIT(mem);
|
164
|
+
cmark_event_type ev_type;
|
165
|
+
cmark_node *cur;
|
166
|
+
struct render_state state = {&xml, 0};
|
167
|
+
|
168
|
+
cmark_iter *iter = cmark_iter_new(root);
|
169
|
+
|
170
|
+
cmark_strbuf_puts(state.xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
171
|
+
cmark_strbuf_puts(state.xml,
|
172
|
+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n");
|
173
|
+
while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
|
174
|
+
cur = cmark_iter_get_node(iter);
|
175
|
+
S_render_node(cur, ev_type, &state, options);
|
176
|
+
}
|
177
|
+
result = (char *)cmark_strbuf_detach(&xml);
|
178
|
+
|
179
|
+
cmark_iter_free(iter);
|
180
|
+
return result;
|
181
|
+
}
|
data/lib/markly.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# The compiled library.
|
5
|
+
require_relative 'markly/markly'
|
6
|
+
|
7
|
+
require_relative 'markly/flags'
|
8
|
+
require_relative 'markly/node'
|
9
|
+
require_relative 'markly/renderer'
|
10
|
+
require_relative 'markly/renderer/html_renderer'
|
11
|
+
require_relative 'markly/version'
|
12
|
+
|
13
|
+
module Markly
|
14
|
+
# Public: Parses a Markdown string into a `document` node.
|
15
|
+
#
|
16
|
+
# string - {String} to be parsed
|
17
|
+
# option - A {Symbol} or {Array of Symbol}s indicating the parse options
|
18
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
19
|
+
#
|
20
|
+
# Returns the `parser` node.
|
21
|
+
def self.parse(text, flags: DEFAULT, extensions: nil)
|
22
|
+
parser = Parser.new(flags)
|
23
|
+
|
24
|
+
extensions&.each do |extension|
|
25
|
+
parser.enable(extension)
|
26
|
+
end
|
27
|
+
|
28
|
+
return parser.parse(text.encode(Encoding::UTF_8))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Parses a Markdown string into an HTML string.
|
32
|
+
#
|
33
|
+
# text - A {String} of text
|
34
|
+
# option - Either a {Symbol} or {Array of Symbol}s indicating the render options
|
35
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
36
|
+
#
|
37
|
+
# Returns a {String} of converted HTML.
|
38
|
+
def self.render_html(text, flags: DEFAULT, parse_flags: flags, render_flags: flags, extensions: [])
|
39
|
+
root = self.parse(text, flags: parse_flags, extensions: extensions)
|
40
|
+
|
41
|
+
return root.to_html(flags: render_flags, extensions: extensions)
|
42
|
+
end
|
43
|
+
end
|
data/lib/markly/flags.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Markly
|
4
|
+
DEFAULT = 0
|
5
|
+
VALIDATE_UTF8 = 1 << 9
|
6
|
+
SMART = 1 << 10
|
7
|
+
LIBERAL_HTML_TAG = 1 << 12
|
8
|
+
FOOTNOTES = 1 << 13
|
9
|
+
STRIKETHROUGH_DOUBLE_TILDE = 1 << 14
|
10
|
+
UNSAFE = 1 << 17
|
11
|
+
|
12
|
+
PARSE_FLAGS = {
|
13
|
+
validate_utf8: VALIDATE_UTF8,
|
14
|
+
smart_quotes: SMART,
|
15
|
+
liberal_html_tags: LIBERAL_HTML_TAG,
|
16
|
+
footnotes: FOOTNOTES,
|
17
|
+
strikethrough_double_tilde: STRIKETHROUGH_DOUBLE_TILDE,
|
18
|
+
unsafe: UNSAFE,
|
19
|
+
}
|
20
|
+
|
21
|
+
SOURCE_POSITION = 1 << 1
|
22
|
+
HARD_BREAKS = 1 << 2
|
23
|
+
NO_BREAKS = 1 << 4
|
24
|
+
GITHUB_PRE_LANG = 1 << 11
|
25
|
+
TABLE_PREFER_STYLE_ATTRIBUTES = 1 << 15
|
26
|
+
FULL_INFO_STRING = 1 << 16
|
27
|
+
|
28
|
+
RENDER_FLAGS = {
|
29
|
+
source_position: SOURCE_POSITION,
|
30
|
+
hard_breaks: HARD_BREAKS,
|
31
|
+
no_breaks: NO_BREAKS,
|
32
|
+
pre_lang: GITHUB_PRE_LANG,
|
33
|
+
table_prefer_style_attributes: TABLE_PREFER_STYLE_ATTRIBUTES,
|
34
|
+
full_info_string: FULL_INFO_STRING,
|
35
|
+
unsafe: UNSAFE,
|
36
|
+
}
|
37
|
+
end
|
Binary file
|
data/lib/markly/node.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'node/inspect'
|
4
|
+
|
5
|
+
module Markly
|
6
|
+
class Node
|
7
|
+
include Enumerable
|
8
|
+
include Inspect
|
9
|
+
|
10
|
+
# Public: An iterator that "walks the tree," descending into children recursively.
|
11
|
+
#
|
12
|
+
# blk - A {Proc} representing the action to take for each child
|
13
|
+
def walk(&block)
|
14
|
+
return enum_for(:walk) unless block_given?
|
15
|
+
|
16
|
+
yield self
|
17
|
+
each do |child|
|
18
|
+
child.walk(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: Convert the node to an HTML string.
|
23
|
+
#
|
24
|
+
# options - A {Symbol} or {Array of Symbol}s indicating the render options
|
25
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
26
|
+
#
|
27
|
+
# Returns a {String}.
|
28
|
+
def to_html(flags: DEFAULT, extensions: [])
|
29
|
+
_render_html(flags, extensions).force_encoding('utf-8')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Convert the node to a CommonMark string.
|
33
|
+
#
|
34
|
+
# options - A {Symbol} or {Array of Symbol}s indicating the render options
|
35
|
+
# width - Column to wrap the output at
|
36
|
+
#
|
37
|
+
# Returns a {String}.
|
38
|
+
def to_commonmark(flags: DEFAULT, width: 120)
|
39
|
+
_render_commonmark(flags, width).force_encoding('utf-8')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Convert the node to a plain text string.
|
43
|
+
#
|
44
|
+
# options - A {Symbol} or {Array of Symbol}s indicating the render options
|
45
|
+
# width - Column to wrap the output at
|
46
|
+
#
|
47
|
+
# Returns a {String}.
|
48
|
+
def to_plaintext(flags: DEFAULT, width: 120)
|
49
|
+
_render_plaintext(flags, width).force_encoding('utf-8')
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Iterate over the children (if any) of the current pointer.
|
53
|
+
def each
|
54
|
+
return enum_for(:each) unless block_given?
|
55
|
+
|
56
|
+
child = first_child
|
57
|
+
while child
|
58
|
+
nextchild = child.next
|
59
|
+
yield child
|
60
|
+
child = nextchild
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Deprecated: Please use `each` instead
|
65
|
+
def each_child(&block)
|
66
|
+
warn '[DEPRECATION] `each_child` is deprecated. Please use `each` instead.'
|
67
|
+
each(&block)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
module Markly
|
6
|
+
class Node
|
7
|
+
module Inspect
|
8
|
+
PP_INDENT_SIZE = 2
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
PP.pp(self, +'', Float::INFINITY)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param printer [PrettyPrint] pp
|
15
|
+
def pretty_print(printer)
|
16
|
+
printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):", '>') do
|
17
|
+
printer.breakable
|
18
|
+
|
19
|
+
attrs = %i[
|
20
|
+
source_position
|
21
|
+
string_content
|
22
|
+
url
|
23
|
+
title
|
24
|
+
header_level
|
25
|
+
list_type
|
26
|
+
list_start
|
27
|
+
list_tight
|
28
|
+
fence_info
|
29
|
+
].map do |name|
|
30
|
+
begin
|
31
|
+
[name, __send__(name)]
|
32
|
+
rescue Error
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end.compact
|
36
|
+
|
37
|
+
printer.seplist(attrs) do |name, value|
|
38
|
+
printer.text "#{name}="
|
39
|
+
printer.pp value
|
40
|
+
end
|
41
|
+
|
42
|
+
if first_child
|
43
|
+
printer.breakable
|
44
|
+
printer.group(PP_INDENT_SIZE) do
|
45
|
+
children = []
|
46
|
+
node = first_child
|
47
|
+
while node
|
48
|
+
children << node
|
49
|
+
node = node.next
|
50
|
+
end
|
51
|
+
printer.text 'children='
|
52
|
+
printer.pp children
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
module Markly
|
7
|
+
class Renderer
|
8
|
+
attr_accessor :in_tight, :warnings, :in_plain
|
9
|
+
def initialize(flags: DEFAULT, extensions: [])
|
10
|
+
@flags = flags
|
11
|
+
@stream = StringIO.new(+'')
|
12
|
+
@need_blocksep = false
|
13
|
+
@warnings = Set.new
|
14
|
+
@in_tight = false
|
15
|
+
@in_plain = false
|
16
|
+
@tagfilter = extensions.include?(:tagfilter)
|
17
|
+
end
|
18
|
+
|
19
|
+
def out(*args)
|
20
|
+
args.each do |arg|
|
21
|
+
if arg == :children
|
22
|
+
@node.each { |child| out(child) }
|
23
|
+
elsif arg.is_a?(Array)
|
24
|
+
arg.each { |x| render(x) }
|
25
|
+
elsif arg.is_a?(Node)
|
26
|
+
render(arg)
|
27
|
+
else
|
28
|
+
@stream.write(arg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def render(node)
|
34
|
+
@node = node
|
35
|
+
if node.type == :document
|
36
|
+
document(node)
|
37
|
+
@stream.string
|
38
|
+
elsif @in_plain && node.type != :text && node.type != :softbreak
|
39
|
+
node.each { |child| render(child) }
|
40
|
+
else
|
41
|
+
begin
|
42
|
+
send(node.type, node)
|
43
|
+
rescue NoMethodError => e
|
44
|
+
@warnings.add("WARNING: #{node.type} not implemented.")
|
45
|
+
raise e
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def document(_node)
|
51
|
+
out(:children)
|
52
|
+
end
|
53
|
+
|
54
|
+
def code_block(node)
|
55
|
+
code_block(node)
|
56
|
+
end
|
57
|
+
|
58
|
+
def reference_def(_node); end
|
59
|
+
|
60
|
+
def cr
|
61
|
+
return if @stream.string.empty? || @stream.string[-1] == "\n"
|
62
|
+
|
63
|
+
out("\n")
|
64
|
+
end
|
65
|
+
|
66
|
+
def blocksep
|
67
|
+
out("\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
def containersep
|
71
|
+
cr unless @in_tight
|
72
|
+
end
|
73
|
+
|
74
|
+
def block
|
75
|
+
cr
|
76
|
+
yield
|
77
|
+
cr
|
78
|
+
end
|
79
|
+
|
80
|
+
def container(starter, ender)
|
81
|
+
out(starter)
|
82
|
+
yield
|
83
|
+
out(ender)
|
84
|
+
end
|
85
|
+
|
86
|
+
def plain
|
87
|
+
old_in_plain = @in_plain
|
88
|
+
@in_plain = true
|
89
|
+
yield
|
90
|
+
@in_plain = old_in_plain
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def escape_href(str)
|
96
|
+
@node.html_escape_href(str)
|
97
|
+
end
|
98
|
+
|
99
|
+
def escape_html(str)
|
100
|
+
@node.html_escape_html(str)
|
101
|
+
end
|
102
|
+
|
103
|
+
def tagfilter(str)
|
104
|
+
if @tagfilter
|
105
|
+
str.gsub(
|
106
|
+
%r{
|
107
|
+
<
|
108
|
+
(
|
109
|
+
title|textarea|style|xmp|iframe|
|
110
|
+
noembed|noframes|script|plaintext
|
111
|
+
)
|
112
|
+
(?=\s|>|/>)
|
113
|
+
}xi,
|
114
|
+
'<\1'
|
115
|
+
)
|
116
|
+
else
|
117
|
+
str
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def source_position(node)
|
122
|
+
return '' unless flag_enabled?(SOURCE_POSITION)
|
123
|
+
|
124
|
+
s = node.source_position
|
125
|
+
" data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
|
126
|
+
"#{s[:end_line]}:#{s[:end_column]}\""
|
127
|
+
end
|
128
|
+
|
129
|
+
def flag_enabled?(flag)
|
130
|
+
(@flags & flag) != 0
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|