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