saminsohag

new syntax added

  1 +## 1.0.6
  2 +
  3 +* `_italic_` and `>Indentation` syntax added.
  4 +* `linkBuilder` and `highlightBuilder` added `[f45132b](https://github.com/Infinitix-LLC/gpt_markdown/commit/f45132b2cd4b069d3e5703561deb5c7e51d3c560)`.
  5 +
1 ## 1.0.5 6 ## 1.0.5
2 7
3 * Fixed the order of inline and block latex in markdown. 8 * Fixed the order of inline and block latex in markdown.
@@ -269,22 +269,33 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex @@ -269,22 +269,33 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
269 ), 269 ),
270 highlightBuilder: (context, text, style) { 270 highlightBuilder: (context, text, style) {
271 return Container( 271 return Container(
272 - padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2), 272 + padding: const EdgeInsets.symmetric(
  273 + horizontal: 4, vertical: 2),
273 decoration: BoxDecoration( 274 decoration: BoxDecoration(
274 - color: Theme.of(context).colorScheme.secondaryContainer,  
275 - borderRadius: BorderRadius.circular(4), 275 + color: Theme.of(context)
  276 + .colorScheme
  277 + .secondaryContainer,
  278 + borderRadius:
  279 + BorderRadius.circular(4),
276 border: Border.all( 280 border: Border.all(
277 - color: Theme.of(context).colorScheme.secondary.withOpacity(0.5), 281 + color: Theme.of(context)
  282 + .colorScheme
  283 + .secondary
  284 + .withValues(alpha: 0.5),
278 width: 1, 285 width: 1,
279 ), 286 ),
280 ), 287 ),
281 child: Text( 288 child: Text(
282 text, 289 text,
283 style: TextStyle( 290 style: TextStyle(
284 - color: Theme.of(context).colorScheme.onSecondaryContainer, 291 + color: Theme.of(context)
  292 + .colorScheme
  293 + .onSecondaryContainer,
285 fontFamily: 'monospace', 294 fontFamily: 'monospace',
286 fontWeight: FontWeight.bold, 295 fontWeight: FontWeight.bold,
287 - fontSize: style.fontSize != null ? style.fontSize! * 0.9 : 13.5, 296 + fontSize: style.fontSize != null
  297 + ? style.fontSize! * 0.9
  298 + : 13.5,
288 height: style.height, 299 height: style.height,
289 ), 300 ),
290 ), 301 ),
@@ -400,21 +411,29 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex @@ -400,21 +411,29 @@ Markdown and LaTeX can be powerful tools for formatting text and mathematical ex
400 ), 411 ),
401 ); 412 );
402 }, 413 },
  414 + linkBuilder:
  415 + (context, label, path, style) {
  416 + //
  417 + return Text(path);
  418 + },
  419 + // codeBuilder: (context, name, code) {
  420 + // return Padding(
  421 + // padding: const EdgeInsets.symmetric(
  422 + // horizontal: 16),
  423 + // child: Text(
  424 + // code.trim(),
  425 + // style: TextStyle(
  426 + // fontFamily: 'JetBrains Mono',
  427 + // fontSize: 14,
  428 + // height: 1.5,
  429 + // color: Theme.of(context)
  430 + // .colorScheme
  431 + // .onSurface,
  432 + // ),
  433 + // ),
  434 + // );
  435 + // }
403 ); 436 );
404 - codeBuilder: (context, name, code) {  
405 - return Padding(  
406 - padding: const EdgeInsets.symmetric(horizontal: 16),  
407 - child: Text(  
408 - code.trim(),  
409 - style: TextStyle(  
410 - fontFamily: 'JetBrains Mono',  
411 - fontSize: 14,  
412 - height: 1.5,  
413 - color: Theme.of(context).colorScheme.onSurface,  
414 - ),  
415 - ),  
416 - );  
417 - };  
418 if (selectable) { 437 if (selectable) {
419 child = SelectionArea( 438 child = SelectionArea(
420 child: child, 439 child: child,
@@ -126,7 +126,7 @@ packages: @@ -126,7 +126,7 @@ packages:
126 path: ".." 126 path: ".."
127 relative: true 127 relative: true
128 source: path 128 source: path
129 - version: "1.0.5" 129 + version: "1.0.6"
130 http: 130 http:
131 dependency: transitive 131 dependency: transitive
132 description: 132 description:
  1 +import 'package:flutter/material.dart';
  2 +
  3 +class IndentWidget extends StatelessWidget {
  4 + const IndentWidget({
  5 + super.key,
  6 + required this.child,
  7 + required this.direction,
  8 + required this.color,
  9 + });
  10 + final Widget child;
  11 + final TextDirection direction;
  12 + final Color color;
  13 +
  14 + @override
  15 + Widget build(BuildContext context) {
  16 + return CustomPaint(
  17 + foregroundPainter: IndentPainter(color, direction),
  18 + child: child,
  19 + );
  20 + }
  21 +}
  22 +
  23 +class IndentPainter extends CustomPainter {
  24 + IndentPainter(this.color, this.direction);
  25 + final Color color;
  26 + final TextDirection direction;
  27 + @override
  28 + void paint(Canvas canvas, Size size) {
  29 + var left = direction == TextDirection.ltr;
  30 + var start = left ? 0.0 : size.width - 4;
  31 + var rect = Rect.fromLTWH(start, 0, 4, size.height);
  32 + var paint = Paint()..color = color;
  33 + canvas.drawRect(rect, paint);
  34 + }
  35 +
  36 + @override
  37 + bool shouldRepaint(covariant CustomPainter oldDelegate) {
  38 + return true;
  39 + }
  40 +}
@@ -34,8 +34,11 @@ class GptMarkdownConfig { @@ -34,8 +34,11 @@ class GptMarkdownConfig {
34 codeBuilder; 34 codeBuilder;
35 final int? maxLines; 35 final int? maxLines;
36 final TextOverflow? overflow; 36 final TextOverflow? overflow;
37 - final Widget Function(BuildContext context, String text, TextStyle style)? highlightBuilder;  
38 - final Widget Function(BuildContext context, String text, String url, TextStyle style)? linkBuilder; 37 + final Widget Function(BuildContext context, String text, TextStyle style)?
  38 + highlightBuilder;
  39 + final Widget Function(
  40 + BuildContext context, String text, String url, TextStyle style)?
  41 + linkBuilder;
39 42
40 GptMarkdownConfig copyWith({ 43 GptMarkdownConfig copyWith({
41 TextStyle? style, 44 TextStyle? style,
@@ -55,8 +58,11 @@ class GptMarkdownConfig { @@ -55,8 +58,11 @@ class GptMarkdownConfig {
55 codeBuilder, 58 codeBuilder,
56 final int? maxLines, 59 final int? maxLines,
57 final TextOverflow? overflow, 60 final TextOverflow? overflow,
58 - final Widget Function(BuildContext context, String text, TextStyle style)? highlightBuilder,  
59 - final Widget Function(BuildContext context, String text, String url, TextStyle style)? linkBuilder, 61 + final Widget Function(BuildContext context, String text, TextStyle style)?
  62 + highlightBuilder,
  63 + final Widget Function(
  64 + BuildContext context, String text, String url, TextStyle style)?
  65 + linkBuilder,
60 }) { 66 }) {
61 return GptMarkdownConfig( 67 return GptMarkdownConfig(
62 style: style ?? this.style, 68 style: style ?? this.style,
@@ -13,6 +13,7 @@ import 'package:gpt_markdown/custom_widgets/unordered_ordered_list.dart'; @@ -13,6 +13,7 @@ import 'package:gpt_markdown/custom_widgets/unordered_ordered_list.dart';
13 import 'dart:math'; 13 import 'dart:math';
14 14
15 import 'custom_widgets/code_field.dart'; 15 import 'custom_widgets/code_field.dart';
  16 +import 'custom_widgets/indent_widget.dart';
16 import 'custom_widgets/link_button.dart'; 17 import 'custom_widgets/link_button.dart';
17 18
18 part 'theme.dart'; 19 part 'theme.dart';
@@ -55,8 +56,11 @@ class GptMarkdown extends StatelessWidget { @@ -55,8 +56,11 @@ class GptMarkdown extends StatelessWidget {
55 final Widget Function(BuildContext context, String name, String code)? 56 final Widget Function(BuildContext context, String name, String code)?
56 codeBuilder; 57 codeBuilder;
57 final Widget Function(BuildContext, String, TextStyle)? sourceTagBuilder; 58 final Widget Function(BuildContext, String, TextStyle)? sourceTagBuilder;
58 - final Widget Function(BuildContext context, String text, TextStyle style)? highlightBuilder;  
59 - final Widget Function(BuildContext context, String text, String url, TextStyle style)? linkBuilder; 59 + final Widget Function(BuildContext context, String text, TextStyle style)?
  60 + highlightBuilder;
  61 + final Widget Function(
  62 + BuildContext context, String text, String url, TextStyle style)?
  63 + linkBuilder;
60 64
61 @override 65 @override
62 Widget build(BuildContext context) { 66 Widget build(BuildContext context) {
@@ -2,28 +2,28 @@ part of 'gpt_markdown.dart'; @@ -2,28 +2,28 @@ 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 = [  
6 - CodeBlockMd(),  
7 - NewLines(),  
8 - // IndentMd(),  
9 - ImageMd(),  
10 - TableMd(),  
11 - HTag(),  
12 - UnOrderedList(),  
13 - OrderedList(),  
14 - RadioButtonMd(),  
15 - CheckBoxMd(),  
16 - HrLine(),  
17 - LatexMath(),  
18 - LatexMathMultiLine(),  
19 - ImageMd(),  
20 - HighlightedText(),  
21 - StrikeMd(),  
22 - BoldMd(),  
23 - ItalicMd(),  
24 - ATagMd(),  
25 - SourceTag(),  
26 - ]; 5 + static List<MarkdownComponent> get components => [
  6 + CodeBlockMd(),
  7 + NewLines(),
  8 + IndentMd(),
  9 + ImageMd(),
  10 + TableMd(),
  11 + HTag(),
  12 + UnOrderedList(),
  13 + OrderedList(),
  14 + RadioButtonMd(),
  15 + CheckBoxMd(),
  16 + HrLine(),
  17 + LatexMath(),
  18 + LatexMathMultiLine(),
  19 + ImageMd(),
  20 + HighlightedText(),
  21 + StrikeMd(),
  22 + BoldMd(),
  23 + ItalicMd(),
  24 + ATagMd(),
  25 + SourceTag(),
  26 + ];
27 27
28 /// Generate widget for markdown widget 28 /// Generate widget for markdown widget
29 static List<InlineSpan> generate( 29 static List<InlineSpan> generate(
@@ -311,7 +311,7 @@ class IndentMd extends InlineMd { @@ -311,7 +311,7 @@ class IndentMd extends InlineMd {
311 @override 311 @override
312 RegExp get exp => 312 RegExp get exp =>
313 // RegExp(r"(?<=\n\n)(\ +)(.+?)(?=\n\n)", dotAll: true, multiLine: true); 313 // RegExp(r"(?<=\n\n)(\ +)(.+?)(?=\n\n)", dotAll: true, multiLine: true);
314 - RegExp(r"(?:\n\n+)^(\ *)(.+?)$(?:\n\n+)", dotAll: true, multiLine: true); 314 + RegExp(r"^>([^\n]+)$", dotAll: true, multiLine: true);
315 315
316 @override 316 @override
317 InlineSpan span( 317 InlineSpan span(
@@ -320,8 +320,7 @@ class IndentMd extends InlineMd { @@ -320,8 +320,7 @@ class IndentMd extends InlineMd {
320 final GptMarkdownConfig config, 320 final GptMarkdownConfig config,
321 ) { 321 ) {
322 var match = exp.firstMatch(text); 322 var match = exp.firstMatch(text);
323 - int spaces = (match?[1] ?? "").length;  
324 - var data = "${match?[2]}".trim(); 323 + var data = "${match?[1]}".trim();
325 // data = data.replaceAll(RegExp(r'\n\ {' '$spaces' '}'), '\n').trim(); 324 // data = data.replaceAll(RegExp(r'\n\ {' '$spaces' '}'), '\n').trim();
326 data = data.trim(); 325 data = data.trim();
327 var child = TextSpan( 326 var child = TextSpan(
@@ -331,23 +330,21 @@ class IndentMd extends InlineMd { @@ -331,23 +330,21 @@ class IndentMd extends InlineMd {
331 config, 330 config,
332 ), 331 ),
333 ); 332 );
334 - var leftPadding = 20.0;  
335 - if (spaces < 4) {  
336 - leftPadding = 0;  
337 - }  
338 - var padding = config.style?.fontSize ?? 16.0;  
339 return TextSpan( 333 return TextSpan(
340 children: [ 334 children: [
341 WidgetSpan( 335 WidgetSpan(
342 - child: Padding(  
343 - padding: EdgeInsets.symmetric(vertical: padding),  
344 - child: Row(  
345 - children: [  
346 - SizedBox(  
347 - width: leftPadding, 336 + child: Directionality(
  337 + textDirection: config.textDirection,
  338 + child: Padding(
  339 + padding: const EdgeInsets.symmetric(vertical: 2),
  340 + child: IndentWidget(
  341 + color: Theme.of(context).colorScheme.onSurfaceVariant,
  342 + direction: config.textDirection,
  343 + child: Padding(
  344 + padding: const EdgeInsetsDirectional.only(start: 10.0),
  345 + child: Expanded(child: config.getRich(child)),
348 ), 346 ),
349 - Expanded(child: config.getRich(child)),  
350 - ], 347 + ),
351 ), 348 ),
352 ), 349 ),
353 ), 350 ),
@@ -517,7 +514,8 @@ class StrikeMd extends InlineMd { @@ -517,7 +514,8 @@ class StrikeMd extends InlineMd {
517 class ItalicMd extends InlineMd { 514 class ItalicMd extends InlineMd {
518 @override 515 @override
519 RegExp get exp => 516 RegExp get exp =>
520 - RegExp(r"(?<!\*)\*(?<!\s)(.+?)(?<!\s)\*(?!\*)", dotAll: true); 517 + RegExp(r"(?<!\*)\*(?<!\s)(.+?)(?<!\s)\*(?!\*)|\_(?<!\s)(.+?)(?<!\s)\_",
  518 + dotAll: true);
521 519
522 @override 520 @override
523 InlineSpan span( 521 InlineSpan span(
@@ -526,13 +524,14 @@ class ItalicMd extends InlineMd { @@ -526,13 +524,14 @@ class ItalicMd extends InlineMd {
526 final GptMarkdownConfig config, 524 final GptMarkdownConfig config,
527 ) { 525 ) {
528 var match = exp.firstMatch(text.trim()); 526 var match = exp.firstMatch(text.trim());
  527 + var data = match?[1] ?? match?[2];
529 var conf = config.copyWith( 528 var conf = config.copyWith(
530 style: (config.style ?? const TextStyle()) 529 style: (config.style ?? const TextStyle())
531 .copyWith(fontStyle: FontStyle.italic)); 530 .copyWith(fontStyle: FontStyle.italic));
532 return TextSpan( 531 return TextSpan(
533 children: MarkdownComponent.generate( 532 children: MarkdownComponent.generate(
534 context, 533 context,
535 - "${match?[1]}", 534 + "$data",
536 conf, 535 conf,
537 ), 536 ),
538 style: conf.style, 537 style: conf.style,
@@ -733,10 +732,10 @@ class ATagMd extends InlineMd { @@ -733,10 +732,10 @@ class ATagMd extends InlineMd {
733 if (match?[1] == null && match?[2] == null) { 732 if (match?[1] == null && match?[2] == null) {
734 return const TextSpan(); 733 return const TextSpan();
735 } 734 }
736 - 735 +
737 final linkText = match?[1] ?? ""; 736 final linkText = match?[1] ?? "";
738 final url = match?[2] ?? ""; 737 final url = match?[2] ?? "";
739 - 738 +
740 // Use custom builder if provided 739 // Use custom builder if provided
741 if (config.linkBuilder != null) { 740 if (config.linkBuilder != null) {
742 return WidgetSpan( 741 return WidgetSpan(
@@ -924,9 +923,8 @@ class CodeBlockMd extends BlockMd { @@ -924,9 +923,8 @@ class CodeBlockMd extends BlockMd {
924 String codes = this.exp.firstMatch(text)?[2] ?? ""; 923 String codes = this.exp.firstMatch(text)?[2] ?? "";
925 String name = this.exp.firstMatch(text)?[1] ?? ""; 924 String name = this.exp.firstMatch(text)?[1] ?? "";
926 codes = codes.replaceAll(r"```", "").trim(); 925 codes = codes.replaceAll(r"```", "").trim();
927 -  
928 - return config.codeBuilder != null  
929 - ? config.codeBuilder!(context, name, codes)  
930 - : CodeField(name: name, codes: codes); 926 +
  927 + return config.codeBuilder?.call(context, name, codes) ??
  928 + CodeField(name: name, codes: codes);
931 } 929 }
932 } 930 }
1 name: gpt_markdown 1 name: gpt_markdown
2 description: "Powerful Markdown & LaTeX Renderer for Flutter: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more." 2 description: "Powerful Markdown & LaTeX Renderer for Flutter: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more."
3 -version: 1.0.5 3 +version: 1.0.6
4 homepage: https://github.com/Infinitix-LLC/gpt_markdown 4 homepage: https://github.com/Infinitix-LLC/gpt_markdown
5 5
6 environment: 6 environment: