// ignore_for_file: depend_on_referenced_packages import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; 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, redStrong, greenStrong, yellowStrong, blueStrong, magentaStrong, cyanStrong, 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.redStrong: "91", Color.greenStrong: "92", Color.yellowStrong: "93", Color.blueStrong: "94", Color.magentaStrong: "95", Color.cyanStrong: "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.redStrong: "101", Color.greenStrong: "102", Color.yellowStrong: "103", Color.blueStrong: "104", Color.magentaStrong: "105", Color.cyanStrong: "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}) { 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, {Color? color, Color? background}) async { if (color != null || background != null) { for (var i = 0; i < printList.length; ++i) { printList[i] = CLI.style(printList[i], color: color, background: background); } } await printer.printCLI(printList); return simpleFuture; } static Future printBuffer(StringBuffer buffer, {Color? color, Color? background}) async { return await printString(buffer.toString(), color: color, background: background); } static Future printString(String str, {Color? color, Color? background}) async { str = str.replaceAll('\r', ''); return await print(str.split('\n'), color: color, background: background); } static Future println(String str, {Color? color, Color? background}) async { str = str.replaceAll('\n', '').replaceAll('\r', ''); return await printString(str, color: color, background: background); } 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}_${Random().nextInt(1000)}.$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'; } String removeTags(String value) { return value .replaceAll('^', '^^') .replaceAll('<', '^<') .replaceAll('>', '^>') .replaceAll('[', '^[') .replaceAll('╷', '^╷') .replaceAll('│', '^│') .replaceAll('╵', '^╵') .replaceAll(']', '^]') .replaceAll('|', '^|') .replaceAll('\r', '') .replaceAll('\n', ''); } @override Future printCLI(List printList) async { var c = Completer(); StringBuffer message = StringBuffer(); message.writeln('@echo off\r'); message.writeln('chcp 65001 > nul'); message.writeln('setlocal\r'); message.writeln('call :setESC\r'); if (printList.length == 1) { message.writeln('echo | set /p=${removeTags(printList.first)}'); } else { for (var item in printList) { item = removeTags(item); if (item.trim().isEmpty) { message.writeln('echo.\r'); } else { message.writeln('echo $item\r'); } } } message.writeln(':setESC\r'); message.writeln( '''for /F "tokens=1,2 delims=#" %%a in ('"prompt #\$H#\$E# & echo on & for %%b in (1) do rem"') do (\r'''); message.writeln(' set ESC=%%b\r'); message.writeln(' exit /B 0\r'); message.writeln(')\r'); message.writeln('exit /B 0\r'); var temp = await getTempFile(message.toString(), 'bat'); await Process.run('cmd', ['/C', temp.path], stderrEncoding: utf8, stdoutEncoding: utf8) .then((ProcessResult result) { print(result.stdout); String error = result.stderr; if (error.isNotEmpty) { print( '=============== Error ===============\r\n${result.stderr}\r\n\r\nr\n=============== Script ===============\r\n${message.toString()}'); } }); 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(); if (printList.length == 1) { message.write('echo -n "${printList.first}"'); } else { 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; } }