diff --git a/win_text_editor/lib/modules/content_search/providers/content_search_controller.dart b/win_text_editor/lib/modules/content_search/providers/content_search_controller.dart index d45f5e1..f983bf3 100644 --- a/win_text_editor/lib/modules/content_search/providers/content_search_controller.dart +++ b/win_text_editor/lib/modules/content_search/providers/content_search_controller.dart @@ -67,6 +67,7 @@ class ContentSearchController with ChangeNotifier { set searchDirectory(String value) { _searchDirectory = value; + Logger().debug('Updating searchDirectory to: $value'); notifyListeners(); } @@ -100,67 +101,6 @@ class ContentSearchController with ChangeNotifier { notifyListeners(); } - Future performCustomSearch() async { - final results = []; - int count = 0; - final dir = Directory(_searchDirectory); - - await for (final entity in dir.list(recursive: true)) { - if (entity is File && _matchesFileType(entity.path, fileType)) { - try { - final lines = await entity.readAsLines(); - for (int i = 0; i < lines.length; i++) { - final line = lines[i].trim(); - //过滤掉2个字符以内的行(如 ); 等) - if (line.length < 3) continue; - - final script = 'match(${jsonEncode(line)});'; - - final result = _jsRuntime.evaluate(script); - if (result.isError) { - Logger().error('JavaScript 执行错误: ${result.stringResult}'); - continue; - } - - if (result.stringResult == 'true') { - if (searchMode == SearchMode.locate) { - results.add( - SearchResult( - filePath: entity.path, - lineNumber: i + 1, - lineContent: line, - matches: [], - queryTerm: "自定义", - ), - ); - } else { - count = count + 1; - } - } - } - } catch (e) { - Logger().error('Error reading file ${entity.path}: $e'); - } - } - } - - if (searchMode == SearchMode.locate) { - Logger().debug("处理结果--定位${results.length.toString()}"); - _results.addAll(results); - } else { - Logger().debug("处理结果--计数${count.toString()}"); - _results.add( - SearchResult( - filePath: "JavaScript", - lineNumber: count, - lineContent: '', - matches: [], - queryTerm: "JavaScript", - ), - ); - } - } - Future startSearch() async { _results.clear(); @@ -178,27 +118,12 @@ class ContentSearchController with ChangeNotifier { } if (customRule) { - final jsFunction = 'function match(content) {$searchQuery};'; - try { - // 执行 JS 代码进行语法检查 - final result = _jsRuntime.evaluate(jsFunction); - if (result.isError) { - Logger().error('JavaScript 语法错误: ${result.rawResult.toString()}'); - return; - } - - final test = _jsRuntime.evaluate("match('test');"); - if (test.stringResult != 'true' && test.stringResult != 'false') { - Logger().error('自定规则逻辑错误,没有返回布尔值,返回值为: ${test.stringResult}'); - return; - } - } catch (e) { - Logger().error('JavaScript 语法检查错误: $e'); + final validationResult = ContentSearchService.validateJsRule(searchQuery); + if (validationResult.isError) { + Logger().error('JavaScript 语法错误: ${validationResult.rawResult.toString()}'); return; - } finally { - notifyListeners(); - _jsRuntime.dispose(); } + _results.addAll( await ContentSearchService.performCustomSearch( directory: searchDirectory, @@ -256,10 +181,4 @@ class ContentSearchController with ChangeNotifier { searchDirectory = dir; } } - - bool _matchesFileType(String filePath, String fileType) { - if (fileType == '*.*') return true; - final ext = path.extension(filePath).toLowerCase(); - return ext == fileType.toLowerCase(); - } } diff --git a/win_text_editor/lib/modules/content_search/services/content_search_service.dart b/win_text_editor/lib/modules/content_search/services/content_search_service.dart index 8a85439..a90794a 100644 --- a/win_text_editor/lib/modules/content_search/services/content_search_service.dart +++ b/win_text_editor/lib/modules/content_search/services/content_search_service.dart @@ -288,4 +288,29 @@ class ContentSearchService { Logger().error('Error reading file ${file.path}: $e'); } } + + // 在 ContentSearchService 类中添加以下方法 + + /// 验证 JavaScript 自定义规则的语法 + static JsEvalResult validateJsRule(String jsFunction) { + final jsRuntime = getJavascriptRuntime(); + try { + final jsCode = 'function match(content) {$jsFunction};'; + // 执行 JS 代码进行语法检查 + final result = jsRuntime.evaluate(jsCode); + if (result.isError) { + return result; + } + + // 测试函数是否返回布尔值 + final test = jsRuntime.evaluate("match('test');"); + if (test.stringResult != 'true' && test.stringResult != 'false') { + return JsEvalResult('Custom rule must return boolean (true/false)', null, isError: true); + } + + return test; + } finally { + jsRuntime.dispose(); + } + } } diff --git a/win_text_editor/lib/modules/content_search/widgets/content_search_view.dart b/win_text_editor/lib/modules/content_search/widgets/content_search_view.dart index 0610c8b..c9b9203 100644 --- a/win_text_editor/lib/modules/content_search/widgets/content_search_view.dart +++ b/win_text_editor/lib/modules/content_search/widgets/content_search_view.dart @@ -46,13 +46,13 @@ class ContentSearchViewState extends BaseViewState { Widget build(BuildContext context) { return ChangeNotifierProvider.value( value: _controller, - child: Padding( - padding: const EdgeInsets.all(4.0), + child: const Padding( + padding: EdgeInsets.all(4.0), child: Column( children: [ - const DirectorySettings(), // 不再手动传递controller + DirectorySettings(), // 不再手动传递controller SearchSettings(), - const Expanded(child: ResultsView()), + Expanded(child: ResultsView()), ], ), ), diff --git a/win_text_editor/lib/modules/content_search/widgets/directory_settings.dart b/win_text_editor/lib/modules/content_search/widgets/directory_settings.dart index ceda309..96a6760 100644 --- a/win_text_editor/lib/modules/content_search/widgets/directory_settings.dart +++ b/win_text_editor/lib/modules/content_search/widgets/directory_settings.dart @@ -12,25 +12,13 @@ class DirectorySettings extends StatefulWidget { class _DirectorySettingsState extends State { late TextEditingController _searchDirectoryController; late TextEditingController _fileTypeController; - late ContentSearchController _controller; @override void initState() { super.initState(); - _controller = context.read(); - _searchDirectoryController = TextEditingController(text: _controller.searchDirectory); - _fileTypeController = TextEditingController(text: _controller.fileType); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final newController = context.read(); - if (_controller != newController) { - _controller = newController; - _searchDirectoryController.text = _controller.searchDirectory; - _fileTypeController.text = _controller.fileType; - } + final controller = context.read(); + _searchDirectoryController = TextEditingController(text: controller.searchDirectory); + _fileTypeController = TextEditingController(text: controller.fileType); } @override @@ -42,6 +30,17 @@ class _DirectorySettingsState extends State { @override Widget build(BuildContext context) { + // 使用 Consumer 监听 ContentSearchController 的变化 + return Consumer( + builder: (context, controller, child) { + // 同步 TextEditingController 的值 + if (_searchDirectoryController.text != controller.searchDirectory) { + _searchDirectoryController.text = controller.searchDirectory; + } + if (_fileTypeController.text != controller.fileType) { + _fileTypeController.text = controller.fileType; + } + return Card( child: Padding( padding: const EdgeInsets.all(8.0), @@ -50,30 +49,39 @@ class _DirectorySettingsState extends State { Expanded( child: TextField( controller: _searchDirectoryController, - decoration: const InputDecoration(labelText: '搜索目录', border: OutlineInputBorder()), - onChanged: (value) => _controller.searchDirectory = value, + decoration: const InputDecoration( + labelText: '搜索目录', + border: OutlineInputBorder(), ), + onChanged: (value) => controller.searchDirectory = value, ), + ), const SizedBox(width: 8), SizedBox( width: 100, child: TextField( controller: _fileTypeController, - decoration: const InputDecoration(labelText: '文件类型', border: OutlineInputBorder()), - onChanged: (value) => _controller.fileType = value, + decoration: const InputDecoration( + labelText: '文件类型', + border: OutlineInputBorder(), ), + onChanged: (value) => controller.fileType = value, ), + ), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.folder_open), onPressed: () async { - await _controller.pickDirectory(); - _searchDirectoryController.text = _controller.searchDirectory; + await controller.pickDirectory(); + // 不需要手动更新 _searchDirectoryController.text, + // 因为 Consumer 会触发重建并自动同步 }, ), ], ), ), ); + }, + ); } }