158 lines
4.4 KiB
Dart
158 lines
4.4 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
|
|
import '../../core/plugins/plugin_host.dart';
|
|
import '../../core/plugins/plugin_manifest.dart';
|
|
|
|
class PluginCommandContext implements PluginHost {
|
|
const PluginCommandContext({
|
|
required this.args,
|
|
required this.arguments,
|
|
required this.replyMessage,
|
|
required this.onlineCheck,
|
|
required this.activeCheck,
|
|
required this.sendTextCallback,
|
|
required this.editTextCallback,
|
|
required this.sendPhotoCallback,
|
|
required this.sendFileCallback,
|
|
required this.notifyCallback,
|
|
required this.getPeerCallback,
|
|
});
|
|
|
|
@override
|
|
final String args;
|
|
|
|
@override
|
|
final Map<String, dynamic> arguments;
|
|
|
|
@override
|
|
final Map<String, dynamic>? replyMessage;
|
|
|
|
final bool Function() onlineCheck;
|
|
final bool Function() activeCheck;
|
|
final Future<String> Function(String text) sendTextCallback;
|
|
final Future<void> Function(String messageId, String text) editTextCallback;
|
|
final Future<void> Function(Uint8List bytes, String filename, String caption)
|
|
sendPhotoCallback;
|
|
final Future<void> Function(Uint8List bytes, String filename)
|
|
sendFileCallback;
|
|
final Future<void> Function(String message) notifyCallback;
|
|
final Future<Map<String, dynamic>?> Function() getPeerCallback;
|
|
|
|
@override
|
|
bool get isOnline => onlineCheck();
|
|
|
|
@override
|
|
bool get isActive => activeCheck();
|
|
|
|
@override
|
|
Future<String> sendText(String text) => sendTextCallback(text);
|
|
|
|
@override
|
|
Future<void> editText(String messageId, String text) =>
|
|
editTextCallback(messageId, text);
|
|
|
|
@override
|
|
Future<void> sendPhoto(
|
|
Uint8List bytes, {
|
|
required String filename,
|
|
required String caption,
|
|
}) => sendPhotoCallback(bytes, filename, caption);
|
|
|
|
@override
|
|
Future<void> sendFile(Uint8List bytes, {required String filename}) =>
|
|
sendFileCallback(bytes, filename);
|
|
|
|
@override
|
|
Future<void> notify(String message) => notifyCallback(message);
|
|
|
|
@override
|
|
Future<Map<String, dynamic>?> getPeer() => getPeerCallback();
|
|
}
|
|
|
|
Map<String, dynamic> parseCommandArguments(
|
|
String raw,
|
|
List<PluginCommandArgumentManifest> specs,
|
|
) {
|
|
if (specs.isEmpty) return const {};
|
|
final values = <String, dynamic>{};
|
|
final tokens = _tokenizeArguments(raw);
|
|
for (final spec in specs) {
|
|
if (spec.rest) {
|
|
values[spec.name] = tokens.join(' ');
|
|
tokens.clear();
|
|
continue;
|
|
}
|
|
values[spec.name] = tokens.isEmpty ? '' : tokens.removeAt(0);
|
|
}
|
|
return Map.unmodifiable(values);
|
|
}
|
|
|
|
String serializeCommandArguments(
|
|
List<PluginCommandArgumentManifest> specs,
|
|
Map<String, dynamic> values,
|
|
) {
|
|
final parts = <String>[];
|
|
for (final spec in specs) {
|
|
final value = values[spec.name]?.toString().trim() ?? '';
|
|
if (value.isEmpty && spec.rest) continue;
|
|
if (spec.rest) {
|
|
parts.add(value);
|
|
} else {
|
|
parts.add(_quoteArgument(value));
|
|
}
|
|
}
|
|
return parts.join(' ');
|
|
}
|
|
|
|
String _quoteArgument(String value) {
|
|
if (value.isEmpty) return '""';
|
|
if (!value.contains(RegExp(r'''[\s"']'''))) return value;
|
|
final escaped = value.replaceAll(r'\', r'\\').replaceAll('"', r'\"');
|
|
return '"$escaped"';
|
|
}
|
|
|
|
List<String> _tokenizeArguments(String source) {
|
|
final values = <String>[];
|
|
var remaining = source.trim();
|
|
while (remaining.isNotEmpty) {
|
|
final parsed = _takeArgument(remaining);
|
|
values.add(parsed.value);
|
|
if (parsed.remaining == remaining) break;
|
|
remaining = parsed.remaining;
|
|
}
|
|
return values;
|
|
}
|
|
|
|
({String value, String remaining}) _takeArgument(String source) {
|
|
final input = source.trimLeft();
|
|
if (input.isEmpty) return (value: '', remaining: '');
|
|
final quote = input[0];
|
|
if (quote == '"' || quote == "'") {
|
|
final buffer = StringBuffer();
|
|
var escaped = false;
|
|
for (var index = 1; index < input.length; index++) {
|
|
final char = input[index];
|
|
if (escaped) {
|
|
buffer.write(char);
|
|
escaped = false;
|
|
} else if (char == r'\') {
|
|
escaped = true;
|
|
} else if (char == quote) {
|
|
return (
|
|
value: buffer.toString(),
|
|
remaining: input.substring(index + 1).trimLeft(),
|
|
);
|
|
} else {
|
|
buffer.write(char);
|
|
}
|
|
}
|
|
return (value: buffer.toString(), remaining: '');
|
|
}
|
|
final separator = input.indexOf(RegExp(r'\s'));
|
|
if (separator == -1) return (value: input, remaining: '');
|
|
return (
|
|
value: input.substring(0, separator),
|
|
remaining: input.substring(separator + 1).trimLeft(),
|
|
);
|
|
}
|