react-native-nitro-markdown 0.3.0 → 0.3.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.
- package/README.md +20 -2
- package/cpp/bindings/HybridMarkdownParser.cpp +2 -0
- package/cpp/core/MD4CParser.cpp +73 -39
- package/cpp/core/MarkdownTypes.hpp +6 -1
- package/cpp/md4c/md4c.c +79 -56
- package/cpp/md4c/md4c.h +7 -4
- package/lib/commonjs/headless.js +38 -1
- package/lib/commonjs/headless.js.map +1 -1
- package/lib/commonjs/markdown.js +19 -11
- package/lib/commonjs/markdown.js.map +1 -1
- package/lib/commonjs/renderers/image.js +26 -5
- package/lib/commonjs/renderers/image.js.map +1 -1
- package/lib/commonjs/renderers/list.js +1 -3
- package/lib/commonjs/renderers/list.js.map +1 -1
- package/lib/commonjs/renderers/math.js +14 -4
- package/lib/commonjs/renderers/math.js.map +1 -1
- package/lib/commonjs/renderers/paragraph.js +0 -1
- package/lib/commonjs/renderers/paragraph.js.map +1 -1
- package/lib/module/headless.js +36 -0
- package/lib/module/headless.js.map +1 -1
- package/lib/module/markdown.js +20 -12
- package/lib/module/markdown.js.map +1 -1
- package/lib/module/renderers/image.js +27 -6
- package/lib/module/renderers/image.js.map +1 -1
- package/lib/module/renderers/list.js +1 -3
- package/lib/module/renderers/list.js.map +1 -1
- package/lib/module/renderers/math.js +14 -4
- package/lib/module/renderers/math.js.map +1 -1
- package/lib/module/renderers/paragraph.js +0 -1
- package/lib/module/renderers/paragraph.js.map +1 -1
- package/lib/typescript/commonjs/headless.d.ts +4 -0
- package/lib/typescript/commonjs/headless.d.ts.map +1 -1
- package/lib/typescript/commonjs/markdown.d.ts +13 -0
- package/lib/typescript/commonjs/markdown.d.ts.map +1 -1
- package/lib/typescript/commonjs/renderers/image.d.ts.map +1 -1
- package/lib/typescript/commonjs/renderers/list.d.ts.map +1 -1
- package/lib/typescript/commonjs/renderers/math.d.ts.map +1 -1
- package/lib/typescript/commonjs/renderers/paragraph.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/MarkdownSession.nitro.d.ts.map +1 -1
- package/lib/typescript/module/headless.d.ts +4 -0
- package/lib/typescript/module/headless.d.ts.map +1 -1
- package/lib/typescript/module/markdown.d.ts +13 -0
- package/lib/typescript/module/markdown.d.ts.map +1 -1
- package/lib/typescript/module/renderers/image.d.ts.map +1 -1
- package/lib/typescript/module/renderers/list.d.ts.map +1 -1
- package/lib/typescript/module/renderers/math.d.ts.map +1 -1
- package/lib/typescript/module/renderers/paragraph.d.ts.map +1 -1
- package/lib/typescript/module/specs/MarkdownSession.nitro.d.ts.map +1 -1
- package/nitrogen/generated/ios/NitroMarkdownAutolinking.swift +8 -7
- package/nitrogen/generated/ios/swift/HybridMarkdownSessionSpec.swift +2 -2
- package/package.json +1 -1
- package/src/headless.ts +56 -1
- package/src/markdown.tsx +40 -16
- package/src/renderers/image.tsx +35 -6
- package/src/renderers/list.tsx +5 -11
- package/src/renderers/math.tsx +8 -2
- package/src/renderers/paragraph.tsx +1 -2
- package/src/specs/MarkdownSession.nitro.ts +4 -6
package/README.md
CHANGED
|
@@ -76,8 +76,8 @@ cd ios && pod install
|
|
|
76
76
|
If you are using Expo, you must run a **Prebuild** (Development Build) because this package contains native C++ code.
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
bunx expo install react-native-nitro-markdown react-native-nitro-modules
|
|
80
|
+
bunx expo prebuild
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
---
|
|
@@ -265,10 +265,12 @@ For maximum control, data processing, or minimal JS overhead:
|
|
|
265
265
|
import {
|
|
266
266
|
parseMarkdown,
|
|
267
267
|
getTextContent,
|
|
268
|
+
getFlattenedText,
|
|
268
269
|
} from "react-native-nitro-markdown/headless";
|
|
269
270
|
|
|
270
271
|
const ast = parseMarkdown("# Hello World");
|
|
271
272
|
const text = getTextContent(ast); // "Hello World"
|
|
273
|
+
const fullText = getFlattenedText(ast); // "Hello World\n\n" (Normalized with line breaks)
|
|
272
274
|
```
|
|
273
275
|
|
|
274
276
|
### Option 10: High-Performance Streaming (LLMs)
|
|
@@ -295,6 +297,21 @@ export function AIResponseStream() {
|
|
|
295
297
|
}
|
|
296
298
|
```
|
|
297
299
|
|
|
300
|
+
### Option 11: Extracting Plain Text
|
|
301
|
+
|
|
302
|
+
You can extract the plain text representation (with proper line breaks) using the `onParseComplete` callback. This is useful for "Copy All" buttons or TTS.
|
|
303
|
+
|
|
304
|
+
```tsx
|
|
305
|
+
<Markdown
|
|
306
|
+
onParseComplete={(result) => {
|
|
307
|
+
console.log(result.text); // "Hello World\n\nThis is bold text."
|
|
308
|
+
console.log(result.ast); // Full AST
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
{markdown}
|
|
312
|
+
</Markdown>
|
|
313
|
+
```
|
|
314
|
+
|
|
298
315
|
---
|
|
299
316
|
|
|
300
317
|
## 🎨 Using Context in Custom Renderers
|
|
@@ -324,6 +341,7 @@ export {
|
|
|
324
341
|
parseMarkdown,
|
|
325
342
|
parseMarkdownWithOptions,
|
|
326
343
|
getTextContent,
|
|
344
|
+
getFlattenedText,
|
|
327
345
|
} from "./headless";
|
|
328
346
|
|
|
329
347
|
// Theme presets
|
|
@@ -48,6 +48,8 @@ std::string HybridMarkdownParser::nodeToJson(const std::shared_ptr<InternalMarkd
|
|
|
48
48
|
std::ostringstream json;
|
|
49
49
|
json << "{";
|
|
50
50
|
json << "\"type\":\"" << ::NitroMarkdown::nodeTypeToString(node->type) << "\"";
|
|
51
|
+
json << ",\"beg\":" << node->beg;
|
|
52
|
+
json << ",\"end\":" << node->end;
|
|
51
53
|
|
|
52
54
|
if (node->content.has_value()) {
|
|
53
55
|
json << ",\"content\":\"" << escapeJson(node->content.value()) << "\"";
|
package/cpp/core/MD4CParser.cpp
CHANGED
|
@@ -12,6 +12,9 @@ public:
|
|
|
12
12
|
std::stack<std::shared_ptr<MarkdownNode>> nodeStack;
|
|
13
13
|
std::string currentText;
|
|
14
14
|
const char* inputText = nullptr;
|
|
15
|
+
size_t inputTextSize = 0;
|
|
16
|
+
OFF currentTextBeg = 0;
|
|
17
|
+
OFF lastTextEnd = 0;
|
|
15
18
|
|
|
16
19
|
void reset() {
|
|
17
20
|
root = std::make_shared<MarkdownNode>(NodeType::Document);
|
|
@@ -19,28 +22,34 @@ public:
|
|
|
19
22
|
nodeStack.push(root);
|
|
20
23
|
currentText.clear();
|
|
21
24
|
currentText.reserve(256);
|
|
25
|
+
currentTextBeg = 0;
|
|
26
|
+
lastTextEnd = 0;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
void flushText() {
|
|
25
30
|
if (!currentText.empty() && !nodeStack.empty()) {
|
|
26
31
|
auto textNode = std::make_shared<MarkdownNode>(NodeType::Text);
|
|
27
32
|
textNode->content = std::move(currentText);
|
|
33
|
+
textNode->beg = currentTextBeg;
|
|
34
|
+
textNode->end = lastTextEnd;
|
|
28
35
|
nodeStack.top()->addChild(std::move(textNode));
|
|
29
36
|
currentText.clear();
|
|
30
37
|
}
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
void pushNode(std::shared_ptr<MarkdownNode> node) {
|
|
40
|
+
void pushNode(std::shared_ptr<MarkdownNode> node, OFF beg = 0) {
|
|
34
41
|
flushText();
|
|
35
42
|
if (node && !nodeStack.empty()) {
|
|
43
|
+
node->beg = beg;
|
|
36
44
|
nodeStack.top()->addChild(node);
|
|
37
45
|
nodeStack.push(std::move(node));
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
void popNode() {
|
|
49
|
+
void popNode(OFF end = 0) {
|
|
42
50
|
flushText();
|
|
43
51
|
if (nodeStack.size() > 1) {
|
|
52
|
+
nodeStack.top()->end = end;
|
|
44
53
|
nodeStack.pop();
|
|
45
54
|
}
|
|
46
55
|
}
|
|
@@ -68,7 +77,7 @@ public:
|
|
|
68
77
|
return result;
|
|
69
78
|
}
|
|
70
79
|
|
|
71
|
-
static int enterBlock(MD_BLOCKTYPE type, void* detail, void* userdata) {
|
|
80
|
+
static int enterBlock(MD_BLOCKTYPE type, void* detail, MD_OFFSET off, void* userdata) {
|
|
72
81
|
auto* impl = static_cast<Impl*>(userdata);
|
|
73
82
|
|
|
74
83
|
switch (type) {
|
|
@@ -76,14 +85,14 @@ public:
|
|
|
76
85
|
break;
|
|
77
86
|
|
|
78
87
|
case MD_BLOCK_QUOTE: {
|
|
79
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Blockquote));
|
|
88
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Blockquote), off);
|
|
80
89
|
break;
|
|
81
90
|
}
|
|
82
91
|
|
|
83
92
|
case MD_BLOCK_UL: {
|
|
84
93
|
auto node = std::make_shared<MarkdownNode>(NodeType::List);
|
|
85
94
|
node->ordered = false;
|
|
86
|
-
impl->pushNode(node);
|
|
95
|
+
impl->pushNode(node, off);
|
|
87
96
|
break;
|
|
88
97
|
}
|
|
89
98
|
|
|
@@ -92,7 +101,7 @@ public:
|
|
|
92
101
|
auto node = std::make_shared<MarkdownNode>(NodeType::List);
|
|
93
102
|
node->ordered = true;
|
|
94
103
|
node->start = d->start;
|
|
95
|
-
impl->pushNode(node);
|
|
104
|
+
impl->pushNode(node, off);
|
|
96
105
|
break;
|
|
97
106
|
}
|
|
98
107
|
|
|
@@ -101,17 +110,15 @@ public:
|
|
|
101
110
|
if (d->is_task) {
|
|
102
111
|
auto node = std::make_shared<MarkdownNode>(NodeType::TaskListItem);
|
|
103
112
|
node->checked = (d->task_mark == 'x' || d->task_mark == 'X');
|
|
104
|
-
impl->pushNode(node);
|
|
113
|
+
impl->pushNode(node, off);
|
|
105
114
|
} else {
|
|
106
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::ListItem));
|
|
115
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::ListItem), off);
|
|
107
116
|
}
|
|
108
117
|
break;
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
case MD_BLOCK_HR: {
|
|
112
|
-
impl->
|
|
113
|
-
impl->nodeStack.top()->addChild(
|
|
114
|
-
std::make_shared<MarkdownNode>(NodeType::HorizontalRule));
|
|
121
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::HorizontalRule), off);
|
|
115
122
|
break;
|
|
116
123
|
}
|
|
117
124
|
|
|
@@ -119,7 +126,7 @@ public:
|
|
|
119
126
|
auto* d = static_cast<MD_BLOCK_H_DETAIL*>(detail);
|
|
120
127
|
auto node = std::make_shared<MarkdownNode>(NodeType::Heading);
|
|
121
128
|
node->level = d->level;
|
|
122
|
-
impl->pushNode(node);
|
|
129
|
+
impl->pushNode(node, off);
|
|
123
130
|
break;
|
|
124
131
|
}
|
|
125
132
|
|
|
@@ -129,37 +136,37 @@ public:
|
|
|
129
136
|
if (d->lang.text && d->lang.size > 0) {
|
|
130
137
|
node->language = std::string(d->lang.text, d->lang.size);
|
|
131
138
|
}
|
|
132
|
-
impl->pushNode(node);
|
|
139
|
+
impl->pushNode(node, off);
|
|
133
140
|
break;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
case MD_BLOCK_HTML: {
|
|
137
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::HtmlBlock));
|
|
144
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::HtmlBlock), off);
|
|
138
145
|
break;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
case MD_BLOCK_P: {
|
|
142
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Paragraph));
|
|
149
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Paragraph), off);
|
|
143
150
|
break;
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
case MD_BLOCK_TABLE: {
|
|
147
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Table));
|
|
154
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Table), off);
|
|
148
155
|
break;
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
case MD_BLOCK_THEAD: {
|
|
152
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableHead));
|
|
159
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableHead), off);
|
|
153
160
|
break;
|
|
154
161
|
}
|
|
155
162
|
|
|
156
163
|
case MD_BLOCK_TBODY: {
|
|
157
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableBody));
|
|
164
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableBody), off);
|
|
158
165
|
break;
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
case MD_BLOCK_TR: {
|
|
162
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableRow));
|
|
169
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::TableRow), off);
|
|
163
170
|
break;
|
|
164
171
|
}
|
|
165
172
|
|
|
@@ -173,7 +180,7 @@ public:
|
|
|
173
180
|
case MD_ALIGN_RIGHT: node->align = TextAlign::Right; break;
|
|
174
181
|
default: node->align = TextAlign::Default; break;
|
|
175
182
|
}
|
|
176
|
-
impl->pushNode(node);
|
|
183
|
+
impl->pushNode(node, off);
|
|
177
184
|
break;
|
|
178
185
|
}
|
|
179
186
|
|
|
@@ -187,7 +194,7 @@ public:
|
|
|
187
194
|
case MD_ALIGN_RIGHT: node->align = TextAlign::Right; break;
|
|
188
195
|
default: node->align = TextAlign::Default; break;
|
|
189
196
|
}
|
|
190
|
-
impl->pushNode(node);
|
|
197
|
+
impl->pushNode(node, off);
|
|
191
198
|
break;
|
|
192
199
|
}
|
|
193
200
|
}
|
|
@@ -195,38 +202,41 @@ public:
|
|
|
195
202
|
return 0;
|
|
196
203
|
}
|
|
197
204
|
|
|
198
|
-
static int leaveBlock(MD_BLOCKTYPE type, void* detail, void* userdata) {
|
|
205
|
+
static int leaveBlock(MD_BLOCKTYPE type, void* detail, MD_OFFSET off, void* userdata) {
|
|
199
206
|
(void)detail;
|
|
200
207
|
auto* impl = static_cast<Impl*>(userdata);
|
|
201
208
|
|
|
202
209
|
switch (type) {
|
|
203
210
|
case MD_BLOCK_DOC:
|
|
211
|
+
impl->root->end = off;
|
|
212
|
+
break;
|
|
204
213
|
case MD_BLOCK_HR:
|
|
214
|
+
impl->popNode(off);
|
|
205
215
|
break;
|
|
206
216
|
default:
|
|
207
|
-
impl->popNode();
|
|
217
|
+
impl->popNode(off);
|
|
208
218
|
break;
|
|
209
219
|
}
|
|
210
220
|
|
|
211
221
|
return 0;
|
|
212
222
|
}
|
|
213
223
|
|
|
214
|
-
static int enterSpan(MD_SPANTYPE type, void* detail, void* userdata) {
|
|
224
|
+
static int enterSpan(MD_SPANTYPE type, void* detail, MD_OFFSET off, void* userdata) {
|
|
215
225
|
auto* impl = static_cast<Impl*>(userdata);
|
|
216
226
|
|
|
217
227
|
switch (type) {
|
|
218
228
|
case MD_SPAN_EM: {
|
|
219
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Italic));
|
|
229
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Italic), off);
|
|
220
230
|
break;
|
|
221
231
|
}
|
|
222
232
|
|
|
223
233
|
case MD_SPAN_STRONG: {
|
|
224
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Bold));
|
|
234
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Bold), off);
|
|
225
235
|
break;
|
|
226
236
|
}
|
|
227
237
|
|
|
228
238
|
case MD_SPAN_DEL: {
|
|
229
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Strikethrough));
|
|
239
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Strikethrough), off);
|
|
230
240
|
break;
|
|
231
241
|
}
|
|
232
242
|
|
|
@@ -239,7 +249,7 @@ public:
|
|
|
239
249
|
if (d->title.text && d->title.size > 0) {
|
|
240
250
|
node->title = std::string(d->title.text, d->title.size);
|
|
241
251
|
}
|
|
242
|
-
impl->pushNode(node);
|
|
252
|
+
impl->pushNode(node, off);
|
|
243
253
|
break;
|
|
244
254
|
}
|
|
245
255
|
|
|
@@ -252,33 +262,33 @@ public:
|
|
|
252
262
|
if (d->title.text && d->title.size > 0) {
|
|
253
263
|
node->title = std::string(d->title.text, d->title.size);
|
|
254
264
|
}
|
|
255
|
-
impl->pushNode(node);
|
|
265
|
+
impl->pushNode(node, off);
|
|
256
266
|
break;
|
|
257
267
|
}
|
|
258
268
|
|
|
259
269
|
case MD_SPAN_CODE: {
|
|
260
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::CodeInline));
|
|
270
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::CodeInline), off);
|
|
261
271
|
break;
|
|
262
272
|
}
|
|
263
273
|
|
|
264
274
|
case MD_SPAN_LATEXMATH: {
|
|
265
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::MathInline));
|
|
275
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::MathInline), off);
|
|
266
276
|
break;
|
|
267
277
|
}
|
|
268
278
|
|
|
269
279
|
case MD_SPAN_LATEXMATH_DISPLAY: {
|
|
270
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::MathBlock));
|
|
280
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::MathBlock), off);
|
|
271
281
|
break;
|
|
272
282
|
}
|
|
273
283
|
|
|
274
284
|
case MD_SPAN_U: {
|
|
275
|
-
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Italic));
|
|
285
|
+
impl->pushNode(std::make_shared<MarkdownNode>(NodeType::Italic), off);
|
|
276
286
|
break;
|
|
277
287
|
}
|
|
278
288
|
|
|
279
289
|
case MD_SPAN_WIKILINK: {
|
|
280
290
|
auto node = std::make_shared<MarkdownNode>(NodeType::Link);
|
|
281
|
-
impl->pushNode(node);
|
|
291
|
+
impl->pushNode(node, off);
|
|
282
292
|
break;
|
|
283
293
|
}
|
|
284
294
|
}
|
|
@@ -286,7 +296,7 @@ public:
|
|
|
286
296
|
return 0;
|
|
287
297
|
}
|
|
288
298
|
|
|
289
|
-
static int leaveSpan(MD_SPANTYPE type, void* detail, void* userdata) {
|
|
299
|
+
static int leaveSpan(MD_SPANTYPE type, void* detail, MD_OFFSET off, void* userdata) {
|
|
290
300
|
(void)detail;
|
|
291
301
|
auto* impl = static_cast<Impl*>(userdata);
|
|
292
302
|
|
|
@@ -309,7 +319,7 @@ public:
|
|
|
309
319
|
}
|
|
310
320
|
}
|
|
311
321
|
|
|
312
|
-
impl->popNode();
|
|
322
|
+
impl->popNode(off);
|
|
313
323
|
return 0;
|
|
314
324
|
}
|
|
315
325
|
|
|
@@ -320,6 +330,7 @@ public:
|
|
|
320
330
|
|
|
321
331
|
switch (type) {
|
|
322
332
|
case MD_TEXT_NULLCHAR:
|
|
333
|
+
if (impl->currentText.empty()) impl->currentTextBeg = impl->lastTextEnd;
|
|
323
334
|
impl->currentText += '\0';
|
|
324
335
|
break;
|
|
325
336
|
|
|
@@ -345,15 +356,37 @@ public:
|
|
|
345
356
|
break;
|
|
346
357
|
|
|
347
358
|
case MD_TEXT_ENTITY:
|
|
348
|
-
|
|
359
|
+
if (text && size > 0) {
|
|
360
|
+
MD_OFFSET off = impl->lastTextEnd;
|
|
361
|
+
ptrdiff_t diff = text - impl->inputText;
|
|
362
|
+
if (diff >= 0 && static_cast<size_t>(diff) <= impl->inputTextSize) {
|
|
363
|
+
off = static_cast<MD_OFFSET>(diff);
|
|
364
|
+
}
|
|
365
|
+
if (impl->currentText.empty()) impl->currentTextBeg = off;
|
|
366
|
+
impl->currentText.append(text, size);
|
|
367
|
+
impl->lastTextEnd = off + size;
|
|
368
|
+
}
|
|
349
369
|
break;
|
|
350
370
|
|
|
351
371
|
case MD_TEXT_NORMAL:
|
|
352
372
|
case MD_TEXT_CODE:
|
|
353
373
|
case MD_TEXT_LATEXMATH:
|
|
354
|
-
default:
|
|
355
|
-
|
|
374
|
+
default: {
|
|
375
|
+
if (text && size > 0) {
|
|
376
|
+
MD_OFFSET off = impl->lastTextEnd;
|
|
377
|
+
ptrdiff_t diff = text - impl->inputText;
|
|
378
|
+
if (diff >= 0 && static_cast<size_t>(diff) <= impl->inputTextSize) {
|
|
379
|
+
off = static_cast<MD_OFFSET>(diff);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (impl->currentText.empty()) {
|
|
383
|
+
impl->currentTextBeg = off;
|
|
384
|
+
}
|
|
385
|
+
impl->currentText.append(text, size);
|
|
386
|
+
impl->lastTextEnd = off + size;
|
|
387
|
+
}
|
|
356
388
|
break;
|
|
389
|
+
}
|
|
357
390
|
}
|
|
358
391
|
|
|
359
392
|
return 0;
|
|
@@ -367,6 +400,7 @@ MD4CParser::~MD4CParser() = default;
|
|
|
367
400
|
std::shared_ptr<MarkdownNode> MD4CParser::parse(const std::string& markdown, const ParserOptions& options) {
|
|
368
401
|
impl_->reset();
|
|
369
402
|
impl_->inputText = markdown.c_str();
|
|
403
|
+
impl_->inputTextSize = markdown.size();
|
|
370
404
|
|
|
371
405
|
unsigned int flags = MD_FLAG_NOHTML;
|
|
372
406
|
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
namespace NitroMarkdown {
|
|
9
9
|
|
|
10
|
+
typedef unsigned MD_OFFSET;
|
|
11
|
+
typedef MD_OFFSET OFF;
|
|
12
|
+
|
|
10
13
|
enum class NodeType {
|
|
11
14
|
Document,
|
|
12
15
|
Heading,
|
|
@@ -99,9 +102,11 @@ struct MarkdownNode {
|
|
|
99
102
|
std::optional<bool> checked;
|
|
100
103
|
std::optional<bool> isHeader;
|
|
101
104
|
std::optional<TextAlign> align;
|
|
105
|
+
OFF beg;
|
|
106
|
+
OFF end;
|
|
102
107
|
std::vector<std::shared_ptr<MarkdownNode>> children;
|
|
103
108
|
|
|
104
|
-
explicit MarkdownNode(NodeType t) : type(t) {}
|
|
109
|
+
explicit MarkdownNode(NodeType t) : type(t), beg(0), end(0) {}
|
|
105
110
|
|
|
106
111
|
void addChild(std::shared_ptr<MarkdownNode> child) {
|
|
107
112
|
if (child) {
|