import 'dart:async'; import 'dart:io'; import 'package:dart_framework/utils/system_util.dart'; import 'package:oto_cli/cli/commands/command_base.dart'; import 'package:oto_cli/cli/commands/command_manager.dart'; import 'package:path/path.dart' as path; enum Color { black, red, green, yellow, blue, magenta, cyan, lightGray, darkGray, lightRed, lightGreen, lightYellow, lightBlue, lightMagenta, lightCyan, white } enum Style { bold, underline, dim, reverse } class CLIConfig { String serviceName; List arguments; List commands; late String executableFileName; CLIConfig(this.serviceName, this.arguments, this.commands) { var fileName = path.basename(Platform.resolvedExecutable); fileName = fileName.replaceAll(path.extension(fileName), ''); executableFileName = fileName; } } class CLI { static final _colorCodeMap = { Color.black: "30", Color.red: "31", Color.green: "32", Color.yellow: "33", Color.blue: "34", Color.magenta: "35", Color.cyan: "36", Color.lightGray: "37", Color.darkGray: "90", Color.lightRed: "91", Color.lightGreen: "92", Color.lightYellow: "93", Color.lightBlue: "94", Color.lightMagenta: "95", Color.lightCyan: "96", Color.white: "97" }; static final _backgroundCodeMap = { Color.black: "40", Color.red: "41", Color.green: "42", Color.yellow: "43", Color.blue: "44", Color.magenta: "45", Color.cyan: "46", Color.lightGray: "47", Color.darkGray: "100", Color.lightRed: "101", Color.lightGreen: "102", Color.lightYellow: "103", Color.lightBlue: "104", Color.lightMagenta: "105", Color.lightCyan: "106", Color.white: "107" }; static final _styleCodeMap = { Style.bold: "1", Style.dim: "2", Style.underline: "4", Style.reverse: "7" }; static Printer get printer { if (Platform.isWindows) { return Printer.windows(); } else { return Printer.unix(); } } CLI._privateConstructor(); static final CLI _instance = CLI._privateConstructor(); static CLI get current => _instance; static void initialize( String serviceName, List arguments, List commands) { current.start(serviceName, arguments, commands); } static String style(String message, {Color? color, Color? background, Style? style}) { if (Platform.isWindows) { return message; } else { return printer.getStyle(message, color: color, background: background, style: style); } } static final commandNameSpace = 18; static get serviceName => CLI.current.config.serviceName; static get executableFileName => CLI.current.config.executableFileName; static Future print(List printList) async { await printer.printCLI(printList); return simpleFuture; } late CLIConfig config; late CommandManager _commandManager; void start(String serviceName, List arguments, List commands) async { config = CLIConfig(serviceName, arguments, commands); _commandManager = CommandManager(config.commands); //find command String? command; var args = config.arguments.toList(); if (arguments.isNotEmpty) { for (var value in args) { command = value; break; } args.removeAt(0); } await _commandManager.execute(command, args); } } //Printer Base abstract class Printer { Printer(); factory Printer.windows() => _PrinterWindows(); factory Printer.unix() => _PrinterUnix(); String getStyle(String message, {Color? color, Color? background, Style? style}) { var combine = ''; if (color != null) { combine = CLI._colorCodeMap[color]!; } if (background != null) { combine = combineText(combine, CLI._backgroundCodeMap[background]!); } if (style != null) { combine = combineText(combine, CLI._styleCodeMap[style]!); } return combine; } String combineText(String combine, String item) { if (combine == '') { combine = item; } else { combine += ';$item'; } return combine; } Future getTempFile(String content, String extension) async { var c = Completer(); var now = DateTime.now(); var time = '${now.hour}${now.minute}${now.second}${now.millisecond}${now.microsecond}'; var tempFile = File(path.join(Directory.systemTemp.path, 'temp_$time.$extension')); await tempFile.writeAsString(content); c.complete(tempFile); return c.future; } Future printCLI(List printList) async {} } //Printer windows class _PrinterWindows extends Printer { @override String getStyle(String message, {Color? color, Color? background, Style? style}) { var combine = super .getStyle(message, color: color, background: background, style: style); return '%ESC%[${combine}m$message%ESC%[0m'; } @override Future printCLI(List printList) async { var c = Completer(); StringBuffer message = StringBuffer(); message.writeln('@echo off'); message.writeln(''); message.writeln('setlocal'); message.writeln('call :setESC'); for (var item in printList) { if (item.isEmpty) { message.writeln('echo.'); } else { item = item .replaceAll('<', '^<') .replaceAll('>', '^>') // .replaceAll('[', '^[') .replaceAll(']', '^]') .replaceAll('|', '^|'); message.writeln('echo $item'); } } message.writeln(':setESC'); var temp = await getTempFile(message.toString(), 'bat'); await Process.run('cmd', ['/C', temp.path]).then((ProcessResult result) { print(result.stdout); }); await temp.delete(); c.complete(); return c.future; } } //Printer mac/linux class _PrinterUnix extends Printer { @override String getStyle(String message, {Color? color, Color? background, Style? style}) { var combine = super .getStyle(message, color: color, background: background, style: style); return '\\e[${combine}m$message\\e[0m'; } @override Future printCLI(List printList) async { var c = Completer(); StringBuffer message = StringBuffer(); message.writeln("echo -e '"); for (var item in printList) { message.writeln(item); } message.write("'"); var temp = await getTempFile(message.toString(), 'sh'); await Process.run('zsh', [temp.path]).then((ProcessResult result) { print(result.stdout); }); await temp.delete(); c.complete(); return c.future; } }