executeImpl method
Implement the actual tool logic
params are the validated parameters (never null here)
Returns the result data to send in the response
Implementation
@override
Future<dynamic> executeImpl(Map<String, dynamic> params) async {
final query = params['query'] as String;
final filePattern = params['file_pattern'] as String? ?? '*.dart';
final searchPath = params['path'] as String?;
final caseSensitive = params['case_sensitive'] as bool? ?? false;
final useRegex = params['use_regex'] as bool? ?? false;
final maxResults = params['max_results'] as int? ?? 50;
// TODO: Implement context_lines feature
// final contextLines = params['context_lines'] as int? ?? 0;
final excludePatterns = params['exclude_patterns'] as List<String>?;
final project = ServerPodLocator.getProject();
if (project == null || !project.isValid) {
return {'error': 'Not a valid ServerPod project'};
}
// Determine search directory
String basePath = project.rootPath;
if (searchPath != null && searchPath.isNotEmpty) {
basePath = p.normalize(p.join(project.rootPath, searchPath));
}
final baseDir = Directory(basePath);
if (!baseDir.existsSync()) {
return {
'error': 'Search path not found',
'path': basePath,
};
}
// Build regex for matching
RegExp searchRegex;
try {
if (useRegex) {
searchRegex = RegExp(query, caseSensitive: caseSensitive);
} else {
searchRegex = RegExp(
RegExp.escape(query),
caseSensitive: caseSensitive,
);
}
} catch (e) {
return {
'error': 'Invalid query pattern',
'message': e.toString(),
};
}
// Search files
final results = <CodeMatch>[];
final filesSearched = <String>[];
await for (final entity in _findFiles(baseDir, filePattern, excludePatterns)) {
if (results.length >= maxResults) break;
final file = entity as File;
filesSearched.add(file.path);
final matches = await _searchInFile(
file,
project.rootPath,
searchRegex,
maxResults - results.length,
);
results.addAll(matches);
}
return {
'query': query,
'filePattern': filePattern,
'searchPath': basePath,
'caseSensitive': caseSensitive,
'useRegex': useRegex,
'results': results.map((m) => m.toJson()).toList(),
'resultCount': results.length,
'filesSearched': filesSearched.length,
'truncated': results.length >= maxResults,
};
}