gpt_markdown.dart
3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import 'package:flutter/material.dart';
import 'package:gpt_markdown/custom_widgets/markdow_config.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_math_fork/flutter_math.dart';
import 'package:gpt_markdown/custom_widgets/custom_divider.dart';
import 'package:gpt_markdown/custom_widgets/custom_error_image.dart';
import 'package:gpt_markdown/custom_widgets/custom_rb_cb.dart';
import 'package:gpt_markdown/custom_widgets/selectable_adapter.dart';
import 'package:gpt_markdown/custom_widgets/unordered_ordered_list.dart';
import 'dart:math';
import 'custom_widgets/code_field.dart';
import 'custom_widgets/indent_widget.dart';
import 'custom_widgets/link_button.dart';
part 'theme.dart';
part 'markdown_component.dart';
part 'md_widget.dart';
/// This widget create a full markdown widget as a column view.
class GptMarkdown extends StatelessWidget {
const GptMarkdown(
this.data, {
super.key,
this.style,
this.followLinkColor = false,
this.textDirection = TextDirection.ltr,
this.latexWorkaround,
this.textAlign,
this.textScaler,
this.onLinkTab,
this.latexBuilder,
this.codeBuilder,
this.sourceTagBuilder,
this.highlightBuilder,
this.linkBuilder,
this.maxLines,
this.overflow,
});
final TextDirection textDirection;
final String data;
final TextStyle? style;
final TextAlign? textAlign;
final TextScaler? textScaler;
final void Function(String url, String title)? onLinkTab;
final String Function(String tex)? latexWorkaround;
final int? maxLines;
final TextOverflow? overflow;
final Widget Function(
BuildContext context,
String tex,
TextStyle style,
bool inline,
)?
latexBuilder;
final bool followLinkColor;
final Widget Function(
BuildContext context,
String name,
String code,
bool closed,
)?
codeBuilder;
final Widget Function(BuildContext, String, TextStyle)? sourceTagBuilder;
final Widget Function(BuildContext context, String text, TextStyle style)?
highlightBuilder;
final Widget Function(
BuildContext context,
String text,
String url,
TextStyle style,
)?
linkBuilder;
String _removeExtraLinesInsideBlockLatex(String text) {
return text.replaceAllMapped(
RegExp(r"\\\[(.*?)\\\]", multiLine: true, dotAll: true),
(match) {
String content = match[0] ?? "";
return content.replaceAllMapped(RegExp(r"\n[\n\ ]+"), (match) => "\n");
},
);
}
@override
Widget build(BuildContext context) {
String tex = data.trim();
tex = tex.replaceAllMapped(
RegExp(r"(?<!\\)\$\$(.*?)(?<!\\)\$\$", dotAll: true),
(match) => "\\[${match[1] ?? ""}\\]",
);
if (!tex.contains(r"\(")) {
tex = tex.replaceAllMapped(
RegExp(r"(?<!\\)\$(.*?)(?<!\\)\$"),
(match) => "\\(${match[1] ?? ""}\\)",
);
tex = tex.splitMapJoin(
RegExp(r"\[.*?\]|\(.*?\)"),
onNonMatch: (p0) {
return p0.replaceAll("\\\$", "\$");
},
);
}
tex = _removeExtraLinesInsideBlockLatex(tex);
return ClipRRect(
child: MdWidget(
tex,
config: GptMarkdownConfig(
textDirection: textDirection,
style: style,
onLinkTab: onLinkTab,
textAlign: textAlign,
textScaler: textScaler,
followLinkColor: followLinkColor,
latexWorkaround: latexWorkaround,
latexBuilder: latexBuilder,
codeBuilder: codeBuilder,
maxLines: maxLines,
overflow: overflow,
sourceTagBuilder: sourceTagBuilder,
highlightBuilder: highlightBuilder,
linkBuilder: linkBuilder,
),
),
);
}
}