顾海波

Merge remote-tracking branch 'github/main'

# Conflicts:
#	example/lib/main.dart
1 ## 1.0.16 1 ## 1.0.16
2 2
3 * `IndentMd` and `BlockQuote` fixed. 3 * `IndentMd` and `BlockQuote` fixed.
  4 +* Baseline of bloc type component is fixed.
  5 +* block quote support improved.
  6 +* custom components support added.
  7 +* `Table` syntax improved.
4 8
5 ## 1.0.15 9 ## 1.0.15
6 10
@@ -21,15 +21,16 @@ A comprehensive Flutter package for rendering rich Markdown and LaTeX content in @@ -21,15 +21,16 @@ A comprehensive Flutter package for rendering rich Markdown and LaTeX content in
21 | ➖ Horizontal Line | ✅ | | 21 | ➖ Horizontal Line | ✅ | |
22 | 🔢 Latex Math | ✅ | | 22 | 🔢 Latex Math | ✅ | |
23 | ↩️ Indent | ✅ | 23 | ↩️ Indent | ✅ |
  24 +| ↩️ BlockQuote | ✅ |
24 | 🖼️ Image | ✅ | 25 | 🖼️ Image | ✅ |
25 | ✨ Highlighted Text | ✅ | 26 | ✨ Highlighted Text | ✅ |
26 -| ✂️ Striked Text | ✅ | 27 +| ✂️ Strike Text | ✅ |
27 | 🔵 Bold Text | ✅ | 28 | 🔵 Bold Text | ✅ |
28 | 📜 Italic Text | ✅ | 29 | 📜 Italic Text | ✅ |
29 | 🔗 Links | ✅ | 30 | 🔗 Links | ✅ |
30 | 📱 Selectable | ✅ | 31 | 📱 Selectable | ✅ |
  32 +| 🧩 Custom components | ✅ | |
31 | 📎 Underline | | 🔜 | 33 | 📎 Underline | | 🔜 |
32 -| 🧩 Custom components | | 🔜 |  
33 34
34 ## ✨ Key Features 35 ## ✨ Key Features
35 36
  1 +description: This file stores settings for Dart & Flutter DevTools.
  2 +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
  3 +extensions:
  1 +description: This file stores settings for Dart & Flutter DevTools.
  2 +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
  3 +extensions:
@@ -76,19 +76,216 @@ class _MyHomePageState extends State<MyHomePage> { @@ -76,19 +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 +```markdown
  80 +# Complex Markdown Document for Testing
79 81
80 -一袋大米25千克,已经吃了它的$\frac{2}{5}$,吃了( )千克,还剩( )千克。  
81 -1. 计算已经吃的大米重量:  
82 - $$  
83 - 已经吃的大米重量 = 25 \text{千克} \times \frac{2}{5} = 25 \times 0.4 = 1  
84 -$$  
85 -2. 计算剩余的大米重量:  
86 - $$  
87 - 剩余的大米重量 = 25 \text{千克} - 10 \text{千克} = 15 \text{千克}  
88 -$$  
89 -【答案】  
90 -吃了10千克,还剩15千克。 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.
91 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 +```
  163 +
  164 +### Fenced Code Block (JavaScript)
  165 +```javascript
  166 +function greet(name) {
  167 + console.log(`Hello, ${name}!`);
  168 +}
  169 +greet("Bob");
  170 +```
  171 +
  172 +---
  173 +
  174 +## Tables
  175 +
  176 +Here is a table demonstrating various elements:
  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;` |
  183 +
  184 +Additional table with alignment:
  185 +
  186 +| Left Align | Center Align | Right Align |
  187 +| :--------- |:------------:| ----------:|
  188 +| Row 1 | Row 1 | Row 1 |
  189 +| Row 2 | Row 2 | Row 2 |
  190 +
  191 +---
  192 +
  193 +## Blockquotes and Nested Elements
  194 +
  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.
  212 +
  213 +---
  214 +
  215 +## Mathematical Expressions
  216 +
  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} \).
  220 +
  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 +\]
  226 +
  227 +More complex display equations:
  228 +\[
  229 +E = mc^2 \quad \text{and} \quad F = ma
  230 +\]
  231 +
  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 +![Alt Text for Image](https://via.placeholder.com/150 "Image Title")
  244 +
  245 +Images can also be referenced with links:
  246 +[![Linked Image](https://via.placeholder.com/100 "Thumbnail")](https://via.placeholder.com/500 "Full Image")
  247 +
  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 +```
92 ''', 289 ''',
93 ); 290 );
94 File? file; 291 File? file;
@@ -143,7 +340,8 @@ $$ @@ -143,7 +340,8 @@ $$
143 ? Theme.of(context).colorScheme.onSurfaceVariant 340 ? Theme.of(context).colorScheme.onSurfaceVariant
144 : Theme.of(context) 341 : Theme.of(context)
145 .colorScheme 342 .colorScheme
146 - .onSurface, 343 + .onSurface
  344 + .withValues(alpha: 0.38),
147 ), 345 ),
148 ), 346 ),
149 IconButton( 347 IconButton(
@@ -241,7 +439,8 @@ $$ @@ -241,7 +439,8 @@ $$
241 border: Border.all( 439 border: Border.all(
242 color: Theme.of(context) 440 color: Theme.of(context)
243 .colorScheme 441 .colorScheme
244 - .secondary, 442 + .secondary
  443 + .withValues(alpha: 0.5),
245 width: 1, 444 width: 1,
246 ), 445 ),
247 ), 446 ),
@@ -387,6 +586,40 @@ $$ @@ -387,6 +586,40 @@ $$
387 ), 586 ),
388 ); 587 );
389 }, 588 },
  589 + components: [
  590 + CodeBlockMd(),
  591 + NewLines(),
  592 + BlockQuote(),
  593 + ImageMd(),
  594 + ATagMd(),
  595 + TableMd(),
  596 + HTag(),
  597 + UnOrderedList(),
  598 + OrderedList(),
  599 + RadioButtonMd(),
  600 + CheckBoxMd(),
  601 + HrLine(),
  602 + StrikeMd(),
  603 + BoldMd(),
  604 + ItalicMd(),
  605 + LatexMath(),
  606 + LatexMathMultiLine(),
  607 + HighlightedText(),
  608 + SourceTag(),
  609 + IndentMd(),
  610 + ],
  611 + inlineComponents: [
  612 + ImageMd(),
  613 + ATagMd(),
  614 + TableMd(),
  615 + StrikeMd(),
  616 + BoldMd(),
  617 + ItalicMd(),
  618 + LatexMath(),
  619 + LatexMathMultiLine(),
  620 + HighlightedText(),
  621 + SourceTag(),
  622 + ],
390 // codeBuilder: (context, name, code, closed) { 623 // codeBuilder: (context, name, code, closed) {
391 // return Padding( 624 // return Padding(
392 // padding: const EdgeInsets.symmetric( 625 // padding: const EdgeInsets.symmetric(
@@ -12,6 +12,7 @@ class BlockQuoteWidget extends StatelessWidget { @@ -12,6 +12,7 @@ class BlockQuoteWidget extends StatelessWidget {
12 required this.child, 12 required this.child,
13 required this.direction, 13 required this.direction,
14 required this.color, 14 required this.color,
  15 + this.width = 3,
15 }); 16 });
16 17
17 /// The child widget to be indented. 18 /// The child widget to be indented.
@@ -23,29 +24,39 @@ class BlockQuoteWidget extends StatelessWidget { @@ -23,29 +24,39 @@ class BlockQuoteWidget extends StatelessWidget {
23 /// The color of the indent. 24 /// The color of the indent.
24 final Color color; 25 final Color color;
25 26
  27 + /// The width of the indent.
  28 + final double width;
  29 +
26 @override 30 @override
27 Widget build(BuildContext context) { 31 Widget build(BuildContext context) {
28 - return CustomPaint(  
29 - foregroundPainter: IndentPainter(color, direction),  
30 - child: child, 32 + return Row(
  33 + children: [
  34 + Flexible(
  35 + child: CustomPaint(
  36 + foregroundPainter: BlockQuotePainter(color, direction, width),
  37 + child: child,
  38 + ),
  39 + ),
  40 + ],
31 ); 41 );
32 } 42 }
33 } 43 }
34 44
35 /// A custom painter that draws an indent on a canvas. 45 /// A custom painter that draws an indent on a canvas.
36 /// 46 ///
37 -/// The [IndentPainter] class extends CustomPainter and is responsible for 47 +/// The [BlockQuotePainter] class extends CustomPainter and is responsible for
38 /// painting the indent on a canvas. It takes a [color] and [direction] parameter 48 /// painting the indent on a canvas. It takes a [color] and [direction] parameter
39 /// and uses them to draw an indent in the UI. 49 /// and uses them to draw an indent in the UI.
40 -class IndentPainter extends CustomPainter {  
41 - IndentPainter(this.color, this.direction); 50 +class BlockQuotePainter extends CustomPainter {
  51 + BlockQuotePainter(this.color, this.direction, this.width);
42 final Color color; 52 final Color color;
43 final TextDirection direction; 53 final TextDirection direction;
  54 + final double width;
44 @override 55 @override
45 void paint(Canvas canvas, Size size) { 56 void paint(Canvas canvas, Size size) {
46 var left = direction == TextDirection.ltr; 57 var left = direction == TextDirection.ltr;
47 - var start = left ? 0.0 : size.width - 4;  
48 - var rect = Rect.fromLTWH(start, 0, 4, size.height); 58 + var start = left ? 0.0 : size.width - width;
  59 + var rect = Rect.fromLTWH(start, 0, width, size.height);
49 var paint = Paint()..color = color; 60 var paint = Paint()..color = color;
50 canvas.drawRect(rect, paint); 61 canvas.drawRect(rect, paint);
51 } 62 }
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +import 'package:gpt_markdown/gpt_markdown.dart';
2 3
3 /// A builder function for the ordered list. 4 /// A builder function for the ordered list.
4 typedef OrderedListBuilder = 5 typedef OrderedListBuilder =
@@ -80,6 +81,8 @@ class GptMarkdownConfig { @@ -80,6 +81,8 @@ class GptMarkdownConfig {
80 this.imageBuilder, 81 this.imageBuilder,
81 this.maxLines, 82 this.maxLines,
82 this.overflow, 83 this.overflow,
  84 + this.components,
  85 + this.inlineComponents,
83 }); 86 });
84 87
85 /// The direction of the text. 88 /// The direction of the text.
@@ -133,6 +136,12 @@ class GptMarkdownConfig { @@ -133,6 +136,12 @@ class GptMarkdownConfig {
133 /// The image builder. 136 /// The image builder.
134 final ImageBuilder? imageBuilder; 137 final ImageBuilder? imageBuilder;
135 138
  139 + /// The list of components.
  140 + final List<MarkdownComponent>? components;
  141 +
  142 + /// The list of inline components.
  143 + final List<MarkdownComponent>? inlineComponents;
  144 +
136 /// A copy of the configuration with the specified parameters. 145 /// A copy of the configuration with the specified parameters.
137 GptMarkdownConfig copyWith({ 146 GptMarkdownConfig copyWith({
138 TextStyle? style, 147 TextStyle? style,
@@ -152,6 +161,8 @@ class GptMarkdownConfig { @@ -152,6 +161,8 @@ class GptMarkdownConfig {
152 final ImageBuilder? imageBuilder, 161 final ImageBuilder? imageBuilder,
153 final OrderedListBuilder? orderedListBuilder, 162 final OrderedListBuilder? orderedListBuilder,
154 final UnOrderedListBuilder? unOrderedListBuilder, 163 final UnOrderedListBuilder? unOrderedListBuilder,
  164 + final List<MarkdownComponent>? components,
  165 + final List<MarkdownComponent>? inlineComponents,
155 }) { 166 }) {
156 return GptMarkdownConfig( 167 return GptMarkdownConfig(
157 style: style ?? this.style, 168 style: style ?? this.style,
@@ -171,6 +182,8 @@ class GptMarkdownConfig { @@ -171,6 +182,8 @@ class GptMarkdownConfig {
171 imageBuilder: imageBuilder ?? this.imageBuilder, 182 imageBuilder: imageBuilder ?? this.imageBuilder,
172 orderedListBuilder: orderedListBuilder ?? this.orderedListBuilder, 183 orderedListBuilder: orderedListBuilder ?? this.orderedListBuilder,
173 unOrderedListBuilder: unOrderedListBuilder ?? this.unOrderedListBuilder, 184 unOrderedListBuilder: unOrderedListBuilder ?? this.unOrderedListBuilder,
  185 + components: components ?? this.components,
  186 + inlineComponents: inlineComponents ?? this.inlineComponents,
174 ); 187 );
175 } 188 }
176 189
@@ -40,6 +40,8 @@ class GptMarkdown extends StatelessWidget { @@ -40,6 +40,8 @@ class GptMarkdown extends StatelessWidget {
40 this.overflow, 40 this.overflow,
41 this.orderedListBuilder, 41 this.orderedListBuilder,
42 this.unOrderedListBuilder, 42 this.unOrderedListBuilder,
  43 + this.components,
  44 + this.inlineComponents,
43 }); 45 });
44 46
45 /// The direction of the text. 47 /// The direction of the text.
@@ -94,16 +96,60 @@ class GptMarkdown extends StatelessWidget { @@ -94,16 +96,60 @@ class GptMarkdown extends StatelessWidget {
94 /// The unordered list builder. 96 /// The unordered list builder.
95 final UnOrderedListBuilder? unOrderedListBuilder; 97 final UnOrderedListBuilder? unOrderedListBuilder;
96 98
  99 + /// The list of components.
  100 + /// ```dart
  101 + /// List<MarkdownComponent> components = [
  102 + /// CodeBlockMd(),
  103 + /// NewLines(),
  104 + /// BlockQuote(),
  105 + /// ImageMd(),
  106 + /// ATagMd(),
  107 + /// TableMd(),
  108 + /// HTag(),
  109 + /// UnOrderedList(),
  110 + /// OrderedList(),
  111 + /// RadioButtonMd(),
  112 + /// CheckBoxMd(),
  113 + /// HrLine(),
  114 + /// StrikeMd(),
  115 + /// BoldMd(),
  116 + /// ItalicMd(),
  117 + /// LatexMath(),
  118 + /// LatexMathMultiLine(),
  119 + /// HighlightedText(),
  120 + /// SourceTag(),
  121 + /// IndentMd(),
  122 + /// ];
  123 + /// ```
  124 + final List<MarkdownComponent>? components;
  125 +
  126 + /// The list of inline components.
  127 + /// ```dart
  128 + /// List<MarkdownComponent> inlineComponents = [
  129 + /// ImageMd(),
  130 + /// ATagMd(),
  131 + /// TableMd(),
  132 + /// StrikeMd(),
  133 + /// BoldMd(),
  134 + /// ItalicMd(),
  135 + /// LatexMath(),
  136 + /// LatexMathMultiLine(),
  137 + /// HighlightedText(),
  138 + /// SourceTag(),
  139 + /// ];
  140 + /// ```
  141 + final List<MarkdownComponent>? inlineComponents;
  142 +
97 /// A method to remove extra lines inside block LaTeX. 143 /// 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 - } 144 + // String _removeExtraLinesInsideBlockLatex(String text) {
  145 + // return text.replaceAllMapped(
  146 + // RegExp(r"\\\[(.*?)\\\]", multiLine: true, dotAll: true),
  147 + // (match) {
  148 + // String content = match[0] ?? "";
  149 + // return content.replaceAllMapped(RegExp(r"\n[\n\ ]+"), (match) => "\n");
  150 + // },
  151 + // );
  152 + // }
107 153
108 @override 154 @override
109 Widget build(BuildContext context) { 155 Widget build(BuildContext context) {
@@ -130,7 +176,7 @@ class GptMarkdown extends StatelessWidget { @@ -130,7 +176,7 @@ class GptMarkdown extends StatelessWidget {
130 }, 176 },
131 ); 177 );
132 } 178 }
133 - tex = _removeExtraLinesInsideBlockLatex(tex); 179 + // tex = _removeExtraLinesInsideBlockLatex(tex);
134 return ClipRRect( 180 return ClipRRect(
135 child: MdWidget( 181 child: MdWidget(
136 tex, 182 tex,
@@ -153,6 +199,8 @@ class GptMarkdown extends StatelessWidget { @@ -153,6 +199,8 @@ class GptMarkdown extends StatelessWidget {
153 imageBuilder: imageBuilder, 199 imageBuilder: imageBuilder,
154 orderedListBuilder: orderedListBuilder, 200 orderedListBuilder: orderedListBuilder,
155 unOrderedListBuilder: unOrderedListBuilder, 201 unOrderedListBuilder: unOrderedListBuilder,
  202 + components: components,
  203 + inlineComponents: inlineComponents,
156 ), 204 ),
157 ), 205 ),
158 ); 206 );
@@ -47,8 +47,8 @@ abstract class MarkdownComponent { @@ -47,8 +47,8 @@ abstract class MarkdownComponent {
47 ) { 47 ) {
48 var components = 48 var components =
49 includeGlobalComponents 49 includeGlobalComponents
50 - ? MarkdownComponent.components  
51 - : MarkdownComponent.inlineComponents; 50 + ? config.components ?? MarkdownComponent.components
  51 + : config.inlineComponents ?? MarkdownComponent.inlineComponents;
52 List<InlineSpan> spans = []; 52 List<InlineSpan> spans = [];
53 Iterable<String> regexes = components.map<String>((e) => e.exp.pattern); 53 Iterable<String> regexes = components.map<String>((e) => e.exp.pattern);
54 final combinedRegex = RegExp( 54 final combinedRegex = RegExp(
@@ -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: [Flexible(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(
@@ -182,7 +165,7 @@ class IndentMd extends BlockMd { @@ -182,7 +165,7 @@ class IndentMd extends BlockMd {
182 textDirection: config.textDirection, 165 textDirection: config.textDirection,
183 child: Row( 166 child: Row(
184 children: [ 167 children: [
185 - Expanded( 168 + Flexible(
186 child: config.getRich( 169 child: config.getRich(
187 TextSpan( 170 TextSpan(
188 children: MarkdownComponent.generate( 171 children: MarkdownComponent.generate(
@@ -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
@@ -339,7 +322,11 @@ class BlockQuote extends InlineMd { @@ -339,7 +322,11 @@ class BlockQuote extends InlineMd {
339 @override 322 @override
340 RegExp get exp => 323 RegExp get exp =>
341 // RegExp(r"(?<=\n\n)(\ +)(.+?)(?=\n\n)", dotAll: true, multiLine: true); 324 // RegExp(r"(?<=\n\n)(\ +)(.+?)(?=\n\n)", dotAll: true, multiLine: true);
342 - RegExp(r"^>([^\n]+)$", dotAll: true, multiLine: true); 325 + RegExp(
  326 + r"(?:(?:^)\ *>[^\n]+)(?:(?:\n)\ *>[^\n]+)*",
  327 + dotAll: true,
  328 + multiLine: true,
  329 + );
343 330
344 @override 331 @override
345 InlineSpan span( 332 InlineSpan span(
@@ -348,9 +335,20 @@ class BlockQuote extends InlineMd { @@ -348,9 +335,20 @@ class BlockQuote extends InlineMd {
348 final GptMarkdownConfig config, 335 final GptMarkdownConfig config,
349 ) { 336 ) {
350 var match = exp.firstMatch(text); 337 var match = exp.firstMatch(text);
351 - var data = "${match?[1]}".trim();  
352 - // data = data.replaceAll(RegExp(r'\n\ {' '$spaces' '}'), '\n').trim();  
353 - data = data.trim(); 338 + var dataBuilder = StringBuffer();
  339 + var m = match?[0] ?? '';
  340 + for (var each in m.split('\n')) {
  341 + if (each.startsWith(RegExp(r'\ *>'))) {
  342 + var subString = each.trimLeft().substring(1);
  343 + if (subString.startsWith(' ')) {
  344 + subString = subString.substring(1);
  345 + }
  346 + dataBuilder.writeln(subString);
  347 + } else {
  348 + dataBuilder.writeln(each);
  349 + }
  350 + }
  351 + var data = dataBuilder.toString().trim();
354 var child = TextSpan( 352 var child = TextSpan(
355 children: MarkdownComponent.generate(context, data, config, true), 353 children: MarkdownComponent.generate(context, data, config, true),
356 ); 354 );
@@ -364,8 +362,9 @@ class BlockQuote extends InlineMd { @@ -364,8 +362,9 @@ class BlockQuote extends InlineMd {
364 child: BlockQuoteWidget( 362 child: BlockQuoteWidget(
365 color: Theme.of(context).colorScheme.onSurfaceVariant, 363 color: Theme.of(context).colorScheme.onSurfaceVariant,
366 direction: config.textDirection, 364 direction: config.textDirection,
  365 + width: 3,
367 child: Padding( 366 child: Padding(
368 - padding: const EdgeInsetsDirectional.only(start: 10.0), 367 + padding: const EdgeInsetsDirectional.only(start: 8.0),
369 child: config.getRich(child), 368 child: config.getRich(child),
370 ), 369 ),
371 ), 370 ),
@@ -390,7 +389,7 @@ class UnOrderedList extends BlockMd { @@ -390,7 +389,7 @@ class UnOrderedList extends BlockMd {
390 ) { 389 ) {
391 var match = this.exp.firstMatch(text); 390 var match = this.exp.firstMatch(text);
392 391
393 - var child = MdWidget("${match?[1]?.trim()}", false, config: config); 392 + var child = MdWidget("${match?[1]?.trim()}", true, config: config);
394 393
395 return config.unOrderedListBuilder?.call( 394 return config.unOrderedListBuilder?.call(
396 context, 395 context,
@@ -428,7 +427,7 @@ class OrderedList extends BlockMd { @@ -428,7 +427,7 @@ class OrderedList extends BlockMd {
428 427
429 var no = "${match?[1]}"; 428 var no = "${match?[1]}";
430 429
431 - var child = MdWidget("${match?[2]?.trim()}", false, config: config); 430 + var child = MdWidget("${match?[2]?.trim()}", true, config: config);
432 return config.orderedListBuilder?.call( 431 return config.orderedListBuilder?.call(
433 context, 432 context,
434 no, 433 no,
@@ -582,7 +581,8 @@ class ItalicMd extends InlineMd { @@ -582,7 +581,8 @@ class ItalicMd extends InlineMd {
582 581
583 class LatexMathMultiLine extends BlockMd { 582 class LatexMathMultiLine extends BlockMd {
584 @override 583 @override
585 - String get expString => (r"\\\[(((?!\n\n).)*?)\\\]|(\\begin.*?\\end{.*?})"); 584 + String get expString => (r"\ *\\\[((?:.)*?)\\\]|(\ *\\begin.*?\\end{.*?})");
  585 + // (r"\ *\\\[((?:(?!\n\n\n).)*?)\\\]|(\\begin.*?\\end{.*?})");
586 @override 586 @override
587 RegExp get exp => RegExp(expString, dotAll: true, multiLine: true); 587 RegExp get exp => RegExp(expString, dotAll: true, multiLine: true);
588 588
@@ -593,7 +593,7 @@ class LatexMathMultiLine extends BlockMd { @@ -593,7 +593,7 @@ class LatexMathMultiLine extends BlockMd {
593 final GptMarkdownConfig config, 593 final GptMarkdownConfig config,
594 ) { 594 ) {
595 var p0 = exp.firstMatch(text.trim()); 595 var p0 = exp.firstMatch(text.trim());
596 - String mathText = p0?[1] ?? p0?[2] ?? ""; 596 + String mathText = p0?[1] ?? p0?[2] ?? '';
597 var workaround = config.latexWorkaround ?? (String tex) => tex; 597 var workaround = config.latexWorkaround ?? (String tex) => tex;
598 598
599 var builder = 599 var builder =
@@ -889,7 +889,7 @@ class ImageMd extends InlineMd { @@ -889,7 +889,7 @@ class ImageMd extends InlineMd {
889 class TableMd extends BlockMd { 889 class TableMd extends BlockMd {
890 @override 890 @override
891 String get expString => 891 String get expString =>
892 - (r"(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)$"); 892 + (r"(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?)\ *)(\n\ *(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?))\ *)+)$");
893 @override 893 @override
894 Widget build( 894 Widget build(
895 BuildContext context, 895 BuildContext context,
@@ -902,6 +902,7 @@ class TableMd extends BlockMd { @@ -902,6 +902,7 @@ class TableMd extends BlockMd {
902 .map<Map<int, String>>( 902 .map<Map<int, String>>(
903 (e) => 903 (e) =>
904 e 904 e
  905 + .trim()
905 .split('|') 906 .split('|')
906 .where((element) => element.isNotEmpty) 907 .where((element) => element.isNotEmpty)
907 .toList() 908 .toList()
@@ -955,7 +956,7 @@ class TableMd extends BlockMd { @@ -955,7 +956,7 @@ class TableMd extends BlockMd {
955 children: List.generate(maxCol, (index) { 956 children: List.generate(maxCol, (index) {
956 var e = entry.value; 957 var e = entry.value;
957 String data = e[index] ?? ""; 958 String data = e[index] ?? "";
958 - if (RegExp(r"^--+$").hasMatch(data.trim()) || 959 + if (RegExp(r"^:?--+:?$").hasMatch(data.trim()) ||
959 data.trim().isEmpty) { 960 data.trim().isEmpty) {
960 return const SizedBox(); 961 return const SizedBox();
961 } 962 }
@@ -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()),