From 5de5730739cbf63342d84699eb031334414a6f9a Mon Sep 17 00:00:00 2001 From: Alannah Kearney Date: Sat, 25 May 2019 14:27:28 +1000 Subject: [PATCH] Added display_error_and_exit function --- src/Cli/Cli.php | 149 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 121 insertions(+), 28 deletions(-) diff --git a/src/Cli/Cli.php b/src/Cli/Cli.php index 00d1703..dc70b7d 100644 --- a/src/Cli/Cli.php +++ b/src/Cli/Cli.php @@ -8,6 +8,7 @@ use pointybeard\Helpers\Cli\Input; use pointybeard\Helpers\Cli\Colour; use pointybeard\Helpers\Functions\Flags; use pointybeard\Helpers\Functions\Strings; +use pointybeard\Helpers\Functions\Arrays; /* * Checks if bash can be invoked. @@ -38,6 +39,20 @@ if (!function_exists(__NAMESPACE__.'is_su')) { } } +/* + * Uses tput to find out the size of the window (columns and lines) + * @return array an array containing exactly 2 items: 'cols' and 'lines' + */ +if (!function_exists(__NAMESPACE__.'get_window_size')) { + function get_window_size(): array + { + return [ + 'cols' => exec('tput cols'), + 'lines' => exec('tput lines'), + ]; + } +} + if (!function_exists(__NAMESPACE__.'usage')) { function usage(string $name, Input\InputCollection $collection): string { @@ -62,30 +77,16 @@ if (!function_exists(__NAMESPACE__.'usage')) { } } -/** - * Uses tput to find out the size of the window (columns and lines) - * @return array an array containing exactly 2 items: 'cols' and 'lines' - */ -if (!function_exists(__NAMESPACE__.'get_window_size')) { - function get_window_size(): array - { - return [ - 'cols' => exec('tput cols'), - 'lines' => exec('tput lines'), - ]; - } -} - if (!function_exists(__NAMESPACE__.'manpage')) { - function manpage(string $name, string $version, string $description, Input\InputCollection $collection, $foregroundColour=Colour\Colour::FG_DEFAULT, $headingColour=Colour\Colour::FG_WHITE, array $additionalSections=[]): string + function manpage(string $name, string $version, string $description, Input\InputCollection $collection, $foregroundColour = Colour\Colour::FG_DEFAULT, $headingColour = Colour\Colour::FG_WHITE, array $additionalSections = []): string { // Convienence function for wrapping a heading with colour - $heading = function(string $input) use ($headingColour) { + $heading = function (string $input) use ($headingColour) { return Colour\Colour::colourise($input, $headingColour); }; // Convienence function for wrapping input in a specified colour - $colourise = function(string $input) use ($foregroundColour) { + $colourise = function (string $input) use ($foregroundColour) { return Colour\Colour::colourise($input, $foregroundColour); }; @@ -102,12 +103,12 @@ if (!function_exists(__NAMESPACE__.'manpage')) { $arguments = []; $options = []; - foreach ($collection->getItemsByType("Argument") as $a) { + foreach ($collection->getItemsByType('Argument') as $a) { $arguments[] = (string) $a; } - foreach($collection->getTypes() as $type) { - if($type == 'Argument') { + foreach ($collection->getTypes() as $type) { + if ('Argument' == $type) { continue; } foreach ($collection->getItemsByType($type) as $o) { @@ -116,23 +117,115 @@ if (!function_exists(__NAMESPACE__.'manpage')) { } // Add the arguments, if there are any. - if(false === empty($arguments)){ - $sections[] = $heading("Arguments:"); - $sections[] = $colourise(implode($arguments, PHP_EOL)) . PHP_EOL; + if (false === empty($arguments)) { + $sections[] = $heading('Arguments:'); + $sections[] = $colourise(implode($arguments, PHP_EOL)).PHP_EOL; } // Add the options, if there are any. - if(false === empty($options)){ - $sections[] = $heading("Options:"); - $sections[] = $colourise(implode($options, PHP_EOL)) . PHP_EOL; + if (false === empty($options)) { + $sections[] = $heading('Options:'); + $sections[] = $colourise(implode($options, PHP_EOL)).PHP_EOL; } // Iterate over all additional items and add them as new sections - foreach($additionalSections as $name => $contents) { + foreach ($additionalSections as $name => $contents) { $sections[] = $heading("{$name}:"); - $sections[] = $colourise($contents) . PHP_EOL; + $sections[] = $colourise($contents).PHP_EOL; } return implode($sections, PHP_EOL); } } + +if (!function_exists(__NAMESPACE__."\display_error_and_exit")) { + function display_error_and_exit($message, $heading = 'Error', $background = Colour\Colour::BG_RED): void + { + $padCharacter = ' '; + $paddingBufferSize = 0.15; // 15% + $minimumWindowWidth = 40; + $edgePaddingLength = 5; + $edgePadding = str_repeat($padCharacter, $edgePaddingLength); + + // Get the window dimensions but restrict width to minimum + // of $minimumWindowWidth + $window = get_window_size(); + $window['cols'] = max($minimumWindowWidth, $window['cols']); + + // This shrinks the total line length (derived by the window width) by + // $paddingBufferSize + $paddingBuffer = (int) ceil($window['cols'] * $paddingBufferSize); + + $lineLength = $window['cols'] - (2 * $edgePaddingLength) - $paddingBuffer; + + $add_background = function (string $string, bool $bold = false) use ($padCharacter, $edgePadding, $background): string { + $string = $edgePadding.$string.$edgePadding; + + return Colour\Colour::colourise( + $string, + ( + true == $bold + ? Colour\Colour::FG_WHITE + : Colour\Colour::FG_DEFAULT + ), + $background + ); + }; + + $emptyLine = $add_background(str_repeat($padCharacter, $lineLength), true); + $heading = Strings\mb_str_pad(trim($heading), $lineLength, $padCharacter, \STR_PAD_RIGHT); + + $message = Strings\utf8_wordwrap_array($message, $lineLength, PHP_EOL, true); + + // Remove surrounding whitespace + $message = array_map('trim', $message); + + // Remove empty elements from the array + $message = Arrays\array_remove_empty($message); + + // Reset array indicies + $message = array_values($message); + + // Check for a backtrace and get it's index if there is one. Trace + // will most likely have been provided by the + // Helpers\Exceptions\ReadableTrace\ReadableTraceException + $traceArrayIndex = array_search('Trace', $message); + if (false !== $traceArrayIndex) { + // Purely cosmetic; add a new line before the trace starts + $message[$traceArrayIndex] = PHP_EOL.$message[$traceArrayIndex]; + } + + // Wrap everything (except the trace) in red + for ($ii = 0; $ii < count($message); ++$ii) { + if (false !== $traceArrayIndex && $ii == $traceArrayIndex) { + break; + } + $message[$ii] = $add_background(Strings\mb_str_pad( + $message[$ii], + mb_strlen($heading), + $padCharacter, + \STR_PAD_RIGHT + )); + } + + // Add an empty red line before the trace (or at the end if there + // is no trace) + Arrays\array_insert_at_index( + $message, + false !== $traceArrayIndex + ? $traceArrayIndex + : count($message), + $emptyLine + ); + + // Print the error message, starting with an empty red line + printf( + "\r\n%s\r\n%s\r\n%s\r\n", + $emptyLine, + $add_background($heading, true), + implode($message, PHP_EOL) + ); + + exit(1); + } +}