11 changed files with 626 additions and 94 deletions
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
{ |
||||
// 使用 IntelliSense 了解相关属性。 |
||||
// 悬停以查看现有属性的描述。 |
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
"name": "win_text_editor", |
||||
"request": "launch", |
||||
"type": "dart" |
||||
}, |
||||
{ |
||||
"name": "win_text_editor (profile mode)", |
||||
"request": "launch", |
||||
"type": "dart", |
||||
"flutterMode": "profile" |
||||
}, |
||||
{ |
||||
"name": "win_text_editor (release mode)", |
||||
"request": "launch", |
||||
"type": "dart", |
||||
"flutterMode": "release" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,171 @@
@@ -0,0 +1,171 @@
|
||||
// lib/app/modules/content_search/content_search_service.dart |
||||
|
||||
import 'dart:io'; |
||||
import 'package:path/path.dart' as path; |
||||
|
||||
class ContentSearchService { |
||||
static Future<List<SearchResult>> performLocateSearch({ |
||||
required String directory, |
||||
required String query, |
||||
required String fileType, |
||||
required bool caseSensitive, |
||||
required bool wholeWord, |
||||
required bool useRegex, |
||||
}) async { |
||||
final results = <SearchResult>[]; |
||||
final dir = Directory(directory); |
||||
final queries = _splitQuery(query); // 分割查询字符串 |
||||
|
||||
for (final q in queries) { |
||||
final pattern = _buildSearchPattern( |
||||
query: q, |
||||
caseSensitive: caseSensitive, |
||||
wholeWord: wholeWord, |
||||
useRegex: useRegex, |
||||
); |
||||
|
||||
await for (final entity in dir.list(recursive: true)) { |
||||
if (entity is File && _matchesFileType(entity.path, fileType)) { |
||||
await _searchInFile(entity, pattern, results, q); // 传递当前查询项 |
||||
} |
||||
} |
||||
} |
||||
|
||||
return results; |
||||
} |
||||
|
||||
/// 计数搜索(返回每个关键词的匹配数) |
||||
static Future<Map<String, int>> performCountSearch({ |
||||
required String directory, |
||||
required String query, |
||||
required String fileType, |
||||
required bool caseSensitive, |
||||
required bool wholeWord, |
||||
required bool useRegex, |
||||
}) async { |
||||
final counts = <String, int>{}; |
||||
final dir = Directory(directory); |
||||
final queries = _splitQuery(query); // 分割查询字符串 |
||||
|
||||
for (final q in queries) { |
||||
final pattern = _buildSearchPattern( |
||||
query: q, |
||||
caseSensitive: caseSensitive, |
||||
wholeWord: wholeWord, |
||||
useRegex: useRegex, |
||||
); |
||||
|
||||
await for (final entity in dir.list(recursive: true)) { |
||||
if (entity is File && _matchesFileType(entity.path, fileType)) { |
||||
await _countInFile(entity, pattern, counts, q); // 传递当前查询项 |
||||
} |
||||
} |
||||
} |
||||
|
||||
return counts; |
||||
} |
||||
|
||||
/// 分割查询字符串(按半角逗号分隔,并去除空格) |
||||
static List<String> _splitQuery(String query) { |
||||
return query.split(',').map((q) => q.trim()).where((q) => q.isNotEmpty).toList(); |
||||
} |
||||
|
||||
/// 构建正则表达式(原逻辑不变) |
||||
static RegExp _buildSearchPattern({ |
||||
required String query, |
||||
required bool caseSensitive, |
||||
required bool wholeWord, |
||||
required bool useRegex, |
||||
}) { |
||||
String pattern; |
||||
if (useRegex) { |
||||
pattern = query; |
||||
} else { |
||||
pattern = RegExp.escape(query); |
||||
if (wholeWord) { |
||||
pattern = '\\b$pattern\\b'; |
||||
} |
||||
} |
||||
return RegExp(pattern, caseSensitive: caseSensitive, multiLine: true); |
||||
} |
||||
|
||||
/// 检查文件类型(原逻辑不变) |
||||
static bool _matchesFileType(String filePath, String fileType) { |
||||
if (fileType == '*.*') return true; |
||||
final ext = path.extension(filePath).toLowerCase(); |
||||
return ext == fileType.toLowerCase(); |
||||
} |
||||
|
||||
/// 在文件中搜索匹配项(增加 queryTerm 参数) |
||||
static Future<void> _searchInFile( |
||||
File file, |
||||
RegExp pattern, |
||||
List<SearchResult> results, |
||||
String queryTerm, // 当前查询项 |
||||
) async { |
||||
try { |
||||
final lines = await file.readAsLines(); |
||||
for (int i = 0; i < lines.length; i++) { |
||||
final line = lines[i]; |
||||
final matches = pattern.allMatches(line); |
||||
|
||||
if (matches.isNotEmpty) { |
||||
results.add( |
||||
SearchResult( |
||||
filePath: file.path, |
||||
lineNumber: i + 1, |
||||
lineContent: line, |
||||
matches: matches.map((m) => MatchResult(start: m.start, end: m.end)).toList(), |
||||
queryTerm: queryTerm, // 记录匹配的查询项 |
||||
), |
||||
); |
||||
} |
||||
} |
||||
} catch (e) { |
||||
print('Error reading file ${file.path}: $e'); |
||||
} |
||||
} |
||||
|
||||
/// 在文件中计数匹配项(增加 queryTerm 参数) |
||||
static Future<void> _countInFile( |
||||
File file, |
||||
RegExp pattern, |
||||
Map<String, int> counts, |
||||
String queryTerm, // 当前查询项 |
||||
) async { |
||||
try { |
||||
final content = await file.readAsString(); |
||||
final matches = pattern.allMatches(content); |
||||
|
||||
if (matches.isNotEmpty) { |
||||
counts[queryTerm] = (counts[queryTerm] ?? 0) + matches.length; |
||||
} |
||||
} catch (e) { |
||||
print('Error reading file ${file.path}: $e'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// 搜索结果类(新增 queryTerm 字段) |
||||
class SearchResult { |
||||
final String filePath; |
||||
final int lineNumber; |
||||
final String lineContent; |
||||
final List<MatchResult> matches; |
||||
final String queryTerm; // 记录匹配的查询项 |
||||
|
||||
SearchResult({ |
||||
required this.filePath, |
||||
required this.lineNumber, |
||||
required this.lineContent, |
||||
required this.matches, |
||||
required this.queryTerm, |
||||
}); |
||||
} |
||||
|
||||
class MatchResult { |
||||
final int start; |
||||
final int end; |
||||
|
||||
const MatchResult({required this.start, required this.end}); |
||||
} |
Loading…
Reference in new issue