From bf31e7e9276f79911c95e6ba1200863b91e8b378 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Mon, 6 Nov 2023 00:09:26 +0100 Subject: [PATCH 01/19] feat: add `create` command --- src/Classes/Cli/Command/CommandCreate.php | 97 +++++++++++++++++++++++ src/Classes/Cli/Help.php | 6 +- src/Classes/Cli/MmlcCli.php | 21 ++--- 3 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 src/Classes/Cli/Command/CommandCreate.php diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php new file mode 100644 index 00000000..238d2208 --- /dev/null +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace RobinTheHood\ModifiedModuleLoaderClient\Cli\Command; + +use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; + +class CommandCreate +{ + public function __construct() + { + } + + public function run(MmlcCli $cli): void + { + if ($cli->hasOption('-i') || $cli->hasOption('--interactive')) { + $this->createInteractive($cli); + } else { + $this->create($cli); + } + + var_dump($cli->getArgument(0)); + var_dump($cli->getArgument(1)); + var_dump($cli->getArgument(2)); + var_dump($cli->getArgument(3)); + } + + private function create(MmlcCli $cli): void + { + echo "🏗️ \n"; + } + + private function createInteractive(MmlcCli $cli): void + { + echo "👾 \n"; + echo "Type you module name: \n"; + $input = ''; + while (!$input) { + $input = readline(); + echo "Try again: "; + } + echo \PHP_EOL; + echo "Your module name is $input\n"; + } + + public function help() + { + $this->renderHeading('Description:'); + echo " Creates a new module. Can be done interactively.\n"; + echo "\n"; + $this->renderHeading('Usage:'); + echo " create [options] \n"; + echo "\n"; + $this->renderHeading('Arguments:'); + $this->renderOption('archiveName', 'The name of the archive (vendorName/moduleName).'); + echo "\n"; + $this->renderHeading('Options:'); + $this->renderOption('--prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); + $this->renderOption('-i, --interactive', 'Whether to create the module interactively (by answering questions).'); + } + + + private function renderHeading(string $heading): void + { + echo "\e[33m$heading\e[0m\n"; + } + + private function renderOption($name, $description) + { + $name = $this->rightPad($name, 30); + echo " \e[32m$name\e[0m $description\n"; + } + + private function rightPad($text, $totalLength) + { + $textLength = strlen($text); + + if ($textLength >= $totalLength) { + return $text; // Der Text ist bereits länger oder gleich der Ziel-Länge + } + + $paddingLength = $totalLength - $textLength; + $padding = str_repeat(' ', $paddingLength); + + return $text . $padding; + } +} diff --git a/src/Classes/Cli/Help.php b/src/Classes/Cli/Help.php index eddb3ee0..2a634b59 100644 --- a/src/Classes/Cli/Help.php +++ b/src/Classes/Cli/Help.php @@ -14,6 +14,7 @@ namespace RobinTheHood\ModifiedModuleLoaderClient\Cli; use RobinTheHood\ModifiedModuleLoaderClient\App; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandCreate; use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandInfo; use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandList; @@ -130,9 +131,8 @@ public function showCommandHelp($command) echo "Usage: mmlc status Show the status of all installed modules in MMLC.\n"; break; case 'create': - echo "Usage: mmlc create Create a new module in MMLC.\n"; - echo "Options:\n"; - echo " -i, --interactive Start the interactive mode for module creation, where MMLC will ask questions that you need to answer.\n"; + $command = new CommandCreate(); + $command->help(); break; case 'watch': echo "Usage: mmlc watch Automatically detect and apply file changes for module development.\n"; diff --git a/src/Classes/Cli/MmlcCli.php b/src/Classes/Cli/MmlcCli.php index 32fde053..61ba3b43 100644 --- a/src/Classes/Cli/MmlcCli.php +++ b/src/Classes/Cli/MmlcCli.php @@ -13,6 +13,7 @@ namespace RobinTheHood\ModifiedModuleLoaderClient\Cli; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandCreate; use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandInfo; use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandList; use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\CommandWatch; @@ -67,11 +68,7 @@ public function run() $this->moduleStatus(); break; case 'create': - if ($this->hasOption('-i')) { - $this->createModuleInteractive(); - } else { - $this->createModule(); - } + $this->createModule(); break; case 'watch': $this->watchForFileChanges(); @@ -144,12 +141,8 @@ private function moduleStatus() private function createModule() { - // Implement module creation logic - } - - private function createModuleInteractive() - { - // Implement interactive module creation logic + $command = new CommandCreate(); + $command->run($this); } private function watchForFileChanges() @@ -168,19 +161,19 @@ private function selfUpdate() // Implement self-update logic } - private function getCommand() + public function getCommand() { global $argv; return isset($argv[1]) ? $argv[1] : 'help'; } - private function getArgument($index) + public function getArgument($index) { global $argv; return isset($argv[$index]) ? $argv[$index] : null; } - private function hasOption($option) + public function hasOption($option) { global $argv; return in_array($option, $argv); From 693b496f2368fe32700018e7eeb7228c707a6a23 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Mon, 6 Nov 2023 11:14:17 +0100 Subject: [PATCH 02/19] feat: add `archiveName` interaction --- src/Classes/Cli/Command/CommandCreate.php | 44 ++++++++++++++++------- src/Classes/Cli/MmlcCli.php | 22 ++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 238d2208..ec2d6042 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -14,9 +14,12 @@ namespace RobinTheHood\ModifiedModuleLoaderClient\Cli\Command; use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\Create\Argument; class CommandCreate { + private const ARGUMENT_ARCHIVE_NAME = 0; + public function __construct() { } @@ -28,11 +31,6 @@ public function run(MmlcCli $cli): void } else { $this->create($cli); } - - var_dump($cli->getArgument(0)); - var_dump($cli->getArgument(1)); - var_dump($cli->getArgument(2)); - var_dump($cli->getArgument(3)); } private function create(MmlcCli $cli): void @@ -42,15 +40,35 @@ private function create(MmlcCli $cli): void private function createInteractive(MmlcCli $cli): void { - echo "👾 \n"; - echo "Type you module name: \n"; - $input = ''; - while (!$input) { - $input = readline(); - echo "Try again: "; + $archiveName = $cli->getFilteredArgument(self::ARGUMENT_ARCHIVE_NAME); + + if (!$archiveName) { + $vendorName = ''; + + while (!$vendorName) { + echo "1. What is the vendor name?\n"; + echo " Vendor name: "; + + $vendorName = readline(); + + echo "\n"; + } + + $moduleName = ''; + + while (!$moduleName) { + echo "2. What is the module name?\n"; + echo " Module name: "; + + $moduleName = readline(); + + echo "\n"; + } + + $archiveName = $vendorName . '/' . $moduleName; } - echo \PHP_EOL; - echo "Your module name is $input\n"; + + $this->create($cli); } public function help() diff --git a/src/Classes/Cli/MmlcCli.php b/src/Classes/Cli/MmlcCli.php index 61ba3b43..6a9f896c 100644 --- a/src/Classes/Cli/MmlcCli.php +++ b/src/Classes/Cli/MmlcCli.php @@ -173,6 +173,28 @@ public function getArgument($index) return isset($argv[$index]) ? $argv[$index] : null; } + public function getFilteredArgument(int $argumentIndex): string + { + global $argv; + + $arguments = $argv; + $filteredArguments = array(); + + foreach ($arguments as $index => $argument) { + if (0 === $index || 1 === $index) { + continue; + } + + if ('-' === \substr($argument, 0, 1)) { + continue; + } + + $filteredArguments[] = $argument; + } + + return $filteredArguments[$argumentIndex] ?? ''; + } + public function hasOption($option) { global $argv; From 69a029bcd1b62023457f7bb2906e34fa9639dbe9 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Mon, 6 Nov 2023 15:48:29 +0100 Subject: [PATCH 03/19] fix: refactor to match newest upstream changes --- src/Classes/Cli/Command/CommandCreate.php | 51 +++------ src/Classes/Cli/MmlcCli.php | 127 +--------------------- 2 files changed, 17 insertions(+), 161 deletions(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index ec2d6042..7925379a 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -14,9 +14,9 @@ namespace RobinTheHood\ModifiedModuleLoaderClient\Cli\Command; use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; -use RobinTheHood\ModifiedModuleLoaderClient\Cli\Command\Create\Argument; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\TextRenderer; -class CommandCreate +class CommandCreate implements CommandInterface { private const ARGUMENT_ARCHIVE_NAME = 0; @@ -24,6 +24,11 @@ public function __construct() { } + public function getName(): string + { + return 'create'; + } + public function run(MmlcCli $cli): void { if ($cli->hasOption('-i') || $cli->hasOption('--interactive')) { @@ -71,45 +76,19 @@ private function createInteractive(MmlcCli $cli): void $this->create($cli); } - public function help() + public function runHelp(MmlcCli $cli): void { - $this->renderHeading('Description:'); + TextRenderer::renderHelpHeading('Description:'); echo " Creates a new module. Can be done interactively.\n"; echo "\n"; - $this->renderHeading('Usage:'); + TextRenderer::rederHelpArgument('Usage:'); echo " create [options] \n"; echo "\n"; - $this->renderHeading('Arguments:'); - $this->renderOption('archiveName', 'The name of the archive (vendorName/moduleName).'); + TextRenderer::renderHelpHeading('Arguments:'); + TextRenderer::renderHelpOption('archiveName', 'The name of the archive (vendorName/moduleName).'); echo "\n"; - $this->renderHeading('Options:'); - $this->renderOption('--prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); - $this->renderOption('-i, --interactive', 'Whether to create the module interactively (by answering questions).'); - } - - - private function renderHeading(string $heading): void - { - echo "\e[33m$heading\e[0m\n"; - } - - private function renderOption($name, $description) - { - $name = $this->rightPad($name, 30); - echo " \e[32m$name\e[0m $description\n"; - } - - private function rightPad($text, $totalLength) - { - $textLength = strlen($text); - - if ($textLength >= $totalLength) { - return $text; // Der Text ist bereits länger oder gleich der Ziel-Länge - } - - $paddingLength = $totalLength - $textLength; - $padding = str_repeat(' ', $paddingLength); - - return $text . $padding; + TextRenderer::renderHelpHeading('Options:'); + TextRenderer::renderHelpOption('', '--prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); + TextRenderer::renderHelpOption('-i, --interactive', 'Whether to create the module interactively (by answering questions).'); } } diff --git a/src/Classes/Cli/MmlcCli.php b/src/Classes/Cli/MmlcCli.php index 2437d721..60402061 100644 --- a/src/Classes/Cli/MmlcCli.php +++ b/src/Classes/Cli/MmlcCli.php @@ -24,9 +24,10 @@ class MmlcCli extends Cli { public function __construct() { + $this->addCommand(new CommandCreate()); $this->addCommand(new CommandDownload()); - $this->addCommand(new CommandList()); $this->addCommand(new CommandInfo()); + $this->addCommand(new CommandList()); $this->addCommand(new CommandWatch()); } @@ -43,58 +44,6 @@ public function run() $command->run($this); return; } else { - switch ($command) { - case 'download': - $archiveName = $this->getArgument(2); - $this->downloadModule($archiveName); - break; - case 'install': - $archiveName = $this->getArgument(2); - $force = $this->hasOption('-f') || $this->hasOption('--force'); - $this->installModule($archiveName, $force); - break; - case 'update': - $archiveName = $this->getArgument(2); - $force = $this->hasOption('-f') || $this->hasOption('--force'); - $this->updateModule($archiveName, $force); - break; - case 'uninstall': - $archiveName = $this->getArgument(2); - $force = $this->hasOption('-f') || $this->hasOption('--force'); - $this->uninstallModule($archiveName, $force); - break; - case 'list': - $this->listModules(); - break; - case 'search': - $searchTerm = $this->getArgument(2); - $this->searchModules($searchTerm); - break; - case 'info': - $archiveName = $this->getArgument(2); - $this->moduleInfo($archiveName); - break; - case 'status': - $this->moduleStatus(); - break; - case 'create': - $this->createModule(); - break; - case 'watch': - $this->watchForFileChanges(); - break; - case 'discard': - $archiveName = $this->getArgument(2); - $force = $this->hasOption('-f') || $this->hasOption('--force'); - $this->discardChanges($archiveName, $force); - break; - case 'self-update': - $this->selfUpdate(); - break; - default: - $this->showHelp(); - break; - } $this->runHelp(); } } @@ -171,79 +120,7 @@ private function getCurrentGitBranch(string $gitPath): ?string if (empty($output)) { return null; } - } - - private function moduleInfo($archiveName) - { - $command = new CommandInfo(); - $command->run($archiveName); - } - private function moduleStatus() - { - // Implement displaying module status - } - - private function createModule() - { - $command = new CommandCreate(); - $command->run($this); - } - - private function watchForFileChanges() - { - $command = new CommandWatch(); - $command->run(); - } - - private function discardChanges($archiveName, $force = false) - { - // Implement discard changes logic - } - - private function selfUpdate() - { - // Implement self-update logic - } - - public function getCommand() - { - global $argv; - return isset($argv[1]) ? $argv[1] : 'help'; - } - - public function getArgument($index) - { - global $argv; - return isset($argv[$index]) ? $argv[$index] : null; - } - - public function getFilteredArgument(int $argumentIndex): string - { - global $argv; - - $arguments = $argv; - $filteredArguments = array(); - - foreach ($arguments as $index => $argument) { - if (0 === $index || 1 === $index) { - continue; - } - - if ('-' === \substr($argument, 0, 1)) { - continue; - } - - $filteredArguments[] = $argument; - } - - return $filteredArguments[$argumentIndex] ?? ''; - } - - public function hasOption($option) - { - global $argv; - return in_array($option, $argv); return $output; } } From a3b796d2d92de80d74df522207742f9ab47acd13 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Mon, 6 Nov 2023 16:10:48 +0100 Subject: [PATCH 04/19] fix: missing arguments --- src/Classes/Cli/Command/CommandCreate.php | 18 +++++++++++++----- src/Classes/Cli/TextRenderer.php | 6 +++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 7925379a..034556ad 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -78,17 +78,25 @@ private function createInteractive(MmlcCli $cli): void public function runHelp(MmlcCli $cli): void { + $padding = 27; + + echo "\n"; TextRenderer::renderHelpHeading('Description:'); echo " Creates a new module. Can be done interactively.\n"; echo "\n"; - TextRenderer::rederHelpArgument('Usage:'); - echo " create [options] \n"; + + TextRenderer::renderHelpArgument('Usage:', 'create [options] ', $padding); echo "\n"; + TextRenderer::renderHelpHeading('Arguments:'); - TextRenderer::renderHelpOption('archiveName', 'The name of the archive (vendorName/moduleName).'); + TextRenderer::renderHelpOption('', 'archiveName', 'The name of the archive (vendorName/moduleName).', $padding); echo "\n"; + TextRenderer::renderHelpHeading('Options:'); - TextRenderer::renderHelpOption('', '--prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); - TextRenderer::renderHelpOption('-i, --interactive', 'Whether to create the module interactively (by answering questions).'); + TextRenderer::renderHelpOption('', 'prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.', $padding); + TextRenderer::renderHelpOption('i', 'interactive', 'Whether to create the module interactively (by answering questions).', $padding); + echo "\n"; + + echo "Read more at https://module-loader.de/documentation.php\n"; } } diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index ff4c161e..08dd44ae 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -45,13 +45,13 @@ public static function renderHelpHeading(string $heading): void public static function renderHelpCommand(string $name, string $description, int $pad = 20) { - $name = self::rightPad($name, 20); + $name = self::rightPad($name, $pad); echo " " . self::color($name, self::COLOR_GREEN) . " $description\n"; } public static function renderHelpArgument(string $name, string $description, int $pad = 20) { - $name = self::rightPad($name, 20); + $name = self::rightPad($name, $pad); echo " " . self::color($name, self::COLOR_GREEN) . " $description\n"; } @@ -67,7 +67,7 @@ public static function renderHelpOption(string $shortName, string $longName, str $name = " --$longName"; } - $name = self::rightPad($name, 20); + $name = self::rightPad($name, $pad); echo " " . self::color($name, self::COLOR_GREEN) . " $description\n"; } From d6d5d5826b002d49b5e715ab7b8d7db5669f0a26 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 7 Nov 2023 17:44:03 +0100 Subject: [PATCH 05/19] refactor: add `HelpRenderer` --- src/Classes/Cli/Command/CommandCreate.php | 31 +++---- src/Classes/Cli/HelpRenderer.php | 103 ++++++++++++++++++++++ src/Classes/Cli/TextRenderer.php | 59 +++++-------- 3 files changed, 137 insertions(+), 56 deletions(-) create mode 100644 src/Classes/Cli/HelpRenderer.php diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 034556ad..be280d69 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -15,6 +15,7 @@ use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; use RobinTheHood\ModifiedModuleLoaderClient\Cli\TextRenderer; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\HelpRenderer; class CommandCreate implements CommandInterface { @@ -76,27 +77,15 @@ private function createInteractive(MmlcCli $cli): void $this->create($cli); } - public function runHelp(MmlcCli $cli): void + public function getHelp(MmlcCli $cli): string { - $padding = 27; - - echo "\n"; - TextRenderer::renderHelpHeading('Description:'); - echo " Creates a new module. Can be done interactively.\n"; - echo "\n"; - - TextRenderer::renderHelpArgument('Usage:', 'create [options] ', $padding); - echo "\n"; - - TextRenderer::renderHelpHeading('Arguments:'); - TextRenderer::renderHelpOption('', 'archiveName', 'The name of the archive (vendorName/moduleName).', $padding); - echo "\n"; - - TextRenderer::renderHelpHeading('Options:'); - TextRenderer::renderHelpOption('', 'prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.', $padding); - TextRenderer::renderHelpOption('i', 'interactive', 'Whether to create the module interactively (by answering questions).', $padding); - echo "\n"; - - echo "Read more at https://module-loader.de/documentation.php\n"; + $renderer = new HelpRenderer(); + $renderer->setDescription('Creates a new module. Can be done interactively. Read more at https://module-loader.de/documentation.php.'); + $renderer->addArgument('description', 'Usage:', 'create [options] '); + $renderer->addArgument('arguments', 'archiveName:', 'The name of the archive (vendorName/moduleName).'); + $renderer->addArgument('options', '--prefix=VENDOR_PREFIX:', 'Usually an abbreviated vendorName. Can also be vendorName.'); + $renderer->addArgument('options', '-i, --interactive', 'Whether to create the module interactively (by answering questions).'); + + return $renderer->getRender(); } } diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php new file mode 100644 index 00000000..dc6750b9 --- /dev/null +++ b/src/Classes/Cli/HelpRenderer.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace RobinTheHood\ModifiedModuleLoaderClient\Cli; + +class HelpRenderer +{ + private const INDENT = ' '; + private string $description = ''; + private array $arguments = array(); + + public function setDescription(string $description): void + { + $this->description = $description; + } + + public function addArgument(string $section, string $name, string $description, int $pad = 20) + { + $this->arguments[$section][$name] = $description; + } + + public function getRender(): string + { + $render = ''; + + $render .= $this->getDescription(); + $render .= $this->getArguments(); + $render .= $this->getOptions(); + + return $render; + } + + private function getDescription(): string + { + if (empty($this->arguments['description'])) { + return ''; + } + + $items = \array_keys($this->arguments['description']); + $padding = TextRenderer::getPadding($items); + + $description = \PHP_EOL; + $description .= TextRenderer::color('Description', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $description .= self::INDENT . $this->description . \PHP_EOL . \PHP_EOL; + + foreach ($this->arguments['description'] as $argument => $argumentDescription) { + $name = self::INDENT . TextRenderer::rightPad($argument, $padding); + $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $argumentDescription . \PHP_EOL; + + $description .= $text; + } + + return $description; + } + + private function getArguments(): string + { + if (empty($this->arguments['arguments'])) { + return ''; + } + + $items = \array_keys($this->arguments['arguments']); + $padding = TextRenderer::getPadding($items); + + $arguments = \PHP_EOL; + $arguments .= TextRenderer::color('Arguments', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + + foreach ($this->arguments['arguments'] as $argumentName => $argumentDescription) { + $arguments .= self::INDENT . TextRenderer::rightPad($argumentName, $padding) . $argumentDescription . \PHP_EOL; + } + + return $arguments; + } + + private function getOptions(): string + { + if (empty($this->arguments['options'])) { + return ''; + } + + $items = \array_keys($this->arguments['options']); + $padding = TextRenderer::getPadding($items); + + $arguments = \PHP_EOL; + $arguments .= TextRenderer::color('Options', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + + foreach ($this->arguments['options'] as $argument => $description) { + $arguments .= self::INDENT . TextRenderer::rightPad($argument, $padding) . $description . \PHP_EOL; + } + + return $arguments; + } +} diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index 3eb45202..97132010 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -24,50 +24,39 @@ public static function color(string $text, int $color): string return "\e[" . $color . "m" . $text . "\e[0m"; } - public static function rightPad(string $text, int $totalLength): string + public static function rightPad(string $text, int $length): string { - $textLength = strlen($text); - - if ($textLength >= $totalLength) { - return $text; - } - - $paddingLength = $totalLength - $textLength; - $padding = str_repeat(' ', $paddingLength); - - return $text . $padding; + return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); } - public static function renderHelpHeading(string $heading): string + public static function renderLogo() { - return self::color($heading, self::COLOR_YELLOW) . "\n"; + // echo " __ _____ _____ ______ ________ ____\n"; + // echo " / |/ / |/ / / / ____/ / ____/ / / _/\n"; + // echo " / /|_/ / /|_/ / / / / / / / / / / \n"; + // echo " / / / / / / / /___/ /___ / /___/ /____/ / \n"; + // echo "/_/ /_/_/ /_/_____/\____/ \____/_____/___/ \n"; + // created with: https://patorjk.com/software/taag/#p=display&f=Slant&t=MMLC%20CLI + + echo " __ ___ __ ___ __ ______ ______ __ ____\n"; + echo " / |/ // |/ // / / ____/ / ____// / / _/\n"; + echo " / /|_/ // /|_/ // / / / / / / / / / \n"; + echo " / / / // / / // /___/ /___ / /___ / /___ _/ / \n"; + echo "/_/ /_//_/ /_//_____/\____/ \____//_____//___/ \n"; + // cretated with: https://patorjk.com/software/taag/#p=display&h=1&f=Slant&t=MMLC%20CLI } - public static function renderHelpCommand(string $name, string $description, int $pad = 20): string + public static function getPadding(array $items): int { - $name = self::rightPad($name, $pad); - return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; - } + $padding = 0; - public static function renderHelpArgument(string $name, string $description, int $pad = 20): string - { - $name = self::rightPad($name, $pad); - return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; - } - - public static function renderHelpOption(string $shortName, string $longName, string $description, int $pad = 20): string - { - $name = ''; - - if ($shortName && $longName) { - $name = "-$shortName, --$longName"; - } elseif ($shortName) { - $name = "-$shortName"; - } elseif ($longName) { - $name = " --$longName"; + foreach ($items as $item) { + $itemLength = \mb_strlen($item); + $padding = \max($padding, $itemLength); } - $name = self::rightPad($name, $pad); - return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; + $padding += 1; + + return $padding; } } From 8a562e7141cf08823f9117a257ebefadfe8fcc5a Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 7 Nov 2023 17:50:09 +0100 Subject: [PATCH 06/19] refactor: fix indentation --- src/Classes/Cli/MmlcCli.php | 60 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Classes/Cli/MmlcCli.php b/src/Classes/Cli/MmlcCli.php index 01bba87a..acb8830a 100644 --- a/src/Classes/Cli/MmlcCli.php +++ b/src/Classes/Cli/MmlcCli.php @@ -55,36 +55,36 @@ private function getHelp() { $this->writeLine( $this->renderLogo() - . "\n" - - . $this->renderVersion() - . "\n" - - . TextRenderer::renderHelpHeading('Usage:') - . " command [options]\n" - . "\n" - - . TextRenderer::renderHelpHeading('Options:') - . TextRenderer::renderHelpOption('h', 'help', 'Display help for the given command.') - . TextRenderer::renderHelpOption('v', 'version', 'Display this application version.') - . "\n" - - . TextRenderer::renderHelpHeading('Commands:') - . TextRenderer::renderHelpCommand('download', 'Download the latest version of module.') - . TextRenderer::renderHelpCommand('install', 'Download and install a module in your shop. Use the -f or --force option to enforce.') - . TextRenderer::renderHelpCommand('update', 'Update an already installed module to the latest version. Use the -f or --force option to enforce.') - . TextRenderer::renderHelpCommand('uninstall', 'Uninstall a module from your shop. Use the -f or --force option to enforce.') - . TextRenderer::renderHelpCommand('list', 'List all available modules that can be used with MMLC.') - . TextRenderer::renderHelpCommand('search', 'Search for modules based on a specific search term.') - . TextRenderer::renderHelpCommand('info', 'Display information and details for a specific module.') - . TextRenderer::renderHelpCommand('status', 'Show the status of all installed modules in MMLC.') - . TextRenderer::renderHelpCommand('create', 'Create a new module in MMLC. Use the -i option for the interactive mode.') - . TextRenderer::renderHelpCommand('watch', 'Automatically detect and apply file changes for module development.') - . TextRenderer::renderHelpCommand('discard', 'Discard changes to a module. Use the -f or --force option to enforce.') - . TextRenderer::renderHelpCommand('self-update', 'Updates MMLC to the latest version.') - . "\n" - - . "Read more at https://module-loader.de/documentation.php" + . "\n" + + . $this->renderVersion() + . "\n" + + . TextRenderer::renderHelpHeading('Usage:') + . " command [options]\n" + . "\n" + + . TextRenderer::renderHelpHeading('Options:') + . TextRenderer::renderHelpOption('h', 'help', 'Display help for the given command.') + . TextRenderer::renderHelpOption('v', 'version', 'Display this application version.') + . "\n" + + . TextRenderer::renderHelpHeading('Commands:') + . TextRenderer::renderHelpCommand('download', 'Download the latest version of module.') + . TextRenderer::renderHelpCommand('install', 'Download and install a module in your shop. Use the -f or --force option to enforce.') + . TextRenderer::renderHelpCommand('update', 'Update an already installed module to the latest version. Use the -f or --force option to enforce.') + . TextRenderer::renderHelpCommand('uninstall', 'Uninstall a module from your shop. Use the -f or --force option to enforce.') + . TextRenderer::renderHelpCommand('list', 'List all available modules that can be used with MMLC.') + . TextRenderer::renderHelpCommand('search', 'Search for modules based on a specific search term.') + . TextRenderer::renderHelpCommand('info', 'Display information and details for a specific module.') + . TextRenderer::renderHelpCommand('status', 'Show the status of all installed modules in MMLC.') + . TextRenderer::renderHelpCommand('create', 'Create a new module in MMLC. Use the -i option for the interactive mode.') + . TextRenderer::renderHelpCommand('watch', 'Automatically detect and apply file changes for module development.') + . TextRenderer::renderHelpCommand('discard', 'Discard changes to a module. Use the -f or --force option to enforce.') + . TextRenderer::renderHelpCommand('self-update', 'Updates MMLC to the latest version.') + . "\n" + + . "Read more at https://module-loader.de/documentation.php" ); } From 80a578659de916c8da63f85f50569a99d610787d Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 14:13:53 +0100 Subject: [PATCH 07/19] refactor: add specialised methods, rename `getPadding` --- src/Classes/Cli/Command/CommandCreate.php | 10 +- src/Classes/Cli/HelpRenderer.php | 109 ++++++++++++++++------ src/Classes/Cli/TextRenderer.php | 12 +-- 3 files changed, 93 insertions(+), 38 deletions(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index be280d69..2762525f 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -81,11 +81,11 @@ public function getHelp(MmlcCli $cli): string { $renderer = new HelpRenderer(); $renderer->setDescription('Creates a new module. Can be done interactively. Read more at https://module-loader.de/documentation.php.'); - $renderer->addArgument('description', 'Usage:', 'create [options] '); - $renderer->addArgument('arguments', 'archiveName:', 'The name of the archive (vendorName/moduleName).'); - $renderer->addArgument('options', '--prefix=VENDOR_PREFIX:', 'Usually an abbreviated vendorName. Can also be vendorName.'); - $renderer->addArgument('options', '-i, --interactive', 'Whether to create the module interactively (by answering questions).'); + $renderer->setUsage('create', '[options] '); + $renderer->addArgument('archiveName', 'The name of the archive (vendorName/moduleName).'); + $renderer->addOption('', 'prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); + $renderer->addOption('i', 'interactive', 'Whether to create the module interactively (by answering questions).'); - return $renderer->getRender(); + return $renderer->render(); } } diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index dc6750b9..12945f6b 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -17,85 +17,142 @@ class HelpRenderer { private const INDENT = ' '; private string $description = ''; - private array $arguments = array(); + private array $arguments = []; public function setDescription(string $description): void { $this->description = $description; } - public function addArgument(string $section, string $name, string $description, int $pad = 20) + public function setUsage(string $command, string $description): void { - $this->arguments[$section][$name] = $description; + $this->arguments['usage'][$command] = $description; } - public function getRender(): string + public function addArgument(string $argument, string $description): void + { + $this->arguments['arguments'][$argument] = $description; + } + + public function addOption(string $short, string $long, string $description): void + { + $options = [$short, $long]; + + /** Discard empty options */ + $options = \array_filter( + $options, + function ($option) { + return !empty($option); + } + ); + + /** Add dash (`-`) to remaining options */ + $options = \array_map( + function ($value) { + switch (\mb_strlen($value)) { + case 1: + return '-' . $value; + break; + + default: + return '--' . $value; + break; + } + }, + $options + ); + + $combined = \implode(', ', $options); + + if (empty($short)) { + $combined = ' ' . $combined; + } + + $this->arguments['options'][$combined] = $description; + } + + public function render(): string { $render = ''; - $render .= $this->getDescription(); - $render .= $this->getArguments(); - $render .= $this->getOptions(); + $render .= $this->renderDescription(); + $render .= $this->renderUsage(); + $render .= $this->renderArguments(); + $render .= $this->renderOptions(); return $render; } - private function getDescription(): string + private function renderDescription(): string { - if (empty($this->arguments['description'])) { + $description = \PHP_EOL; + $description .= TextRenderer::color('Description:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $description .= self::INDENT . $this->description . \PHP_EOL; + + return $description; + } + + private function renderUsage(): string + { + if (empty($this->arguments['usage'])) { return ''; } - $items = \array_keys($this->arguments['description']); - $padding = TextRenderer::getPadding($items); + $items = \array_keys($this->arguments['usage']); + $maxLength = TextRenderer::getMaxLength($items) + 1; - $description = \PHP_EOL; - $description .= TextRenderer::color('Description', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - $description .= self::INDENT . $this->description . \PHP_EOL . \PHP_EOL; + $usage = \PHP_EOL; + $usage .= TextRenderer::color('Usage:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - foreach ($this->arguments['description'] as $argument => $argumentDescription) { - $name = self::INDENT . TextRenderer::rightPad($argument, $padding); + foreach ($this->arguments['usage'] as $argument => $argumentDescription) { + $name = self::INDENT . TextRenderer::rightPad($argument, $maxLength); $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $argumentDescription . \PHP_EOL; - $description .= $text; + $usage .= $text; } - return $description; + return $usage; } - private function getArguments(): string + private function renderArguments(): string { if (empty($this->arguments['arguments'])) { return ''; } $items = \array_keys($this->arguments['arguments']); - $padding = TextRenderer::getPadding($items); + $maxLength = TextRenderer::getMaxLength($items) + 1; $arguments = \PHP_EOL; - $arguments .= TextRenderer::color('Arguments', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $arguments .= TextRenderer::color('Arguments:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; foreach ($this->arguments['arguments'] as $argumentName => $argumentDescription) { - $arguments .= self::INDENT . TextRenderer::rightPad($argumentName, $padding) . $argumentDescription . \PHP_EOL; + $name = self::INDENT . TextRenderer::rightPad($argumentName, $maxLength); + $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $argumentDescription . \PHP_EOL; + + $arguments .= $text; } return $arguments; } - private function getOptions(): string + private function renderOptions(): string { if (empty($this->arguments['options'])) { return ''; } $items = \array_keys($this->arguments['options']); - $padding = TextRenderer::getPadding($items); + $maxLength = TextRenderer::getMaxLength($items) + 1; $arguments = \PHP_EOL; - $arguments .= TextRenderer::color('Options', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $arguments .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; foreach ($this->arguments['options'] as $argument => $description) { - $arguments .= self::INDENT . TextRenderer::rightPad($argument, $padding) . $description . \PHP_EOL; + $name = self::INDENT . TextRenderer::rightPad($argument, $maxLength); + $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $description . \PHP_EOL; + + $arguments .= $text; } return $arguments; diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index 97132010..d885825f 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -46,17 +46,15 @@ public static function renderLogo() // cretated with: https://patorjk.com/software/taag/#p=display&h=1&f=Slant&t=MMLC%20CLI } - public static function getPadding(array $items): int + public static function getMaxLength(array $items): int { - $padding = 0; + $maxLength = 0; foreach ($items as $item) { - $itemLength = \mb_strlen($item); - $padding = \max($padding, $itemLength); + $currentLength = \mb_strlen($item); + $maxLength = \max($maxLength, $currentLength); } - $padding += 1; - - return $padding; + return $maxLength; } } From 3ae50ce722ca1aadb9c30d7f2cd0c1cc20f76fe2 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 14:16:07 +0100 Subject: [PATCH 08/19] fix: remove duplicate command --- src/Classes/Cli/MmlcCli.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Classes/Cli/MmlcCli.php b/src/Classes/Cli/MmlcCli.php index eb27f36a..7c2f18c9 100644 --- a/src/Classes/Cli/MmlcCli.php +++ b/src/Classes/Cli/MmlcCli.php @@ -38,7 +38,6 @@ public function __construct() $this->addCommand(new CommandDelete()); $this->addCommand(new CommandList()); $this->addCommand(new CommandInfo()); - $this->addCommand(new CommandList()); $this->addCommand(new CommandWatch()); } From 6f44386a460f580805845cf3dfb4b28202791055 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 14:16:57 +0100 Subject: [PATCH 09/19] refactor: remove unused method `renderLogo` --- src/Classes/Cli/TextRenderer.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index d885825f..b2acb731 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -29,23 +29,6 @@ public static function rightPad(string $text, int $length): string return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); } - public static function renderLogo() - { - // echo " __ _____ _____ ______ ________ ____\n"; - // echo " / |/ / |/ / / / ____/ / ____/ / / _/\n"; - // echo " / /|_/ / /|_/ / / / / / / / / / / \n"; - // echo " / / / / / / / /___/ /___ / /___/ /____/ / \n"; - // echo "/_/ /_/_/ /_/_____/\____/ \____/_____/___/ \n"; - // created with: https://patorjk.com/software/taag/#p=display&f=Slant&t=MMLC%20CLI - - echo " __ ___ __ ___ __ ______ ______ __ ____\n"; - echo " / |/ // |/ // / / ____/ / ____// / / _/\n"; - echo " / /|_/ // /|_/ // / / / / / / / / / \n"; - echo " / / / // / / // /___/ /___ / /___ / /___ _/ / \n"; - echo "/_/ /_//_/ /_//_____/\____/ \____//_____//___/ \n"; - // cretated with: https://patorjk.com/software/taag/#p=display&h=1&f=Slant&t=MMLC%20CLI - } - public static function getMaxLength(array $items): int { $maxLength = 0; From 208e13524b12c3ce0d4546c568267bbe78013cf1 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 14:28:28 +0100 Subject: [PATCH 10/19] fix: re-add required render methods --- src/Classes/Cli/TextRenderer.php | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index b2acb731..b1e98777 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -40,4 +40,72 @@ public static function getMaxLength(array $items): int return $maxLength; } + + /** + * @deprecated 1.21.0 Use a `HelpRenderer` instead. + * + * @param string $heading + * + * @return string + */ + public static function renderHelpHeading(string $heading): string + { + return self::color($heading, self::COLOR_YELLOW) . "\n"; + } + + /** + * @deprecated 1.21.0 Use a `HelpRenderer` instead. + * + * @param string $name + * @param string $description + * @param int $pad + * + * @return string + */ + public static function renderHelpCommand(string $name, string $description, int $pad = 20): string + { + $name = self::rightPad($name, $pad); + return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; + } + + /** + * @deprecated 1.21.0 Use a `HelpRenderer` instead. + * + * @param string $name + * @param string $description + * @param int $pad + * + * @return string + */ + public static function renderHelpArgument(string $name, string $description, int $pad = 20): string + { + $name = self::rightPad($name, $pad); + return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; + } + + /** + * @deprecated 1.21.0 Use a `HelpRenderer` instead. + * + * @param string $shortName + * @param string $longName + * @param string $description + * @param int $pad + * + * @return string + */ + public static function renderHelpOption(string $shortName, string $longName, string $description, int $pad = 20): string + { + $name = ''; + + if ($shortName && $longName) { + $name = "-$shortName, --$longName"; + } elseif ($shortName) { + $name = "-$shortName"; + } elseif ($longName) { + $name = " --$longName"; + } + + $name = self::rightPad($name, $pad); + return " " . self::color($name, self::COLOR_GREEN) . " $description\n"; + } } From 118a28fccca0c7ea252dcb665cf23a4e6953678b Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 16:51:50 +0100 Subject: [PATCH 11/19] feat: automatically pad options and description --- src/Classes/Cli/Command/CommandCreate.php | 1 + src/Classes/Cli/HelpRenderer.php | 127 +++++++++++++++------- src/Classes/Cli/TextRenderer.php | 5 + 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 2762525f..6ad99530 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -85,6 +85,7 @@ public function getHelp(MmlcCli $cli): string $renderer->addArgument('archiveName', 'The name of the archive (vendorName/moduleName).'); $renderer->addOption('', 'prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); $renderer->addOption('i', 'interactive', 'Whether to create the module interactively (by answering questions).'); + $renderer->addOption('', '', 'Test with no option.'); return $renderer->render(); } diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index 12945f6b..ad783332 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -36,39 +36,13 @@ public function addArgument(string $argument, string $description): void public function addOption(string $short, string $long, string $description): void { - $options = [$short, $long]; + $option = $short . $long; - /** Discard empty options */ - $options = \array_filter( - $options, - function ($option) { - return !empty($option); - } - ); - - /** Add dash (`-`) to remaining options */ - $options = \array_map( - function ($value) { - switch (\mb_strlen($value)) { - case 1: - return '-' . $value; - break; - - default: - return '--' . $value; - break; - } - }, - $options - ); - - $combined = \implode(', ', $options); - - if (empty($short)) { - $combined = ' ' . $combined; - } - - $this->arguments['options'][$combined] = $description; + $this->arguments['options'][$option] = [ + 'short' => $short, + 'long' => $long, + 'description' => $description, + ]; } public function render(): string @@ -142,19 +116,96 @@ private function renderOptions(): string return ''; } - $items = \array_keys($this->arguments['options']); - $maxLength = TextRenderer::getMaxLength($items) + 1; - $arguments = \PHP_EOL; $arguments .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - foreach ($this->arguments['options'] as $argument => $description) { - $name = self::INDENT . TextRenderer::rightPad($argument, $maxLength); - $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $description . \PHP_EOL; + $padLeftLength = self::getMaxLengthOptionsLeft($this->arguments['options']) + 1; + $padRightLength = self::getMaxLengthOptionsRight($this->arguments['options']) + 1; + + foreach ($this->arguments['options'] as $option) { + $name = TextRenderer::leftPad('', $padLeftLength); + + if ($option['short'] && $option['long']) { + $short = '-' . $option['short']; + $long = '--' . $option['long']; + + $name = TextRenderer::leftPad($short . ', ' . $long, 2); + } elseif ($option['short']) { + $short = TextRenderer::rightPad('-' . $option['short'], 3); + + $name = $short; + } elseif ($option['long']) { + $long = TextRenderer::rightPad('--' . $option['long'], 3); + $name = TextRenderer::leftPad($long, $padLeftLength); + } + + $name = TextRenderer::rightPad($name, $padRightLength); + $text = self::INDENT . TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $option['description'] . \PHP_EOL; $arguments .= $text; } return $arguments; } + + private static function optionExists(array $options, string $shortOrLong): bool { + foreach ($options as $option) { + if ($option[$shortOrLong]) { + return true; + } + } + + return false; + } + + private static function getMaxLengthOptionsLeft(array $options): int + { + $maxLength = 0; + + $shortOptionExists = self::optionExists($options, 'short'); + $longOptionExists = self::optionExists($options, 'long'); + + foreach ($options as $option) { + $shortLength = \mb_strlen($option['short']); + $longLength = \mb_strlen($option['long']); + $currentLength = max($shortLength, $longLength); + + $maxLength = \max($maxLength, $currentLength); + } + + if ($shortOptionExists && $longOptionExists) { + $maxLength += 5; + } elseif ($shortOptionExists) { + $maxLength += 1; + } elseif ($longOptionExists) { + return 0; + } + + return $maxLength; + } + + private static function getMaxLengthOptionsRight(array $options): int + { + $maxLength = 0; + + $shortOptionExists = self::optionExists($options, 'short'); + $longOptionExists = self::optionExists($options, 'long'); + + foreach ($options as $option) { + $shortLength = \mb_strlen($option['short']); + $longLength = \mb_strlen($option['long']); + $currentLength = max($shortLength, $longLength); + + $maxLength = \max($maxLength, $currentLength); + } + + if ($shortOptionExists && $longOptionExists) { + $maxLength += 6; + } elseif ($shortOptionExists) { + } elseif ($longOptionExists) { + $maxLength += 3; + } + + return $maxLength; + } } diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index b1e98777..089ef15b 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -29,6 +29,11 @@ public static function rightPad(string $text, int $length): string return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); } + public static function leftPad(string $text, int $length): string + { + return \str_pad($text, $length, ' ', \STR_PAD_LEFT); + } + public static function getMaxLength(array $items): int { $maxLength = 0; From d76011cb062322b9f561f5fde6ba9ee7b9943a29 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 14 Nov 2023 16:56:50 +0100 Subject: [PATCH 12/19] refactor: rename property `arguments` to `sections` --- src/Classes/Cli/HelpRenderer.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index ad783332..8981eb73 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -17,7 +17,7 @@ class HelpRenderer { private const INDENT = ' '; private string $description = ''; - private array $arguments = []; + private array $sections = []; public function setDescription(string $description): void { @@ -26,19 +26,19 @@ public function setDescription(string $description): void public function setUsage(string $command, string $description): void { - $this->arguments['usage'][$command] = $description; + $this->sections['usage'][$command] = $description; } public function addArgument(string $argument, string $description): void { - $this->arguments['arguments'][$argument] = $description; + $this->sections['arguments'][$argument] = $description; } public function addOption(string $short, string $long, string $description): void { $option = $short . $long; - $this->arguments['options'][$option] = [ + $this->sections['options'][$option] = [ 'short' => $short, 'long' => $long, 'description' => $description, @@ -68,17 +68,17 @@ private function renderDescription(): string private function renderUsage(): string { - if (empty($this->arguments['usage'])) { + if (empty($this->sections['usage'])) { return ''; } - $items = \array_keys($this->arguments['usage']); + $items = \array_keys($this->sections['usage']); $maxLength = TextRenderer::getMaxLength($items) + 1; $usage = \PHP_EOL; $usage .= TextRenderer::color('Usage:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - foreach ($this->arguments['usage'] as $argument => $argumentDescription) { + foreach ($this->sections['usage'] as $argument => $argumentDescription) { $name = self::INDENT . TextRenderer::rightPad($argument, $maxLength); $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $argumentDescription . \PHP_EOL; @@ -90,17 +90,17 @@ private function renderUsage(): string private function renderArguments(): string { - if (empty($this->arguments['arguments'])) { + if (empty($this->sections['arguments'])) { return ''; } - $items = \array_keys($this->arguments['arguments']); + $items = \array_keys($this->sections['arguments']); $maxLength = TextRenderer::getMaxLength($items) + 1; $arguments = \PHP_EOL; $arguments .= TextRenderer::color('Arguments:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - foreach ($this->arguments['arguments'] as $argumentName => $argumentDescription) { + foreach ($this->sections['arguments'] as $argumentName => $argumentDescription) { $name = self::INDENT . TextRenderer::rightPad($argumentName, $maxLength); $text = TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $argumentDescription . \PHP_EOL; @@ -112,17 +112,17 @@ private function renderArguments(): string private function renderOptions(): string { - if (empty($this->arguments['options'])) { + if (empty($this->sections['options'])) { return ''; } $arguments = \PHP_EOL; $arguments .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - $padLeftLength = self::getMaxLengthOptionsLeft($this->arguments['options']) + 1; - $padRightLength = self::getMaxLengthOptionsRight($this->arguments['options']) + 1; + $padLeftLength = self::getMaxLengthOptionsLeft($this->sections['options']) + 1; + $padRightLength = self::getMaxLengthOptionsRight($this->sections['options']) + 1; - foreach ($this->arguments['options'] as $option) { + foreach ($this->sections['options'] as $option) { $name = TextRenderer::leftPad('', $padLeftLength); if ($option['short'] && $option['long']) { From 42be4613d87e51bbfd6fd08ffe84e0c064ab3af0 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 11:29:56 +0100 Subject: [PATCH 13/19] refactor: simply code The formatting doesn't currently work properly when there is no short option and only long options --- src/Classes/Cli/HelpRenderer.php | 98 ++++++-------------------------- 1 file changed, 18 insertions(+), 80 deletions(-) diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index 8981eb73..f37cb57c 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -37,10 +37,20 @@ public function addArgument(string $argument, string $description): void public function addOption(string $short, string $long, string $description): void { $option = $short . $long; + $formatted = ''; + + if ($short && $long) { + $formatted = "-$short, --$long"; + } elseif ($short) { + $formatted = "-$short"; + } elseif ($long) { + $formatted = " --$long"; + } $this->sections['options'][$option] = [ 'short' => $short, 'long' => $long, + 'formatted' => $formatted, 'description' => $description, ]; } @@ -119,27 +129,16 @@ private function renderOptions(): string $arguments = \PHP_EOL; $arguments .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - $padLeftLength = self::getMaxLengthOptionsLeft($this->sections['options']) + 1; - $padRightLength = self::getMaxLengthOptionsRight($this->sections['options']) + 1; + $optionsFormatted = \array_map( + function ($option) { + return $option['formatted']; + }, + $this->sections['options'] + ); + $optionsPadding = TextRenderer::getMaxLength($optionsFormatted) + 1; foreach ($this->sections['options'] as $option) { - $name = TextRenderer::leftPad('', $padLeftLength); - - if ($option['short'] && $option['long']) { - $short = '-' . $option['short']; - $long = '--' . $option['long']; - - $name = TextRenderer::leftPad($short . ', ' . $long, 2); - } elseif ($option['short']) { - $short = TextRenderer::rightPad('-' . $option['short'], 3); - - $name = $short; - } elseif ($option['long']) { - $long = TextRenderer::rightPad('--' . $option['long'], 3); - $name = TextRenderer::leftPad($long, $padLeftLength); - } - - $name = TextRenderer::rightPad($name, $padRightLength); + $name = TextRenderer::rightPad($option['formatted'], $optionsPadding); $text = self::INDENT . TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $option['description'] . \PHP_EOL; $arguments .= $text; @@ -147,65 +146,4 @@ private function renderOptions(): string return $arguments; } - - private static function optionExists(array $options, string $shortOrLong): bool { - foreach ($options as $option) { - if ($option[$shortOrLong]) { - return true; - } - } - - return false; - } - - private static function getMaxLengthOptionsLeft(array $options): int - { - $maxLength = 0; - - $shortOptionExists = self::optionExists($options, 'short'); - $longOptionExists = self::optionExists($options, 'long'); - - foreach ($options as $option) { - $shortLength = \mb_strlen($option['short']); - $longLength = \mb_strlen($option['long']); - $currentLength = max($shortLength, $longLength); - - $maxLength = \max($maxLength, $currentLength); - } - - if ($shortOptionExists && $longOptionExists) { - $maxLength += 5; - } elseif ($shortOptionExists) { - $maxLength += 1; - } elseif ($longOptionExists) { - return 0; - } - - return $maxLength; - } - - private static function getMaxLengthOptionsRight(array $options): int - { - $maxLength = 0; - - $shortOptionExists = self::optionExists($options, 'short'); - $longOptionExists = self::optionExists($options, 'long'); - - foreach ($options as $option) { - $shortLength = \mb_strlen($option['short']); - $longLength = \mb_strlen($option['long']); - $currentLength = max($shortLength, $longLength); - - $maxLength = \max($maxLength, $currentLength); - } - - if ($shortOptionExists && $longOptionExists) { - $maxLength += 6; - } elseif ($shortOptionExists) { - } elseif ($longOptionExists) { - $maxLength += 3; - } - - return $maxLength; - } } From 38a7d1e0e2294a63263be8510ef52edbbb36a060 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 13:19:52 +0100 Subject: [PATCH 14/19] feat: improve `HelpRenderer` --- src/Classes/Cli/HelpRenderer.php | 72 +++++++++++++++++++------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index f37cb57c..9005eb50 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -36,23 +36,14 @@ public function addArgument(string $argument, string $description): void public function addOption(string $short, string $long, string $description): void { - $option = $short . $long; - $formatted = ''; - - if ($short && $long) { - $formatted = "-$short, --$long"; - } elseif ($short) { - $formatted = "-$short"; - } elseif ($long) { - $formatted = " --$long"; - } - - $this->sections['options'][$option] = [ - 'short' => $short, - 'long' => $long, - 'formatted' => $formatted, + $option = [ + 'short' => TextRenderer::color($short ? '-' . $short : '', TextRenderer::COLOR_GREEN), + 'separator' => TextRenderer::color($short && $long ? ', ' : '', TextRenderer::COLOR_GREEN), + 'long' => TextRenderer::color($long ? '--' . $long : '', TextRenderer::COLOR_GREEN), 'description' => $description, ]; + + $this->sections['options'][] = $option; } public function render(): string @@ -126,24 +117,47 @@ private function renderOptions(): string return ''; } - $arguments = \PHP_EOL; - $arguments .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $options = \PHP_EOL; + $options .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - $optionsFormatted = \array_map( - function ($option) { - return $option['formatted']; - }, - $this->sections['options'] - ); - $optionsPadding = TextRenderer::getMaxLength($optionsFormatted) + 1; + $optionsShort = self::getTableColumn($this->sections['options'], 'short'); + $optionsShortLength = TextRenderer::getMaxLength($optionsShort); - foreach ($this->sections['options'] as $option) { - $name = TextRenderer::rightPad($option['formatted'], $optionsPadding); - $text = self::INDENT . TextRenderer::color($name, TextRenderer::COLOR_GREEN) . $option['description'] . \PHP_EOL; + $optionsSeparator = self::getTableColumn($this->sections['options'], 'separator'); + $optionsSeparatorLength = TextRenderer::getMaxLength($optionsSeparator); - $arguments .= $text; + $optionsLong = self::getTableColumn($this->sections['options'], 'long'); + $optionsLongLength = TextRenderer::getMaxLength($optionsLong); + + $optionsDescription = self::getTableColumn($this->sections['options'], 'description'); + $optionsDescriptionLength = TextRenderer::getMaxLength($optionsDescription); + + foreach ($this->sections['options'] as $option) { + $short = $option['short']; + $separator = $option['separator']; + $long = $option['long']; + $description = $option['description']; + + $options .= self::INDENT; + $options .= TextRenderer::rightPad($short, $optionsShortLength); + $options .= TextRenderer::rightPad($separator, $optionsSeparatorLength); + $options .= TextRenderer::rightPad($long, $optionsLongLength); + $options .= ' '; + $options .= TextRenderer::rightPad($description, $optionsDescriptionLength); + $options .= \PHP_EOL; } - return $arguments; + return $options; + } + + private static function getTableColumn(array $table, string $column): array { + $tableColumn = \array_map( + function ($row) use ($column) { + return $row[$column]; + }, + $table + ); + + return $tableColumn; } } From d7c3ac7e9e9c65284e81b0b62731add20ff04a7f Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 13:28:18 +0100 Subject: [PATCH 15/19] refactor: remove unused method `leftPad` --- src/Classes/Cli/TextRenderer.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index 089ef15b..b1e98777 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -29,11 +29,6 @@ public static function rightPad(string $text, int $length): string return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); } - public static function leftPad(string $text, int $length): string - { - return \str_pad($text, $length, ' ', \STR_PAD_LEFT); - } - public static function getMaxLength(array $items): int { $maxLength = 0; From 1d3e3c71e72f53203581d75538bf6153c10c4666 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 13:29:46 +0100 Subject: [PATCH 16/19] refactor: remove test option --- src/Classes/Cli/Command/CommandCreate.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 6ad99530..2762525f 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -85,7 +85,6 @@ public function getHelp(MmlcCli $cli): string $renderer->addArgument('archiveName', 'The name of the archive (vendorName/moduleName).'); $renderer->addOption('', 'prefix=VENDOR_PREFIX', 'Usually an abbreviated vendorName. Can also be vendorName.'); $renderer->addOption('i', 'interactive', 'Whether to create the module interactively (by answering questions).'); - $renderer->addOption('', '', 'Test with no option.'); return $renderer->render(); } From ff06fcdd2eff13dd62618f41061f2015c0c45015 Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 13:42:15 +0100 Subject: [PATCH 17/19] refactor: let caller print new lines --- src/Classes/Cli/HelpRenderer.php | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Classes/Cli/HelpRenderer.php b/src/Classes/Cli/HelpRenderer.php index 9005eb50..189924da 100644 --- a/src/Classes/Cli/HelpRenderer.php +++ b/src/Classes/Cli/HelpRenderer.php @@ -48,21 +48,25 @@ public function addOption(string $short, string $long, string $description): voi public function render(): string { - $render = ''; - - $render .= $this->renderDescription(); - $render .= $this->renderUsage(); - $render .= $this->renderArguments(); - $render .= $this->renderOptions(); + $render = \array_filter( + [ + $this->renderDescription(), + $this->renderUsage(), + $this->renderArguments(), + $this->renderOptions(), + ], + function (string $renderedText) { + return !empty($renderedText); + } + ); - return $render; + return \PHP_EOL . \implode(\PHP_EOL, $render); } private function renderDescription(): string { - $description = \PHP_EOL; - $description .= TextRenderer::color('Description:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; - $description .= self::INDENT . $this->description . \PHP_EOL; + $description = TextRenderer::color('Description:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $description .= self::INDENT . $this->description; return $description; } @@ -76,8 +80,7 @@ private function renderUsage(): string $items = \array_keys($this->sections['usage']); $maxLength = TextRenderer::getMaxLength($items) + 1; - $usage = \PHP_EOL; - $usage .= TextRenderer::color('Usage:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $usage = TextRenderer::color('Usage:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; foreach ($this->sections['usage'] as $argument => $argumentDescription) { $name = self::INDENT . TextRenderer::rightPad($argument, $maxLength); @@ -98,8 +101,7 @@ private function renderArguments(): string $items = \array_keys($this->sections['arguments']); $maxLength = TextRenderer::getMaxLength($items) + 1; - $arguments = \PHP_EOL; - $arguments .= TextRenderer::color('Arguments:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $arguments = TextRenderer::color('Arguments:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; foreach ($this->sections['arguments'] as $argumentName => $argumentDescription) { $name = self::INDENT . TextRenderer::rightPad($argumentName, $maxLength); @@ -117,8 +119,7 @@ private function renderOptions(): string return ''; } - $options = \PHP_EOL; - $options .= TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; + $options = TextRenderer::color('Options:', TextRenderer::COLOR_YELLOW) . \PHP_EOL; $optionsShort = self::getTableColumn($this->sections['options'], 'short'); $optionsShortLength = TextRenderer::getMaxLength($optionsShort); From 63f04976cda74d881c36a0b75f37ee707298893f Mon Sep 17 00:00:00 2001 From: grandeljay Date: Wed, 15 Nov 2023 14:26:21 +0100 Subject: [PATCH 18/19] refactor: move `rightPad` back where it was --- src/Classes/Cli/TextRenderer.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Classes/Cli/TextRenderer.php b/src/Classes/Cli/TextRenderer.php index d0d86499..87d57841 100644 --- a/src/Classes/Cli/TextRenderer.php +++ b/src/Classes/Cli/TextRenderer.php @@ -34,11 +34,6 @@ public static function color(string $text, int $color): string return "\e[" . $color . "m" . $text . "\e[0m"; } - public static function rightPad(string $text, int $length): string - { - return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); - } - public static function stripEscapeSequencesColor(string $text): string { // Muster für Escape-Sequenzen finden und ersetzen @@ -76,6 +71,11 @@ public static function getTextLength(string $text): int return $textLength; } + public static function rightPad(string $text, int $length): string + { + return \str_pad($text, $length, ' ', \STR_PAD_RIGHT); + } + public static function getMaxLength(array $items): int { $maxLength = 0; From 1efe04593817ee3ff8bb731c03e2c6b29b2cf82b Mon Sep 17 00:00:00 2001 From: grandeljay Date: Tue, 9 Jan 2024 12:08:10 +0100 Subject: [PATCH 19/19] feat: add create command --- src/Classes/Cli/Cli.php | 30 ++++++++++++++++++++++- src/Classes/Cli/Command/CommandCreate.php | 20 ++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/Classes/Cli/Cli.php b/src/Classes/Cli/Cli.php index 2f6eb3d8..86c3b45a 100644 --- a/src/Classes/Cli/Cli.php +++ b/src/Classes/Cli/Cli.php @@ -74,6 +74,34 @@ public function getFilteredArgument(int $argumentIndex): string public function hasOption($option) { global $argv; - return in_array($option, $argv); + + foreach ($argv as $index => $value) { + $optionParts = explode('=', $value); + $optionName = $optionParts[0] ?? $value; + $optionValue = $optionParts[1] ?? ''; + + if ($option === $optionName) { + return true; + } + } + + return false; + } + + public function getOption($option) + { + global $argv; + + foreach ($argv as $index => $value) { + $optionParts = explode('=', $value); + $optionName = $optionParts[0] ?? $value; + $optionValue = $optionParts[1] ?? ''; + + if ($option === $optionName) { + return $optionValue; + } + } + + return false; } } diff --git a/src/Classes/Cli/Command/CommandCreate.php b/src/Classes/Cli/Command/CommandCreate.php index 2762525f..b2c5b573 100644 --- a/src/Classes/Cli/Command/CommandCreate.php +++ b/src/Classes/Cli/Command/CommandCreate.php @@ -13,13 +13,14 @@ namespace RobinTheHood\ModifiedModuleLoaderClient\Cli\Command; -use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; -use RobinTheHood\ModifiedModuleLoaderClient\Cli\TextRenderer; use RobinTheHood\ModifiedModuleLoaderClient\Cli\HelpRenderer; +use RobinTheHood\ModifiedModuleLoaderClient\Cli\MmlcCli; +use RobinTheHood\ModifiedModuleLoaderClient\ModuleCreator; class CommandCreate implements CommandInterface { private const ARGUMENT_ARCHIVE_NAME = 0; + private const ARGUMENT_VENDOR_PREFIX = 1; public function __construct() { @@ -41,7 +42,18 @@ public function run(MmlcCli $cli): void private function create(MmlcCli $cli): void { - echo "🏗️ \n"; + $archiveName = $cli->getFilteredArgument(self::ARGUMENT_ARCHIVE_NAME); + $archiveParts = explode('/', $archiveName); + $vendorName = $archiveParts[0] ?? 'MyCompany'; + $moduleName = $archiveParts[1] ?? 'My First Module'; + + if ($cli->hasOption('--prefix')) { + echo $cli->getOption('--prefix'); + } + $vendorPrefix = $cli->getFilteredArgument(self::ARGUMENT_VENDOR_PREFIX); + + $moduleCreator = new ModuleCreator(); + $moduleCreator->createModule($vendorPrefix, $vendorName, $moduleName); } private function createInteractive(MmlcCli $cli): void @@ -72,6 +84,8 @@ private function createInteractive(MmlcCli $cli): void } $archiveName = $vendorName . '/' . $moduleName; + + $arguments['archiveName'] = $archiveName; } $this->create($cli);