Chris@12: message`, Chris@12: * `message`) Chris@12: * - Write output to a specified stream, optionally with colorization. Chris@12: * - Write a line of output to a specified stream, optionally with Chris@12: * colorization, using the system EOL sequence.. Chris@12: * - Write an error message to STDERR. Chris@12: * Chris@12: * Colorization will only occur when expected sequences are discovered, and Chris@12: * then, only if the console terminal allows it. Chris@12: * Chris@12: * Essentially, provides the bare minimum to allow you to provide messages to Chris@12: * the current console. Chris@12: */ Chris@12: class ConsoleHelper Chris@12: { Chris@12: const COLOR_GREEN = "\033[32m"; Chris@12: const COLOR_RED = "\033[31m"; Chris@12: const COLOR_RESET = "\033[0m"; Chris@12: Chris@12: const HIGHLIGHT_INFO = 'info'; Chris@12: const HIGHLIGHT_ERROR = 'error'; Chris@12: Chris@12: private $highlightMap = [ Chris@12: self::HIGHLIGHT_INFO => self::COLOR_GREEN, Chris@12: self::HIGHLIGHT_ERROR => self::COLOR_RED, Chris@12: ]; Chris@12: Chris@12: /** Chris@12: * @var string Exists only for testing. Chris@12: */ Chris@12: private $eol = PHP_EOL; Chris@12: Chris@12: /** Chris@12: * @var resource Exists only for testing. Chris@12: */ Chris@12: private $stderr = STDERR; Chris@12: Chris@12: /** Chris@12: * @var bool Chris@12: */ Chris@12: private $supportsColor; Chris@12: Chris@12: /** Chris@12: * @param resource $resource Chris@12: */ Chris@12: public function __construct($resource = STDOUT) Chris@12: { Chris@12: $this->supportsColor = $this->detectColorCapabilities($resource); Chris@12: } Chris@12: Chris@12: /** Chris@12: * Colorize a string for use with the terminal. Chris@12: * Chris@12: * Takes strings formatted as `string` and formats them per the Chris@12: * $highlightMap; if color support is disabled, simply removes the formatting Chris@12: * tags. Chris@12: * Chris@12: * @param string $string Chris@12: * @return string Chris@12: */ Chris@12: public function colorize($string) Chris@12: { Chris@12: $reset = $this->supportsColor ? self::COLOR_RESET : ''; Chris@12: foreach ($this->highlightMap as $key => $color) { Chris@12: $pattern = sprintf('#<%s>(.*?)#s', $key, $key); Chris@12: $color = $this->supportsColor ? $color : ''; Chris@12: $string = preg_replace($pattern, $color . '$1' . $reset, $string); Chris@12: } Chris@12: return $string; Chris@12: } Chris@12: Chris@12: /** Chris@12: * @param string $string Chris@12: * @param bool $colorize Whether or not to colorize the string Chris@12: * @param resource $resource Defaults to STDOUT Chris@12: * @return void Chris@12: */ Chris@12: public function write($string, $colorize = true, $resource = STDOUT) Chris@12: { Chris@12: if ($colorize) { Chris@12: $string = $this->colorize($string); Chris@12: } Chris@12: Chris@12: $string = $this->formatNewlines($string); Chris@12: Chris@12: fwrite($resource, $string); Chris@12: } Chris@12: Chris@12: /** Chris@12: * @param string $string Chris@12: * @param bool $colorize Whether or not to colorize the line Chris@12: * @param resource $resource Defaults to STDOUT Chris@12: * @return void Chris@12: */ Chris@12: public function writeLine($string, $colorize = true, $resource = STDOUT) Chris@12: { Chris@12: $this->write($string . $this->eol, $colorize, $resource); Chris@12: } Chris@12: Chris@12: /** Chris@12: * Emit an error message. Chris@12: * Chris@12: * Wraps the message in ``, and passes it to `writeLine()`, Chris@12: * using STDERR as the resource; emits an additional empty line when done, Chris@12: * also to STDERR. Chris@12: * Chris@12: * @param string $message Chris@12: * @return void Chris@12: */ Chris@12: public function writeErrorMessage($message) Chris@12: { Chris@12: $this->writeLine(sprintf('%s', $message), true, $this->stderr); Chris@12: $this->writeLine('', false, $this->stderr); Chris@12: } Chris@12: Chris@12: /** Chris@12: * @param resource $resource Chris@12: * @return bool Chris@12: */ Chris@12: private function detectColorCapabilities($resource = STDOUT) Chris@12: { Chris@12: if ('\\' === DIRECTORY_SEPARATOR) { Chris@12: // Windows Chris@12: return false !== getenv('ANSICON') Chris@12: || 'ON' === getenv('ConEmuANSI') Chris@12: || 'xterm' === getenv('TERM'); Chris@12: } Chris@12: Chris@12: return function_exists('posix_isatty') && posix_isatty($resource); Chris@12: } Chris@12: Chris@12: /** Chris@12: * Ensure newlines are appropriate for the current terminal. Chris@12: * Chris@12: * @param string Chris@12: * @return string Chris@12: */ Chris@12: private function formatNewlines($string) Chris@12: { Chris@12: $string = str_replace($this->eol, "\0PHP_EOL\0", $string); Chris@12: $string = preg_replace("/(\r\n|\n|\r)/", $this->eol, $string); Chris@12: return str_replace("\0PHP_EOL\0", $this->eol, $string); Chris@12: } Chris@12: }