fix: catch regex FormatException and show a corresponding error message (#573)
* add error message * restore and reformat * update localization and comments * chore: reformat files
This commit is contained in:
parent
aa90288c20
commit
77e5d8713b
9 changed files with 97 additions and 15 deletions
|
|
@ -128,6 +128,9 @@
|
||||||
"replaceAll": "Replace all",
|
"replaceAll": "Replace all",
|
||||||
"regex": "Regex",
|
"regex": "Regex",
|
||||||
"caseSensitive": "Case sensitive",
|
"caseSensitive": "Case sensitive",
|
||||||
|
"regexError": "Regex Error",
|
||||||
|
"noFindResult": "No result",
|
||||||
|
"emptySearchBoxHint": "Enter a pattern",
|
||||||
"uploadImage": "Upload Image",
|
"uploadImage": "Upload Image",
|
||||||
"urlImage": "URL Image",
|
"urlImage": "URL Image",
|
||||||
"incorrectLink": "Incorrect Link",
|
"incorrectLink": "Incorrect Link",
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,9 @@
|
||||||
"replaceAll": "替换全部",
|
"replaceAll": "替换全部",
|
||||||
"regex": "正则表达式",
|
"regex": "正则表达式",
|
||||||
"caseSensitive": "区分大小写",
|
"caseSensitive": "区分大小写",
|
||||||
|
"regexError": "正则错误",
|
||||||
|
"noFindResult": "无匹配项",
|
||||||
|
"emptySearchBoxHint": "输入查找内容",
|
||||||
"uploadImage": "上传图片",
|
"uploadImage": "上传图片",
|
||||||
"urlImage": "网络图片",
|
"urlImage": "网络图片",
|
||||||
"incorrectLink": "链接错误",
|
"incorrectLink": "链接错误",
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,9 @@
|
||||||
"replaceAll": "取代全部",
|
"replaceAll": "取代全部",
|
||||||
"regex": "正規表示式",
|
"regex": "正規表示式",
|
||||||
"caseSensitive": "區分大小寫",
|
"caseSensitive": "區分大小寫",
|
||||||
|
"regexError": "正規錯誤",
|
||||||
|
"noFindResult": "無相符項",
|
||||||
|
"emptySearchBoxHint": "鍵入尋找内容",
|
||||||
"uploadImage": "上載圖片",
|
"uploadImage": "上載圖片",
|
||||||
"urlImage": "網路圖片",
|
"urlImage": "網路圖片",
|
||||||
"incorrectLink": "連結錯誤",
|
"incorrectLink": "連結錯誤",
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ class _FindMenuState extends State<FindMenu> {
|
||||||
|
|
||||||
final findTextEditingController = TextEditingController();
|
final findTextEditingController = TextEditingController();
|
||||||
|
|
||||||
String queriedPattern = '';
|
String message = AppFlowyEditorLocalizations.current.emptySearchBoxHint;
|
||||||
|
|
||||||
bool showReplaceMenu = false;
|
bool showReplaceMenu = false;
|
||||||
bool caseSensitive = false;
|
bool caseSensitive = false;
|
||||||
|
|
@ -250,9 +250,7 @@ class _FindMenuState extends State<FindMenu> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
matches.isEmpty
|
matches.isEmpty ? message : '$selectedIndex of ${matches.length}',
|
||||||
? widget.localizations?.noResult ?? 'No Result'
|
|
||||||
: '$selectedIndex of ${matches.length}',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// previous match button
|
// previous match button
|
||||||
|
|
@ -322,11 +320,25 @@ class _FindMenuState extends State<FindMenu> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _searchPattern() {
|
void _searchPattern() {
|
||||||
if (findTextEditingController.text.isEmpty) {
|
String error;
|
||||||
return;
|
|
||||||
|
// the following line needs to be executed even if
|
||||||
|
// findTextEditingController.text.isEmpty, otherwise the previous
|
||||||
|
// matches will persist
|
||||||
|
error =
|
||||||
|
widget.searchService.findAndHighlight(findTextEditingController.text);
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case 'Regex':
|
||||||
|
message = AppFlowyEditorLocalizations.current.regexError;
|
||||||
|
case 'Empty':
|
||||||
|
message = AppFlowyEditorLocalizations.current.emptySearchBoxHint;
|
||||||
|
default:
|
||||||
|
message = widget.localizations?.noResult ??
|
||||||
|
AppFlowyEditorLocalizations.current.noFindResult;
|
||||||
}
|
}
|
||||||
widget.searchService.findAndHighlight(findTextEditingController.text);
|
|
||||||
setState(() => queriedPattern = findTextEditingController.text);
|
_setState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setState() {
|
void _setState() {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ class SearchServiceV3 {
|
||||||
|
|
||||||
final EditorState editorState;
|
final EditorState editorState;
|
||||||
|
|
||||||
//matchedPositions.value will contain a list of positions of the matched patterns
|
//matchWrappers.value will contain a list of matchWrappers of the matched patterns
|
||||||
//the position here consists of the node and the starting offset of the
|
//the position here consists of the match and the node path of
|
||||||
//matched pattern. We will use this to traverse between the matched patterns.
|
//matched pattern. We will use this to traverse between the matched patterns.
|
||||||
ValueNotifier<List<MatchWrapper>> matchWrappers = ValueNotifier([]);
|
ValueNotifier<List<MatchWrapper>> matchWrappers = ValueNotifier([]);
|
||||||
SearchAlgorithm searchAlgorithm = DartBuiltIn();
|
SearchAlgorithm searchAlgorithm = DartBuiltIn();
|
||||||
|
|
@ -75,8 +75,15 @@ class SearchServiceV3 {
|
||||||
|
|
||||||
// Public entry method for _findAndHighlight, do necessary checks
|
// Public entry method for _findAndHighlight, do necessary checks
|
||||||
// and clear previous highlights before calling the private method
|
// and clear previous highlights before calling the private method
|
||||||
void findAndHighlight(String target, {bool unHighlight = false}) {
|
String findAndHighlight(String target, {bool unHighlight = false}) {
|
||||||
Pattern pattern = _getPattern(target);
|
Pattern pattern;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pattern = _getPattern(target);
|
||||||
|
} on FormatException {
|
||||||
|
matchWrappers.value.clear();
|
||||||
|
return 'Regex';
|
||||||
|
}
|
||||||
|
|
||||||
if (queriedPattern != pattern) {
|
if (queriedPattern != pattern) {
|
||||||
// this means we have a new pattern, but before we highlight the new matches,
|
// this means we have a new pattern, but before we highlight the new matches,
|
||||||
|
|
@ -87,9 +94,11 @@ class SearchServiceV3 {
|
||||||
targetString = target;
|
targetString = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.isEmpty) return;
|
if (target.isEmpty) return 'Empty';
|
||||||
|
|
||||||
_findAndHighlight(pattern, unHighlight: unHighlight);
|
_findAndHighlight(pattern, unHighlight: unHighlight);
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds the pattern in editorState.document and stores it in matchedPositions.
|
/// Finds the pattern in editorState.document and stores it in matchedPositions.
|
||||||
|
|
@ -186,7 +195,7 @@ class SearchServiceV3 {
|
||||||
/// matched word if that exists.
|
/// matched word if that exists.
|
||||||
Future<void> replaceSelectedWord(String replaceText) async {
|
Future<void> replaceSelectedWord(String replaceText) async {
|
||||||
if (replaceText.isEmpty ||
|
if (replaceText.isEmpty ||
|
||||||
queriedPattern.toString().isEmpty ||
|
queriedPattern.isEmpty ||
|
||||||
matchWrappers.value.isEmpty) {
|
matchWrappers.value.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +226,7 @@ class SearchServiceV3 {
|
||||||
/// Replaces all the found occurrences of pattern with replaceText
|
/// Replaces all the found occurrences of pattern with replaceText
|
||||||
void replaceAllMatches(String replaceText) {
|
void replaceAllMatches(String replaceText) {
|
||||||
if (replaceText.isEmpty ||
|
if (replaceText.isEmpty ||
|
||||||
queriedPattern.toString().isEmpty ||
|
queriedPattern.isEmpty ||
|
||||||
matchWrappers.value.isEmpty) {
|
matchWrappers.value.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -257,3 +266,15 @@ class MatchWrapper {
|
||||||
end: Position(path: path, offset: match.end),
|
end: Position(path: path, offset: match.end),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on Pattern {
|
||||||
|
bool get isEmpty {
|
||||||
|
if (this is String) {
|
||||||
|
return (this as String).isEmpty;
|
||||||
|
} else if (this is RegExp) {
|
||||||
|
return (this as RegExp).pattern.isEmpty;
|
||||||
|
} else {
|
||||||
|
return toString().isEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"done": MessageLookupByLibrary.simpleMessage("Done"),
|
"done": MessageLookupByLibrary.simpleMessage("Done"),
|
||||||
"editLink": MessageLookupByLibrary.simpleMessage("Edit link"),
|
"editLink": MessageLookupByLibrary.simpleMessage("Edit link"),
|
||||||
"embedCode": MessageLookupByLibrary.simpleMessage("Embed Code"),
|
"embedCode": MessageLookupByLibrary.simpleMessage("Embed Code"),
|
||||||
|
"emptySearchBoxHint":
|
||||||
|
MessageLookupByLibrary.simpleMessage("Enter a pattern"),
|
||||||
"find": MessageLookupByLibrary.simpleMessage("Find"),
|
"find": MessageLookupByLibrary.simpleMessage("Find"),
|
||||||
"fontColorBlue": MessageLookupByLibrary.simpleMessage("Blue"),
|
"fontColorBlue": MessageLookupByLibrary.simpleMessage("Blue"),
|
||||||
"fontColorBrown": MessageLookupByLibrary.simpleMessage("Brown"),
|
"fontColorBrown": MessageLookupByLibrary.simpleMessage("Brown"),
|
||||||
|
|
@ -113,6 +115,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"mobileHeading2": MessageLookupByLibrary.simpleMessage("Heading 2"),
|
"mobileHeading2": MessageLookupByLibrary.simpleMessage("Heading 2"),
|
||||||
"mobileHeading3": MessageLookupByLibrary.simpleMessage("Heading 3"),
|
"mobileHeading3": MessageLookupByLibrary.simpleMessage("Heading 3"),
|
||||||
"nextMatch": MessageLookupByLibrary.simpleMessage("Next match"),
|
"nextMatch": MessageLookupByLibrary.simpleMessage("Next match"),
|
||||||
|
"noFindResult": MessageLookupByLibrary.simpleMessage("No result"),
|
||||||
"numberedList": MessageLookupByLibrary.simpleMessage("Numbered List"),
|
"numberedList": MessageLookupByLibrary.simpleMessage("Numbered List"),
|
||||||
"opacity": MessageLookupByLibrary.simpleMessage("Opacity"),
|
"opacity": MessageLookupByLibrary.simpleMessage("Opacity"),
|
||||||
"openLink": MessageLookupByLibrary.simpleMessage("Open link"),
|
"openLink": MessageLookupByLibrary.simpleMessage("Open link"),
|
||||||
|
|
@ -120,6 +123,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"previousMatch": MessageLookupByLibrary.simpleMessage("Previous match"),
|
"previousMatch": MessageLookupByLibrary.simpleMessage("Previous match"),
|
||||||
"quote": MessageLookupByLibrary.simpleMessage("Quote"),
|
"quote": MessageLookupByLibrary.simpleMessage("Quote"),
|
||||||
"regex": MessageLookupByLibrary.simpleMessage("Regex"),
|
"regex": MessageLookupByLibrary.simpleMessage("Regex"),
|
||||||
|
"regexError": MessageLookupByLibrary.simpleMessage("Regex Error"),
|
||||||
"removeLink": MessageLookupByLibrary.simpleMessage("Remove link"),
|
"removeLink": MessageLookupByLibrary.simpleMessage("Remove link"),
|
||||||
"replace": MessageLookupByLibrary.simpleMessage("Replace"),
|
"replace": MessageLookupByLibrary.simpleMessage("Replace"),
|
||||||
"replaceAll": MessageLookupByLibrary.simpleMessage("Replace all"),
|
"replaceAll": MessageLookupByLibrary.simpleMessage("Replace all"),
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"done": MessageLookupByLibrary.simpleMessage("完成"),
|
"done": MessageLookupByLibrary.simpleMessage("完成"),
|
||||||
"editLink": MessageLookupByLibrary.simpleMessage("修改链接"),
|
"editLink": MessageLookupByLibrary.simpleMessage("修改链接"),
|
||||||
"embedCode": MessageLookupByLibrary.simpleMessage("代码块"),
|
"embedCode": MessageLookupByLibrary.simpleMessage("代码块"),
|
||||||
|
"emptySearchBoxHint": MessageLookupByLibrary.simpleMessage("输入查找内容"),
|
||||||
"find": MessageLookupByLibrary.simpleMessage("查找"),
|
"find": MessageLookupByLibrary.simpleMessage("查找"),
|
||||||
"fontColorBlue": MessageLookupByLibrary.simpleMessage("蓝色"),
|
"fontColorBlue": MessageLookupByLibrary.simpleMessage("蓝色"),
|
||||||
"fontColorBrown": MessageLookupByLibrary.simpleMessage("棕色"),
|
"fontColorBrown": MessageLookupByLibrary.simpleMessage("棕色"),
|
||||||
|
|
@ -97,6 +98,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"mobileHeading2": MessageLookupByLibrary.simpleMessage("二级标题"),
|
"mobileHeading2": MessageLookupByLibrary.simpleMessage("二级标题"),
|
||||||
"mobileHeading3": MessageLookupByLibrary.simpleMessage("三级标题"),
|
"mobileHeading3": MessageLookupByLibrary.simpleMessage("三级标题"),
|
||||||
"nextMatch": MessageLookupByLibrary.simpleMessage("下一匹配项"),
|
"nextMatch": MessageLookupByLibrary.simpleMessage("下一匹配项"),
|
||||||
|
"noFindResult": MessageLookupByLibrary.simpleMessage("无匹配项"),
|
||||||
"numberedList": MessageLookupByLibrary.simpleMessage("有序列表"),
|
"numberedList": MessageLookupByLibrary.simpleMessage("有序列表"),
|
||||||
"opacity": MessageLookupByLibrary.simpleMessage("透明度"),
|
"opacity": MessageLookupByLibrary.simpleMessage("透明度"),
|
||||||
"openLink": MessageLookupByLibrary.simpleMessage("打开链接"),
|
"openLink": MessageLookupByLibrary.simpleMessage("打开链接"),
|
||||||
|
|
@ -104,6 +106,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"previousMatch": MessageLookupByLibrary.simpleMessage("上一匹配项"),
|
"previousMatch": MessageLookupByLibrary.simpleMessage("上一匹配项"),
|
||||||
"quote": MessageLookupByLibrary.simpleMessage("引文"),
|
"quote": MessageLookupByLibrary.simpleMessage("引文"),
|
||||||
"regex": MessageLookupByLibrary.simpleMessage("正则表达式"),
|
"regex": MessageLookupByLibrary.simpleMessage("正则表达式"),
|
||||||
|
"regexError": MessageLookupByLibrary.simpleMessage("正则错误"),
|
||||||
"removeLink": MessageLookupByLibrary.simpleMessage("移除链接"),
|
"removeLink": MessageLookupByLibrary.simpleMessage("移除链接"),
|
||||||
"replace": MessageLookupByLibrary.simpleMessage("替换"),
|
"replace": MessageLookupByLibrary.simpleMessage("替换"),
|
||||||
"replaceAll": MessageLookupByLibrary.simpleMessage("替换全部"),
|
"replaceAll": MessageLookupByLibrary.simpleMessage("替换全部"),
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"done": MessageLookupByLibrary.simpleMessage("完成"),
|
"done": MessageLookupByLibrary.simpleMessage("完成"),
|
||||||
"editLink": MessageLookupByLibrary.simpleMessage("修改連結"),
|
"editLink": MessageLookupByLibrary.simpleMessage("修改連結"),
|
||||||
"embedCode": MessageLookupByLibrary.simpleMessage("代碼塊"),
|
"embedCode": MessageLookupByLibrary.simpleMessage("代碼塊"),
|
||||||
|
"emptySearchBoxHint": MessageLookupByLibrary.simpleMessage("鍵入尋找内容"),
|
||||||
"find": MessageLookupByLibrary.simpleMessage("尋找"),
|
"find": MessageLookupByLibrary.simpleMessage("尋找"),
|
||||||
"fontColorBlue": MessageLookupByLibrary.simpleMessage("藍色"),
|
"fontColorBlue": MessageLookupByLibrary.simpleMessage("藍色"),
|
||||||
"fontColorBrown": MessageLookupByLibrary.simpleMessage("棕色"),
|
"fontColorBrown": MessageLookupByLibrary.simpleMessage("棕色"),
|
||||||
|
|
@ -97,6 +98,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"mobileHeading2": MessageLookupByLibrary.simpleMessage("二級標題"),
|
"mobileHeading2": MessageLookupByLibrary.simpleMessage("二級標題"),
|
||||||
"mobileHeading3": MessageLookupByLibrary.simpleMessage("三級標題"),
|
"mobileHeading3": MessageLookupByLibrary.simpleMessage("三級標題"),
|
||||||
"nextMatch": MessageLookupByLibrary.simpleMessage("下一相符項"),
|
"nextMatch": MessageLookupByLibrary.simpleMessage("下一相符項"),
|
||||||
|
"noFindResult": MessageLookupByLibrary.simpleMessage("無相符項"),
|
||||||
"numberedList": MessageLookupByLibrary.simpleMessage("有序列表"),
|
"numberedList": MessageLookupByLibrary.simpleMessage("有序列表"),
|
||||||
"opacity": MessageLookupByLibrary.simpleMessage("透明度"),
|
"opacity": MessageLookupByLibrary.simpleMessage("透明度"),
|
||||||
"openLink": MessageLookupByLibrary.simpleMessage("打開連結"),
|
"openLink": MessageLookupByLibrary.simpleMessage("打開連結"),
|
||||||
|
|
@ -104,6 +106,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"previousMatch": MessageLookupByLibrary.simpleMessage("上一相符項"),
|
"previousMatch": MessageLookupByLibrary.simpleMessage("上一相符項"),
|
||||||
"quote": MessageLookupByLibrary.simpleMessage("引文"),
|
"quote": MessageLookupByLibrary.simpleMessage("引文"),
|
||||||
"regex": MessageLookupByLibrary.simpleMessage("正規表示式"),
|
"regex": MessageLookupByLibrary.simpleMessage("正規表示式"),
|
||||||
|
"regexError": MessageLookupByLibrary.simpleMessage("正規錯誤"),
|
||||||
"removeLink": MessageLookupByLibrary.simpleMessage("移除連結"),
|
"removeLink": MessageLookupByLibrary.simpleMessage("移除連結"),
|
||||||
"replace": MessageLookupByLibrary.simpleMessage("取代"),
|
"replace": MessageLookupByLibrary.simpleMessage("取代"),
|
||||||
"replaceAll": MessageLookupByLibrary.simpleMessage("取代全部"),
|
"replaceAll": MessageLookupByLibrary.simpleMessage("取代全部"),
|
||||||
|
|
|
||||||
|
|
@ -961,6 +961,36 @@ class AppFlowyEditorLocalizations {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Regex Error`
|
||||||
|
String get regexError {
|
||||||
|
return Intl.message(
|
||||||
|
'Regex Error',
|
||||||
|
name: 'regexError',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `No result`
|
||||||
|
String get noFindResult {
|
||||||
|
return Intl.message(
|
||||||
|
'No result',
|
||||||
|
name: 'noFindResult',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Enter a pattern`
|
||||||
|
String get emptySearchBoxHint {
|
||||||
|
return Intl.message(
|
||||||
|
'Enter a pattern',
|
||||||
|
name: 'emptySearchBoxHint',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// `Upload Image`
|
/// `Upload Image`
|
||||||
String get uploadImage {
|
String get uploadImage {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue