Changeset View
Changeset View
Standalone View
Standalone View
src/console/format.php
- This file was added.
| <?php | |||||
| function phutil_console_format($format /* ... */) { | |||||
| $args = func_get_args(); | |||||
| return call_user_func_array( | |||||
| array('PhutilConsoleFormatter', 'formatString'), | |||||
| $args); | |||||
| } | |||||
| function phutil_console_confirm($prompt, $default_no = true) { | |||||
| $prompt_options = $default_no ? '[y/N]' : '[Y/n]'; | |||||
| do { | |||||
| $response = phutil_console_prompt($prompt.' '.$prompt_options); | |||||
| $c = trim(strtolower($response)); | |||||
| } while ($c != 'y' && $c != 'n' && $c != ''); | |||||
| echo "\n"; | |||||
| if ($default_no) { | |||||
| return ($c == 'y'); | |||||
| } else { | |||||
| return ($c != 'n'); | |||||
| } | |||||
| } | |||||
| function phutil_console_select($prompt, $min, $max) { | |||||
| $select_options = '['.$min.' - '.$max.']'; | |||||
| do { | |||||
| $response = phutil_console_prompt($prompt.' '.$select_options); | |||||
| $selection = trim($response); | |||||
| if (preg_match('/^\d+\z/', $selection)) { | |||||
| $selection = (int)$selection; | |||||
| if ($selection >= $min && $selection <= $max) { | |||||
| return $selection; | |||||
| } | |||||
| } | |||||
| } while (true); | |||||
| } | |||||
| function phutil_console_prompt($prompt, $history = '') { | |||||
| echo "\n\n"; | |||||
| $prompt = phutil_console_wrap($prompt.' ', 4); | |||||
| try { | |||||
| phutil_console_require_tty(); | |||||
| } catch (PhutilConsoleStdinNotInteractiveException $ex) { | |||||
| // Throw after echoing the prompt so the user has some idea what happened. | |||||
| echo $prompt; | |||||
| throw $ex; | |||||
| } | |||||
| // `escapeshellarg` makes double quotes in the command below disappear on | |||||
| // Windows, which breaks prompts when using history. See T6348 | |||||
| $use_history = !phutil_is_windows(); | |||||
| if ($history == '') { | |||||
| $use_history = false; | |||||
| } else { | |||||
| // Test if bash is available by seeing if it can run `true`. | |||||
| list($err) = exec_manual('bash -c %s', 'true'); | |||||
| if ($err) { | |||||
| $use_history = false; | |||||
| } | |||||
| } | |||||
| if (!$use_history) { | |||||
| echo $prompt; | |||||
| $response = fgets(STDIN); | |||||
| } else { | |||||
| // There's around 0% chance that readline() is available directly in PHP, | |||||
| // so we're using bash/read/history instead. | |||||
| $command = csprintf( | |||||
| 'bash -c %s', | |||||
| csprintf( | |||||
| 'history -r %s 2>/dev/null; '. | |||||
| 'read -e -p %s; '. | |||||
| 'echo "$REPLY"; '. | |||||
| 'history -s "$REPLY" 2>/dev/null; '. | |||||
| 'history -w %s 2>/dev/null', | |||||
| $history, | |||||
| $prompt, | |||||
| $history)); | |||||
| // execx() doesn't work with input, phutil_passthru() doesn't return output. | |||||
| $response = shell_exec($command); | |||||
| } | |||||
| return rtrim($response, "\r\n"); | |||||
| } | |||||
| /** | |||||
| * Soft wrap text for display on a console, respecting UTF8 character boundaries | |||||
| * and ANSI color escape sequences. | |||||
| * | |||||
| * @param string Text to wrap. | |||||
| * @param int Optional indent level. | |||||
| * @param bool True to also indent the first line. | |||||
| * @return string Wrapped text. | |||||
| */ | |||||
| function phutil_console_wrap($text, $indent = 0, $with_prefix = true) { | |||||
| $lines = array(); | |||||
| $width = (78 - $indent); | |||||
| $esc = chr(27); | |||||
| $break_pos = null; | |||||
| $len_after_break = 0; | |||||
| $line_len = 0; | |||||
| $line = array(); | |||||
| $lines = array(); | |||||
| $vector = phutil_utf8v($text); | |||||
| $vector_len = count($vector); | |||||
| for ($ii = 0; $ii < $vector_len; $ii++) { | |||||
| $chr = $vector[$ii]; | |||||
| // If this is an ANSI escape sequence for a color code, just consume it | |||||
| // without counting it toward the character limit. This prevents lines | |||||
| // with bold/color on them from wrapping too early. | |||||
| if ($chr == $esc) { | |||||
| for ($ii; $ii < $vector_len; $ii++) { | |||||
| $line[] = $vector[$ii]; | |||||
| if ($vector[$ii] == 'm') { | |||||
| break; | |||||
| } | |||||
| } | |||||
| continue; | |||||
| } | |||||
| $line[] = $chr; | |||||
| ++$line_len; | |||||
| ++$len_after_break; | |||||
| if ($line_len > $width) { | |||||
| if ($break_pos !== null) { | |||||
| $slice = array_slice($line, 0, $break_pos); | |||||
| while (count($slice) && end($slice) == ' ') { | |||||
| array_pop($slice); | |||||
| } | |||||
| $slice[] = "\n"; | |||||
| $lines[] = $slice; | |||||
| $line = array_slice($line, $break_pos); | |||||
| $line_len = $len_after_break; | |||||
| $len_after_break = 0; | |||||
| $break_pos = null; | |||||
| } | |||||
| } | |||||
| if ($chr == ' ') { | |||||
| $break_pos = count($line); | |||||
| $len_after_break = 0; | |||||
| } | |||||
| if ($chr == "\n") { | |||||
| $lines[] = $line; | |||||
| $line = array(); | |||||
| $len_after_break = 0; | |||||
| $line_len = 0; | |||||
| $break_pos = null; | |||||
| } | |||||
| } | |||||
| if ($line) { | |||||
| if ($line) { | |||||
| $lines[] = $line; | |||||
| } | |||||
| } | |||||
| $pre = null; | |||||
| if ($indent) { | |||||
| $pre = str_repeat(' ', $indent); | |||||
| } | |||||
| foreach ($lines as $idx => $line) { | |||||
| if ($idx == 0 && !$with_prefix) { | |||||
| $prefix = null; | |||||
| } else { | |||||
| $prefix = $pre; | |||||
| } | |||||
| $lines[$idx] = $prefix.implode('', $line); | |||||
| } | |||||
| return implode('', $lines); | |||||
| } | |||||
| function phutil_console_require_tty() { | |||||
| if (function_exists('posix_isatty') && !posix_isatty(STDIN)) { | |||||
| throw new PhutilConsoleStdinNotInteractiveException(); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Determine the width of the terminal, if possible. Returns `null` on failure. | |||||
| * | |||||
| * @return int|null Terminal width in characters, or null on failure. | |||||
| */ | |||||
| function phutil_console_get_terminal_width() { | |||||
| return PhutilConsoleMetrics::getDefaultConsole() | |||||
| ->getTerminalWidth(); | |||||
| } | |||||