Showing
7 changed files
with
239 additions
and
92 deletions
devtools_options.yaml
0 → 100644
example/devtools_options.yaml
0 → 100644
@@ -76,57 +76,216 @@ class _MyHomePageState extends State<MyHomePage> { | @@ -76,57 +76,216 @@ class _MyHomePageState extends State<MyHomePage> { | ||
76 | TextDirection _direction = TextDirection.ltr; | 76 | TextDirection _direction = TextDirection.ltr; |
77 | final TextEditingController _controller = TextEditingController( | 77 | final TextEditingController _controller = TextEditingController( |
78 | text: r''' | 78 | text: r''' |
79 | -## ChatGPT Response | 79 | +```markdown |
80 | +# Complex Markdown Document for Testing | ||
81 | + | ||
82 | +This document is designed to **challenge** your `gpt_markdown` package by incorporating a wide variety of Markdown components including headers, lists, tables, code blocks, blockquotes, footnotes, and LaTeX math expressions. | ||
83 | + | ||
84 | +--- | ||
85 | + | ||
86 | +## Table of Contents | ||
87 | +1. [Headers and Emphasis](#headers-and-emphasis) | ||
88 | +2. [Lists](#lists) | ||
89 | +3. [Code Blocks and Inline Code](#code-blocks-and-inline-code) | ||
90 | +4. [Tables](#tables) | ||
91 | +5. [Blockquotes and Nested Elements](#blockquotes-and-nested-elements) | ||
92 | +6. [Mathematical Expressions](#mathematical-expressions) | ||
93 | +7. [Links and Images](#links-and-images) | ||
94 | +8. [Footnotes](#footnotes) | ||
95 | +9. [Horizontal Rules and Miscellaneous](#horizontal-rules-and-miscellaneous) | ||
96 | + | ||
97 | +--- | ||
98 | + | ||
99 | +## Headers and Emphasis | ||
100 | + | ||
101 | +### Header Levels | ||
102 | +Markdown supports multiple header levels: | ||
103 | +- `# Header 1` | ||
104 | +- `## Header 2` | ||
105 | +- `### Header 3` | ||
106 | +- `#### Header 4` | ||
107 | +- `##### Header 5` | ||
108 | +- `###### Header 6` | ||
109 | + | ||
110 | +### Emphasis Examples | ||
111 | +- *Italicized text* using single asterisks or underscores. | ||
112 | +- **Bold text** using double asterisks or underscores. | ||
113 | +- ***Bold and italic*** by combining them. | ||
114 | +- ~~Strikethrough~~ text using two tildes. | ||
115 | + | ||
116 | +--- | ||
117 | + | ||
118 | +## Lists | ||
119 | + | ||
120 | +### Unordered List | ||
121 | +- Item 1 | ||
122 | + - Nested Item 1.1 | ||
123 | + - Nested Item 1.2 | ||
124 | + - Deeply Nested Item 1.2.1 | ||
125 | +- Item 2 | ||
126 | + - [ ] Task not completed | ||
127 | + - [x] Task completed | ||
128 | + | ||
129 | +### Ordered List | ||
130 | +1. First item | ||
131 | +2. Second item with nested list: | ||
132 | + 1. Subitem 2.1 | ||
133 | + 2. Subitem 2.2 | ||
134 | +3. Third item | ||
135 | + | ||
136 | +### Mixed List Example | ||
137 | +- **Fruits** | ||
138 | + 1. Apple | ||
139 | + 2. Banana | ||
140 | + 3. Cherry | ||
141 | +- **Vegetables** | ||
142 | + - Carrot | ||
143 | + - Lettuce | ||
144 | + - Spinach | ||
145 | + | ||
146 | +--- | ||
147 | + | ||
148 | +## Code Blocks and Inline Code | ||
149 | + | ||
150 | +### Inline Code | ||
151 | +Here is an example of inline code: `print("Hello, world!")`. | ||
152 | + | ||
153 | +### Fenced Code Block (Python) | ||
154 | +```python | ||
155 | +def greet(name): | ||
156 | + """ | ||
157 | + Greets a person with the provided name. | ||
158 | + """ | ||
159 | + print(f"Hello, {name}!") | ||
160 | + | ||
161 | +greet("Alice") | ||
162 | +``` | ||
80 | 163 | ||
81 | -Welcome to ChatGPT! Below is an example of a response with Markdown and LaTeX code: | 164 | +### Fenced Code Block (JavaScript) |
165 | +```javascript | ||
166 | +function greet(name) { | ||
167 | + console.log(`Hello, ${name}!`); | ||
168 | +} | ||
169 | +greet("Bob"); | ||
170 | +``` | ||
82 | 171 | ||
83 | -### Markdown Example | 172 | +--- |
84 | 173 | ||
174 | +## Tables | ||
85 | 175 | ||
86 | -``` | ||
87 | -class MarkdownHelper { | 176 | +Here is a table demonstrating various elements: |
88 | 177 | ||
178 | +| Syntax | Description | Example | | ||
179 | +| ----------- | ---------------------------------------- | --------------------------------- | | ||
180 | +| Header | Title | **Bold Header** | | ||
181 | +| Paragraph | Text with *italic* and **bold** elements | This is a sample paragraph. | | ||
182 | +| Inline Code | `code snippet` | `let x = 10;` | | ||
89 | 183 | ||
90 | - Map<String, Widget> getTitleWidget(m.Node node) => title.getTitleWidget(node); | 184 | +Additional table with alignment: |
91 | 185 | ||
92 | - Widget getPWidget(m.Element node) => p.getPWidget(node); | 186 | +| Left Align | Center Align | Right Align | |
187 | +| :--------- |:------------:| ----------:| | ||
188 | +| Row 1 | Row 1 | Row 1 | | ||
189 | +| Row 2 | Row 2 | Row 2 | | ||
93 | 190 | ||
94 | - Widget getPreWidget(m.Node node) => pre.getPreWidget(node); | ||
95 | - | ||
96 | -} | ||
97 | -``` | 191 | +--- |
98 | 192 | ||
193 | +## Blockquotes and Nested Elements | ||
99 | 194 | ||
100 | -You can use Markdown to format text easily. Here are some examples: | 195 | +> **Blockquote Header** |
196 | +> | ||
197 | +> This is a blockquote. You can include **bold** and *italic* text, as well as `inline code` within blockquotes. | ||
198 | +> | ||
199 | +> > ### Nested Blockquote | ||
200 | +> > - Nested list item 1 | ||
201 | +> > - Nested list item 2 | ||
202 | +> > 1. Numbered subitem 1 | ||
203 | +> > 2. Numbered subitem 2 | ||
204 | +> > | ||
205 | +> > ```python | ||
206 | +> > # Code snippet inside nested blockquote | ||
207 | +> > for i in range(3): | ||
208 | +> > print(i) | ||
209 | +> > ``` | ||
210 | +> | ||
211 | +> Back to the outer blockquote. | ||
101 | 212 | ||
102 | -- `Highlighted Text`: `This text is highlighted` | ||
103 | -- **Bold Text**: **This text is bold** | ||
104 | -- *Italic Text*: *This text is italicized* | ||
105 | -- [Link](https://www.example.com): [This is a link](https://www.example.com) | ||
106 | -- Lists: | ||
107 | - 1. Item 1 | ||
108 | - 2. Item 2 | ||
109 | - 3. Item 3 | 213 | +--- |
110 | 214 | ||
111 | -### LaTeX Example | 215 | +## Mathematical Expressions |
112 | 216 | ||
113 | -You can also use LaTeX for mathematical expressions. Here's an example: | 217 | +### Inline Math |
218 | +You can write inline math using the `\( ... \)` syntax. For example, the quadratic formula is given by: | ||
219 | +\( x = \frac{-b \pm \sqrt{b^2-4ac}}{2a} \). | ||
114 | 220 | ||
115 | -- **Equation**: \( f(x) = x^2 + 2x + 1 \) | ||
116 | -- **Integral**: \( \int_{0}^{1} x^2 \, dx \) | ||
117 | -- **Matrix**: | 221 | +### Display Math |
222 | +Display math can be rendered using the `\[ ... \]` syntax. For example, consider the integral: | ||
223 | +\[ | ||
224 | +\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi} | ||
225 | +\] | ||
118 | 226 | ||
227 | +More complex display equations: | ||
119 | \[ | 228 | \[ |
120 | -\begin{bmatrix} | ||
121 | -1 & 2 & 3 \\ | ||
122 | -4 & 5 & 6 \\ | ||
123 | -7 & 8 & 9 | ||
124 | -\end{bmatrix} | 229 | +E = mc^2 \quad \text{and} \quad F = ma |
125 | \] | 230 | \] |
126 | 231 | ||
127 | -### Conclusion | 232 | +--- |
233 | + | ||
234 | +## Links and Images | ||
235 | + | ||
236 | +### Links | ||
237 | +Here are examples of links: | ||
238 | +- [OpenAI](https://www.openai.com) | ||
239 | +- [GitHub](https://github.com) | ||
240 | + | ||
241 | +### Images | ||
242 | +Inline images can be embedded as follows: | ||
243 | + | ||
244 | + | ||
245 | +Images can also be referenced with links: | ||
246 | +[](https://via.placeholder.com/500 "Full Image") | ||
128 | 247 | ||
129 | -Markdown and LaTeX can be powerful tools for formatting text and mathematical expressions in your Flutter app. If you have any questions or need further assistance, feel free to ask! | 248 | +--- |
249 | + | ||
250 | +## Footnotes | ||
251 | + | ||
252 | +Here is a statement with a footnote.[^1] Another reference can be added here.[^long] | ||
253 | + | ||
254 | +[^1]: This is a simple footnote. | ||
255 | +[^long]: This footnote contains a longer explanation to showcase how multiple lines can be formatted in a footnote. It supports Markdown formatting such as **bold** and *italic* text. | ||
256 | + | ||
257 | +--- | ||
258 | + | ||
259 | +## Horizontal Rules and Miscellaneous | ||
260 | + | ||
261 | +Horizontal rules can be used to separate sections: | ||
262 | + | ||
263 | +--- | ||
264 | + | ||
265 | +### Task List Example | ||
266 | +- [x] Write complex Markdown document | ||
267 | +- [x] Include LaTeX math expressions | ||
268 | +- [ ] Add more Markdown components if needed | ||
269 | + | ||
270 | +### Nested Quotes with Code and Math | ||
271 | +> **Example of Nested Components** | ||
272 | +> | ||
273 | +> - Inline code: `sum = a + b` | ||
274 | +> - Math expression: \( \sum_{i=1}^n i = \frac{n(n+1)}{2} \) | ||
275 | +> - More text with **bold** formatting. | ||
276 | +> | ||
277 | +> ```javascript | ||
278 | +> // JavaScript code example inside a nested blockquote | ||
279 | +> const sum = (n) => (n * (n + 1)) / 2; | ||
280 | +> console.log(sum(10)); | ||
281 | +> ``` | ||
282 | + | ||
283 | +--- | ||
284 | + | ||
285 | +## Conclusion | ||
286 | + | ||
287 | +This document was created to test the robustness of Markdown parsers and to ensure that all components, including advanced LaTeX expressions and nested structures, are rendered correctly. Enjoy testing and feel free to extend it further! | ||
288 | +``` | ||
130 | ''', | 289 | ''', |
131 | ); | 290 | ); |
132 | File? file; | 291 | File? file; |
@@ -95,15 +95,15 @@ class GptMarkdown extends StatelessWidget { | @@ -95,15 +95,15 @@ class GptMarkdown extends StatelessWidget { | ||
95 | final UnOrderedListBuilder? unOrderedListBuilder; | 95 | final UnOrderedListBuilder? unOrderedListBuilder; |
96 | 96 | ||
97 | /// A method to remove extra lines inside block LaTeX. | 97 | /// A method to remove extra lines inside block LaTeX. |
98 | - String _removeExtraLinesInsideBlockLatex(String text) { | ||
99 | - return text.replaceAllMapped( | ||
100 | - RegExp(r"\\\[(.*?)\\\]", multiLine: true, dotAll: true), | ||
101 | - (match) { | ||
102 | - String content = match[0] ?? ""; | ||
103 | - return content.replaceAllMapped(RegExp(r"\n[\n\ ]+"), (match) => "\n"); | ||
104 | - }, | ||
105 | - ); | ||
106 | - } | 98 | + // String _removeExtraLinesInsideBlockLatex(String text) { |
99 | + // return text.replaceAllMapped( | ||
100 | + // RegExp(r"\\\[(.*?)\\\]", multiLine: true, dotAll: true), | ||
101 | + // (match) { | ||
102 | + // String content = match[0] ?? ""; | ||
103 | + // return content.replaceAllMapped(RegExp(r"\n[\n\ ]+"), (match) => "\n"); | ||
104 | + // }, | ||
105 | + // ); | ||
106 | + // } | ||
107 | 107 | ||
108 | @override | 108 | @override |
109 | Widget build(BuildContext context) { | 109 | Widget build(BuildContext context) { |
@@ -124,7 +124,7 @@ class GptMarkdown extends StatelessWidget { | @@ -124,7 +124,7 @@ class GptMarkdown extends StatelessWidget { | ||
124 | }, | 124 | }, |
125 | ); | 125 | ); |
126 | } | 126 | } |
127 | - tex = _removeExtraLinesInsideBlockLatex(tex); | 127 | + // tex = _removeExtraLinesInsideBlockLatex(tex); |
128 | return ClipRRect( | 128 | return ClipRRect( |
129 | child: MdWidget( | 129 | child: MdWidget( |
130 | tex, | 130 | tex, |
@@ -2,7 +2,7 @@ part of 'gpt_markdown.dart'; | @@ -2,7 +2,7 @@ part of 'gpt_markdown.dart'; | ||
2 | 2 | ||
3 | /// Markdown components | 3 | /// Markdown components |
4 | abstract class MarkdownComponent { | 4 | abstract class MarkdownComponent { |
5 | - static final List<MarkdownComponent> components = [ | 5 | + static List<MarkdownComponent> get components => [ |
6 | CodeBlockMd(), | 6 | CodeBlockMd(), |
7 | NewLines(), | 7 | NewLines(), |
8 | BlockQuote(), | 8 | BlockQuote(), |
@@ -25,7 +25,7 @@ abstract class MarkdownComponent { | @@ -25,7 +25,7 @@ abstract class MarkdownComponent { | ||
25 | IndentMd(), | 25 | IndentMd(), |
26 | ]; | 26 | ]; |
27 | 27 | ||
28 | - static final List<MarkdownComponent> inlineComponents = [ | 28 | + static List<MarkdownComponent> get inlineComponents => [ |
29 | ImageMd(), | 29 | ImageMd(), |
30 | ATagMd(), | 30 | ATagMd(), |
31 | TableMd(), | 31 | TableMd(), |
@@ -68,29 +68,7 @@ abstract class MarkdownComponent { | @@ -68,29 +68,7 @@ abstract class MarkdownComponent { | ||
68 | dotAll: each.exp.isDotAll, | 68 | dotAll: each.exp.isDotAll, |
69 | ); | 69 | ); |
70 | if (exp.hasMatch(element)) { | 70 | if (exp.hasMatch(element)) { |
71 | - if (each.inline) { | ||
72 | - spans.add(each.span(context, element, config)); | ||
73 | - } else { | ||
74 | - spans.addAll([ | ||
75 | - TextSpan( | ||
76 | - text: "\n ", | ||
77 | - style: TextStyle( | ||
78 | - fontSize: 0, | ||
79 | - height: 0, | ||
80 | - color: config.style?.color, | ||
81 | - ), | ||
82 | - ), | ||
83 | - each.span(context, element, config), | ||
84 | - TextSpan( | ||
85 | - text: "\n ", | ||
86 | - style: TextStyle( | ||
87 | - fontSize: 0, | ||
88 | - height: 0, | ||
89 | - color: config.style?.color, | ||
90 | - ), | ||
91 | - ), | ||
92 | - ]); | ||
93 | - } | 71 | + spans.add(each.span(context, element, config)); |
94 | return ""; | 72 | return ""; |
95 | } | 73 | } |
96 | } | 74 | } |
@@ -156,7 +134,12 @@ abstract class BlockMd extends MarkdownComponent { | @@ -156,7 +134,12 @@ abstract class BlockMd extends MarkdownComponent { | ||
156 | child: child, | 134 | child: child, |
157 | ); | 135 | ); |
158 | } | 136 | } |
159 | - return WidgetSpan(child: child, alignment: PlaceholderAlignment.middle); | 137 | + child = Row(children: [Expanded(child: child)]); |
138 | + return WidgetSpan( | ||
139 | + child: child, | ||
140 | + alignment: PlaceholderAlignment.baseline, | ||
141 | + baseline: TextBaseline.alphabetic, | ||
142 | + ); | ||
160 | } | 143 | } |
161 | 144 | ||
162 | Widget build( | 145 | Widget build( |
@@ -293,7 +276,7 @@ class HrLine extends BlockMd { | @@ -293,7 +276,7 @@ class HrLine extends BlockMd { | ||
293 | /// Checkbox component | 276 | /// Checkbox component |
294 | class CheckBoxMd extends BlockMd { | 277 | class CheckBoxMd extends BlockMd { |
295 | @override | 278 | @override |
296 | - String get expString => (r"\[(\x?)\]\ (\S[^\n]*?)$"); | 279 | + String get expString => (r"\[((?:\x|\ ))\]\ (\S[^\n]*?)$"); |
297 | get onLinkTab => null; | 280 | get onLinkTab => null; |
298 | 281 | ||
299 | @override | 282 | @override |
@@ -314,7 +297,7 @@ class CheckBoxMd extends BlockMd { | @@ -314,7 +297,7 @@ class CheckBoxMd extends BlockMd { | ||
314 | /// Radio Button component | 297 | /// Radio Button component |
315 | class RadioButtonMd extends BlockMd { | 298 | class RadioButtonMd extends BlockMd { |
316 | @override | 299 | @override |
317 | - String get expString => (r"\((\x?)\)\ (\S[^\n]*)$"); | 300 | + String get expString => (r"\(((?:\x|\ ))\)\ (\S[^\n]*)$"); |
318 | get onLinkTab => null; | 301 | get onLinkTab => null; |
319 | 302 | ||
320 | @override | 303 | @override |
@@ -390,7 +373,7 @@ class UnOrderedList extends BlockMd { | @@ -390,7 +373,7 @@ class UnOrderedList extends BlockMd { | ||
390 | ) { | 373 | ) { |
391 | var match = this.exp.firstMatch(text); | 374 | var match = this.exp.firstMatch(text); |
392 | 375 | ||
393 | - var child = MdWidget("${match?[1]?.trim()}", false, config: config); | 376 | + var child = MdWidget("${match?[1]?.trim()}", true, config: config); |
394 | 377 | ||
395 | return config.unOrderedListBuilder?.call( | 378 | return config.unOrderedListBuilder?.call( |
396 | context, | 379 | context, |
@@ -428,7 +411,7 @@ class OrderedList extends BlockMd { | @@ -428,7 +411,7 @@ class OrderedList extends BlockMd { | ||
428 | 411 | ||
429 | var no = "${match?[1]}"; | 412 | var no = "${match?[1]}"; |
430 | 413 | ||
431 | - var child = MdWidget("${match?[2]?.trim()}", false, config: config); | 414 | + var child = MdWidget("${match?[2]?.trim()}", true, config: config); |
432 | return config.orderedListBuilder?.call( | 415 | return config.orderedListBuilder?.call( |
433 | context, | 416 | context, |
434 | no, | 417 | no, |
@@ -582,7 +565,8 @@ class ItalicMd extends InlineMd { | @@ -582,7 +565,8 @@ class ItalicMd extends InlineMd { | ||
582 | 565 | ||
583 | class LatexMathMultiLine extends BlockMd { | 566 | class LatexMathMultiLine extends BlockMd { |
584 | @override | 567 | @override |
585 | - String get expString => (r"\\\[(((?!\n\n).)*?)\\\]|(\\begin.*?\\end{.*?})"); | 568 | + String get expString => (r"\ *\\\[((?:.)*?)\\\]|(\ *\\begin.*?\\end{.*?})"); |
569 | + // (r"\ *\\\[((?:(?!\n\n\n).)*?)\\\]|(\\begin.*?\\end{.*?})"); | ||
586 | @override | 570 | @override |
587 | RegExp get exp => RegExp(expString, dotAll: true, multiLine: true); | 571 | RegExp get exp => RegExp(expString, dotAll: true, multiLine: true); |
588 | 572 | ||
@@ -593,7 +577,7 @@ class LatexMathMultiLine extends BlockMd { | @@ -593,7 +577,7 @@ class LatexMathMultiLine extends BlockMd { | ||
593 | final GptMarkdownConfig config, | 577 | final GptMarkdownConfig config, |
594 | ) { | 578 | ) { |
595 | var p0 = exp.firstMatch(text.trim()); | 579 | var p0 = exp.firstMatch(text.trim()); |
596 | - String mathText = p0?[1] ?? p0?[2] ?? ""; | 580 | + String mathText = p0?[1] ?? p0?[2] ?? ''; |
597 | var workaround = config.latexWorkaround ?? (String tex) => tex; | 581 | var workaround = config.latexWorkaround ?? (String tex) => tex; |
598 | 582 | ||
599 | var builder = | 583 | var builder = |
@@ -20,24 +20,21 @@ class MdWidget extends StatelessWidget { | @@ -20,24 +20,21 @@ class MdWidget extends StatelessWidget { | ||
20 | 20 | ||
21 | @override | 21 | @override |
22 | Widget build(BuildContext context) { | 22 | Widget build(BuildContext context) { |
23 | - List<InlineSpan> list = []; | ||
24 | - list.addAll( | ||
25 | - MarkdownComponent.generate( | ||
26 | - context, | ||
27 | - exp, | ||
28 | - // .replaceAllMapped( | ||
29 | - // RegExp( | ||
30 | - // r"\\\[(.*?)\\\]|(\\begin.*?\\end{.*?})", | ||
31 | - // multiLine: true, | ||
32 | - // dotAll: true, | ||
33 | - // ), (match) { | ||
34 | - // // | ||
35 | - // String body = (match[1] ?? match[2])?.replaceAll("\n", " ") ?? ""; | ||
36 | - // return "\\[$body\\]"; | ||
37 | - // }), | ||
38 | - config, | ||
39 | - includeGlobalComponents, | ||
40 | - ), | 23 | + List<InlineSpan> list = MarkdownComponent.generate( |
24 | + context, | ||
25 | + exp, | ||
26 | + // .replaceAllMapped( | ||
27 | + // RegExp( | ||
28 | + // r"\\\[(.*?)\\\]|(\\begin.*?\\end{.*?})", | ||
29 | + // multiLine: true, | ||
30 | + // dotAll: true, | ||
31 | + // ), (match) { | ||
32 | + // // | ||
33 | + // String body = (match[1] ?? match[2])?.replaceAll("\n", " ") ?? ""; | ||
34 | + // return "\\[$body\\]"; | ||
35 | + // }), | ||
36 | + config, | ||
37 | + includeGlobalComponents, | ||
41 | ); | 38 | ); |
42 | return config.getRich( | 39 | return config.getRich( |
43 | TextSpan(children: list, style: config.style?.copyWith()), | 40 | TextSpan(children: list, style: config.style?.copyWith()), |
-
Please register or login to post a comment