Skip to content

Commit 92952b1

Browse files
committed
up
1 parent 271b81a commit 92952b1

File tree

7 files changed

+151
-170
lines changed

7 files changed

+151
-170
lines changed

lib/widgets/markdown/widgets/artifact.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import 'package:markdown_widget/markdown_widget.dart';
44
import 'think.dart';
55
import 'package:chatmcp/utils/event_bus.dart';
66

7+
import 'tag.dart';
8+
79
SpanNodeGeneratorWithTag artifactAntThinkingGenerator =
810
SpanNodeGeneratorWithTag(
911
tag: _artifactAntThinkingTag,
@@ -12,12 +14,12 @@ SpanNodeGeneratorWithTag artifactAntThinkingGenerator =
1214

1315
const _artifactAntThinkingTag = 'antThinking';
1416

15-
class ArtifactAntThinkingInlineSyntax extends ThinkInlineSyntax {
17+
class ArtifactAntThinkingInlineSyntax extends TagInlineSyntax {
1618
static const tagName = _artifactAntThinkingTag;
1719
ArtifactAntThinkingInlineSyntax() : super(tag: tagName, caseSensitive: false);
1820
}
1921

20-
class ArtifactAntThinkingBlockSyntax extends ThinkBlockSyntax {
22+
class ArtifactAntThinkingBlockSyntax extends TagBlockSyntax {
2123
static const tagName = _artifactAntThinkingTag;
2224
ArtifactAntThinkingBlockSyntax() : super(tag: tagName);
2325
}
@@ -52,12 +54,12 @@ SpanNodeGeneratorWithTag artifactAntArtifactGenerator =
5254

5355
const _artifactAntArtifactTag = 'antArtifact';
5456

55-
class ArtifactAntArtifactInlineSyntax extends ThinkInlineSyntax {
57+
class ArtifactAntArtifactInlineSyntax extends TagInlineSyntax {
5658
static const tagName = _artifactAntArtifactTag;
5759
ArtifactAntArtifactInlineSyntax() : super(tag: tagName, caseSensitive: false);
5860
}
5961

60-
class ArtifactAntArtifactBlockSyntax extends ThinkBlockSyntax {
62+
class ArtifactAntArtifactBlockSyntax extends TagBlockSyntax {
6163
static const tagName = _artifactAntArtifactTag;
6264
ArtifactAntArtifactBlockSyntax() : super(tag: tagName);
6365
}

lib/widgets/markdown/widgets/tag.dart

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:markdown/markdown.dart' as md;
3+
4+
// 属性匹配正则表达式
5+
final attributeRegex =
6+
RegExp(r'''([\w-]+)\s*=\s*(?:["']([^"'>]+)["']|([^\s>"']+))''');
7+
8+
class TagInlineSyntax extends md.InlineSyntax {
9+
final String tag;
10+
11+
TagInlineSyntax({required this.tag, bool caseSensitive = false})
12+
: super(_getPattern(tag), caseSensitive: caseSensitive);
13+
14+
static String _getPattern(String tag) =>
15+
r'<' + tag + r'\s*([^>]*)>([^<]*)(?:</' + tag + r'\s*([^>]*)>)?';
16+
17+
Map<String, String> _parseAttributes(String attributeString) {
18+
final attributes = <String, String>{};
19+
final matches = attributeRegex.allMatches(attributeString);
20+
21+
for (final match in matches) {
22+
if (match.groupCount >= 1) {
23+
final key = match.group(1) ?? '';
24+
// 值可能在引号组或无引号组中
25+
final value = match.group(2) ?? match.group(3) ?? '';
26+
if (key.isNotEmpty) {
27+
attributes[key] = value;
28+
}
29+
}
30+
}
31+
return attributes;
32+
}
33+
34+
@override
35+
bool onMatch(md.InlineParser parser, Match match) {
36+
final openingAttributes = _parseAttributes(match[1] ?? '');
37+
final content = match[2]!.trim();
38+
final closingAttributes =
39+
match[3] != null ? _parseAttributes(match[3]!) : <String, String>{};
40+
41+
final element = md.Element(tag, [md.Text(content)]);
42+
43+
// 合并开始和结束标签的属性
44+
element.attributes.addAll(openingAttributes);
45+
element.attributes.addAll(closingAttributes);
46+
47+
element.attributes['content'] = content;
48+
element.attributes['isInline'] = 'true';
49+
element.attributes['closed'] = match[3] != null ? 'true' : 'false';
50+
51+
parser.addNode(element);
52+
return true;
53+
}
54+
}
55+
56+
class TagBlockSyntax extends md.BlockSyntax {
57+
final String tag;
58+
59+
TagBlockSyntax({required this.tag});
60+
61+
@protected
62+
RegExp get startPattern => RegExp(r'^<' + tag + r'\s*([^>]*)>$');
63+
64+
@protected
65+
RegExp get endPattern => RegExp(r'^</' + tag + r'\s*([^>]*)>$');
66+
67+
@override
68+
RegExp get pattern => startPattern;
69+
70+
Map<String, String> _parseAttributes(String attributeString) {
71+
final attributes = <String, String>{};
72+
final matches = attributeRegex.allMatches(attributeString);
73+
74+
for (final match in matches) {
75+
if (match.groupCount >= 1) {
76+
final key = match.group(1) ?? '';
77+
// 值可能在引号组或无引号组中
78+
final value = match.group(2) ?? match.group(3) ?? '';
79+
if (key.isNotEmpty) {
80+
attributes[key] = value;
81+
}
82+
}
83+
}
84+
return attributes;
85+
}
86+
87+
@override
88+
bool canParse(md.BlockParser parser) {
89+
final match = startPattern.firstMatch(parser.current.content);
90+
return match != null;
91+
}
92+
93+
@override
94+
md.Node parse(md.BlockParser parser) {
95+
final startMatch = startPattern.firstMatch(parser.current.content);
96+
final openingAttributes = startMatch != null
97+
? _parseAttributes(startMatch[1] ?? '')
98+
: <String, String>{};
99+
100+
final lines = <String>[];
101+
parser.advance(); // Skip the opening tag
102+
103+
bool isClosed = false;
104+
Map<String, String> closingAttributes = {};
105+
106+
while (!parser.isDone) {
107+
final line = parser.current.content;
108+
final endMatch = endPattern.firstMatch(line);
109+
if (endMatch != null) {
110+
isClosed = true;
111+
closingAttributes = _parseAttributes(endMatch[1] ?? '');
112+
parser.advance();
113+
break;
114+
}
115+
lines.add(line);
116+
parser.advance();
117+
}
118+
119+
final content = lines.join('\n');
120+
md.Element el = md.Element.text(tag, content);
121+
122+
// 合并开始和结束标签的属性
123+
el.attributes.addAll(openingAttributes);
124+
el.attributes.addAll(closingAttributes);
125+
126+
el.attributes['content'] = content;
127+
el.attributes['isInline'] = 'false';
128+
el.attributes['closed'] = isClosed ? 'true' : 'false';
129+
return el;
130+
}
131+
}

lib/widgets/markdown/widgets/think.dart

Lines changed: 5 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,16 @@
11
import 'package:flutter/material.dart';
2-
import 'package:markdown/markdown.dart' as md;
32

43
import 'package:markdown_widget/markdown_widget.dart';
54
import 'package:chatmcp/utils/color.dart';
65
import '../markit_widget.dart';
6+
import 'tag.dart';
77

8-
// 属性匹配正则表达式
9-
final attributeRegex =
10-
RegExp(r'''([\w-]+)\s*=\s*(?:["']([^"'>]+)["']|([^\s>"']+))''');
11-
12-
class ThinkInlineSyntax extends md.InlineSyntax {
13-
static const defaultTagName = 'think';
14-
final String tag;
15-
16-
ThinkInlineSyntax({String? tag, bool caseSensitive = false})
17-
: tag = tag ?? defaultTagName,
18-
super(_getPattern(tag ?? defaultTagName), caseSensitive: caseSensitive);
19-
20-
static String _getPattern(String tag) =>
21-
r'<' + tag + r'\s*([^>]*)>([^<]*)(?:</' + tag + r'\s*([^>]*)>)?';
22-
23-
Map<String, String> _parseAttributes(String attributeString) {
24-
final attributes = <String, String>{};
25-
final matches = attributeRegex.allMatches(attributeString);
26-
27-
for (final match in matches) {
28-
if (match.groupCount >= 1) {
29-
final key = match.group(1) ?? '';
30-
// 值可能在引号组或无引号组中
31-
final value = match.group(2) ?? match.group(3) ?? '';
32-
if (key.isNotEmpty) {
33-
attributes[key] = value;
34-
}
35-
}
36-
}
37-
return attributes;
38-
}
39-
40-
@override
41-
bool onMatch(md.InlineParser parser, Match match) {
42-
final openingAttributes = _parseAttributes(match[1] ?? '');
43-
final content = match[2]!.trim();
44-
final closingAttributes =
45-
match[3] != null ? _parseAttributes(match[3]!) : <String, String>{};
46-
47-
final element = md.Element(tag, [md.Text(content)]);
48-
49-
// 合并开始和结束标签的属性
50-
element.attributes.addAll(openingAttributes);
51-
element.attributes.addAll(closingAttributes);
52-
53-
element.attributes['content'] = content;
54-
element.attributes['isInline'] = 'true';
55-
element.attributes['closed'] = match[3] != null ? 'true' : 'false';
56-
57-
parser.addNode(element);
58-
return true;
59-
}
8+
class ThinkInlineSyntax extends TagInlineSyntax {
9+
ThinkInlineSyntax() : super(tag: "think");
6010
}
6111

62-
class ThinkBlockSyntax extends md.BlockSyntax {
63-
static const defaultTagName = 'think';
64-
final String tag;
65-
66-
ThinkBlockSyntax({String? tag}) : tag = tag ?? defaultTagName;
67-
68-
@protected
69-
RegExp get startPattern => RegExp(r'^<' + tag + r'\s*([^>]*)>');
70-
71-
@protected
72-
RegExp get endPattern => RegExp(r'^</' + tag + r'\s*([^>]*)>$');
73-
74-
@override
75-
RegExp get pattern => startPattern;
76-
77-
Map<String, String> _parseAttributes(String attributeString) {
78-
final attributes = <String, String>{};
79-
final matches = attributeRegex.allMatches(attributeString);
80-
81-
for (final match in matches) {
82-
if (match.groupCount >= 1) {
83-
final key = match.group(1) ?? '';
84-
// 值可能在引号组或无引号组中
85-
final value = match.group(2) ?? match.group(3) ?? '';
86-
if (key.isNotEmpty) {
87-
attributes[key] = value;
88-
}
89-
}
90-
}
91-
return attributes;
92-
}
93-
94-
@override
95-
bool canParse(md.BlockParser parser) {
96-
final match = startPattern.firstMatch(parser.current.content);
97-
return match != null;
98-
}
99-
100-
@override
101-
md.Node parse(md.BlockParser parser) {
102-
final startMatch = startPattern.firstMatch(parser.current.content);
103-
final openingAttributes = startMatch != null
104-
? _parseAttributes(startMatch[1] ?? '')
105-
: <String, String>{};
106-
107-
final lines = <String>[];
108-
parser.advance(); // Skip the opening tag
109-
110-
bool isClosed = false;
111-
Map<String, String> closingAttributes = {};
112-
113-
while (!parser.isDone) {
114-
final line = parser.current.content;
115-
final endMatch = endPattern.firstMatch(line);
116-
if (endMatch != null) {
117-
isClosed = true;
118-
closingAttributes = _parseAttributes(endMatch[1] ?? '');
119-
parser.advance();
120-
break;
121-
}
122-
lines.add(line);
123-
parser.advance();
124-
}
125-
126-
final content = lines.join('\n');
127-
md.Element el = md.Element.text(tag, content);
128-
129-
// 合并开始和结束标签的属性
130-
el.attributes.addAll(openingAttributes);
131-
el.attributes.addAll(closingAttributes);
132-
133-
el.attributes['content'] = content;
134-
el.attributes['isInline'] = 'false';
135-
el.attributes['closed'] = isClosed ? 'true' : 'false';
136-
return el;
137-
}
12+
class ThinkBlockSyntax extends TagBlockSyntax {
13+
ThinkBlockSyntax() : super(tag: "think");
13814
}
13915

14016
SpanNodeGeneratorWithTag thinkGenerator = SpanNodeGeneratorWithTag(

macos/Flutter/GeneratedPluginRegistrant.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import share_plus
1313
import shared_preferences_foundation
1414
import sqflite_darwin
1515
import url_launcher_macos
16-
import webview_flutter_wkwebview
1716
import window_manager
1817

1918
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
@@ -25,6 +24,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
2524
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
2625
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
2726
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
28-
FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin"))
2927
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
3028
}

macos/Podfile.lock

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ PODS:
2121
- FlutterMacOS
2222
- url_launcher_macos (0.0.1):
2323
- FlutterMacOS
24-
- webview_flutter_wkwebview (0.0.1):
25-
- Flutter
26-
- FlutterMacOS
2724
- window_manager (0.2.0):
2825
- FlutterMacOS
2926

@@ -37,7 +34,6 @@ DEPENDENCIES:
3734
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
3835
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
3936
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
40-
- webview_flutter_wkwebview (from `Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin`)
4137
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
4238

4339
SPEC REPOS:
@@ -63,24 +59,21 @@ EXTERNAL SOURCES:
6359
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
6460
url_launcher_macos:
6561
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
66-
webview_flutter_wkwebview:
67-
:path: Flutter/ephemeral/.symlinks/plugins/webview_flutter_wkwebview/darwin
6862
window_manager:
6963
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
7064

7165
SPEC CHECKSUMS:
72-
file_picker: e716a70a9fe5fd9e09ebc922d7541464289443af
73-
flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b
66+
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
67+
flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d
7468
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
7569
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
76-
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
77-
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
78-
share_plus: 1fa619de8392a4398bfaf176d441853922614e89
79-
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
80-
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
81-
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
82-
webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4
83-
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
70+
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
71+
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
72+
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
73+
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
74+
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
75+
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
76+
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
8477

8578
PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
8679

0 commit comments

Comments
 (0)