*/
class Shell extends Application
{
- const VERSION = 'v0.9.4';
+ const VERSION = 'v0.9.9';
const PROMPT = '>>> ';
const BUFF_PROMPT = '... ';
private $autoCompleter;
private $matchers = [];
private $commandsMatcher;
+ private $lastExecSuccess = true;
/**
* Create a new Psy Shell.
public static function isIncluded(array $trace)
{
return isset($trace[0]['function']) &&
- in_array($trace[0]['function'], ['require', 'include', 'require_once', 'include_once']);
+ \in_array($trace[0]['function'], ['require', 'include', 'require_once', 'include_once']);
}
/**
*/
protected function getTabCompletionMatchers()
{
- @trigger_error('getTabCompletionMatchers is no longer used', E_USER_DEPRECATED);
+ @\trigger_error('getTabCompletionMatchers is no longer used', E_USER_DEPRECATED);
}
/**
*/
public function addMatchers(array $matchers)
{
- $this->matchers = array_merge($this->matchers, $matchers);
+ $this->matchers = \array_merge($this->matchers, $matchers);
if (isset($this->autoCompleter)) {
$this->addMatchersToAutoCompleter($matchers);
}
// handle empty input
- if (trim($input) === '' && !$this->codeBufferOpen) {
+ if (\trim($input) === '' && !$this->codeBufferOpen) {
continue;
}
}
$code = $this->codeBuffer;
- array_push($code, $input);
- $tokens = @token_get_all('<?php ' . implode("\n", $code));
- $last = array_pop($tokens);
+ \array_push($code, $input);
+ $tokens = @\token_get_all('<?php ' . \implode("\n", $code));
+ $last = \array_pop($tokens);
return $last === '"' || $last === '`' ||
- (is_array($last) && in_array($last[0], [T_ENCAPSED_AND_WHITESPACE, T_START_HEREDOC, T_COMMENT]));
+ (\is_array($last) && \in_array($last[0], [T_ENCAPSED_AND_WHITESPACE, T_START_HEREDOC, T_COMMENT]));
}
/**
return $vars;
}
+ /**
+ * Return the set of variables currently in scope which differ from the
+ * values passed as $currentVars.
+ *
+ * This is used inside the Execution Loop Closure to pick up scope variable
+ * changes made by commands while the loop is running.
+ *
+ * @param array $currentVars
+ *
+ * @return array Associative array of scope variables which differ from $currentVars
+ */
+ public function getScopeVariablesDiff(array $currentVars)
+ {
+ $newVars = [];
+
+ foreach ($this->getScopeVariables(false) as $key => $value) {
+ if (!array_key_exists($key, $currentVars) || $currentVars[$key] !== $value) {
+ $newVars[$key] = $value;
+ }
+ }
+
+ return $newVars;
+ }
+
/**
* Get the set of unused command-scope variable names.
*
*/
public function getScopeVariableNames()
{
- return array_keys($this->context->getAll());
+ return \array_keys($this->context->getAll());
}
/**
*/
public function getIncludes()
{
- return array_merge($this->config->getDefaultIncludes(), $this->includes);
+ return \array_merge($this->config->getDefaultIncludes(), $this->includes);
}
/**
{
try {
// Code lines ending in \ keep the buffer open
- if (substr(rtrim($code), -1) === '\\') {
+ if (\substr(\rtrim($code), -1) === '\\') {
$this->codeBufferOpen = true;
- $code = substr(rtrim($code), 0, -1);
+ $code = \substr(\rtrim($code), 0, -1);
} else {
$this->codeBufferOpen = false;
}
throw new \InvalidArgumentException('Command not found: ' . $input);
}
- $input = new ShellInput(str_replace('\\', '\\\\', rtrim($input, " \t\n\r\0\x0B;")));
+ $input = new ShellInput(\str_replace('\\', '\\\\', \rtrim($input, " \t\n\r\0\x0B;")));
if ($input->hasParameterOption(['--help', '-h'])) {
$helpCommand = $this->get('help');
return;
}
- list($codeBuffer, $codeBufferOpen, $code) = array_pop($this->codeStack);
+ list($codeBuffer, $codeBufferOpen, $code) = \array_pop($this->codeStack);
$this->codeBuffer = $codeBuffer;
$this->codeBufferOpen = $codeBufferOpen;
}
// Skip empty lines and lines starting with a space
- if (trim($line) !== '' && substr($line, 0, 1) !== ' ') {
+ if (\trim($line) !== '' && \substr($line, 0, 1) !== ' ') {
$this->readline->addHistory($line);
}
}
*/
private function addCodeBufferToHistory()
{
- $codeBuffer = array_filter($this->codeBuffer, function ($line) {
+ $codeBuffer = \array_filter($this->codeBuffer, function ($line) {
return !$line instanceof SilentInput;
});
- $this->addHistory(implode("\n", $codeBuffer));
+ $this->addHistory(\implode("\n", $codeBuffer));
}
/**
public function getNamespace()
{
if ($namespace = $this->cleaner->getNamespace()) {
- return implode('\\', $namespace);
+ return \implode('\\', $namespace);
}
}
// Incremental flush
if ($out !== '' && !$isCleaning) {
$this->output->write($out, false, ShellOutput::OUTPUT_RAW);
- $this->outputWantsNewline = (substr($out, -1) !== "\n");
+ $this->outputWantsNewline = (\substr($out, -1) !== "\n");
$this->stdoutBuffer .= $out;
}
if ($phase & PHP_OUTPUT_HANDLER_END) {
// Write an extra newline if stdout didn't end with one
if ($this->outputWantsNewline) {
- $this->output->writeln(sprintf('<aside>%s</aside>', $this->config->useUnicode() ? '⏎' : '\\n'));
+ $this->output->writeln(\sprintf('<aside>%s</aside>', $this->config->useUnicode() ? '⏎' : '\\n'));
$this->outputWantsNewline = false;
}
*/
public function writeReturnValue($ret)
{
+ $this->lastExecSuccess = true;
+
if ($ret instanceof NoReturnValue) {
return;
}
$this->context->setReturnValue($ret);
$ret = $this->presentValue($ret);
- $indent = str_repeat(' ', strlen(static::RETVAL));
+ $indent = \str_repeat(' ', \strlen(static::RETVAL));
- $this->output->writeln(static::RETVAL . str_replace(PHP_EOL, PHP_EOL . $indent, $ret));
+ $this->output->writeln(static::RETVAL . \str_replace(PHP_EOL, PHP_EOL . $indent, $ret));
}
/**
*/
public function writeException(\Exception $e)
{
+ $this->lastExecSuccess = false;
$this->context->setLastException($e);
$this->output->writeln($this->formatException($e));
$this->resetCodeBuffer();
}
+ /**
+ * Check whether the last exec was successful.
+ *
+ * Returns true if a return value was logged rather than an exception.
+ *
+ * @return bool
+ */
+ public function getLastExecSuccess()
+ {
+ return $this->lastExecSuccess;
+ }
+
/**
* Helper for formatting an exception for writeException().
*
$message = $e->getMessage();
if (!$e instanceof PsyException) {
if ($message === '') {
- $message = get_class($e);
+ $message = \get_class($e);
} else {
- $message = sprintf('%s with message \'%s\'', get_class($e), $message);
+ $message = \sprintf('%s with message \'%s\'', \get_class($e), $message);
}
}
- $message = preg_replace(
+ $message = \preg_replace(
"#(\\w:)?(/\\w+)*/src/Execution(?:Loop)?Closure.php\(\d+\) : eval\(\)'d code#",
"eval()'d code",
- str_replace('\\', '/', $message)
+ \str_replace('\\', '/', $message)
);
- $message = str_replace(" in eval()'d code", ' in Psy Shell code', $message);
+ $message = \str_replace(" in eval()'d code", ' in Psy Shell code', $message);
$severity = ($e instanceof \ErrorException) ? $this->getSeverity($e) : 'error';
- return sprintf('<%s>%s</%s>', $severity, OutputFormatter::escape($message), $severity);
+ return \sprintf('<%s>%s</%s>', $severity, OutputFormatter::escape($message), $severity);
}
/**
protected function getSeverity(\ErrorException $e)
{
$severity = $e->getSeverity();
- if ($severity & error_reporting()) {
+ if ($severity & \error_reporting()) {
switch ($severity) {
case E_WARNING:
case E_NOTICE:
*/
public function handleError($errno, $errstr, $errfile, $errline)
{
- if ($errno & error_reporting()) {
+ if ($errno & \error_reporting()) {
ErrorException::throwException($errno, $errstr, $errfile, $errline);
} elseif ($errno & $this->config->errorLoggingLevel()) {
// log it and continue...
*/
protected function hasCommand($input)
{
- if (preg_match('/([^\s]+?)(?:\s|$)/A', ltrim($input), $match)) {
+ if (\preg_match('/([^\s]+?)(?:\s|$)/A', \ltrim($input), $match)) {
return $this->has($match[1]);
}
protected function readline()
{
if (!empty($this->inputBuffer)) {
- $line = array_shift($this->inputBuffer);
+ $line = \array_shift($this->inputBuffer);
if (!$line instanceof SilentInput) {
- $this->output->writeln(sprintf('<aside>%s %s</aside>', static::REPLAY, OutputFormatter::escape($line)));
+ $this->output->writeln(\sprintf('<aside>%s %s</aside>', static::REPLAY, OutputFormatter::escape($line)));
}
return $line;
}
if ($bracketedPaste = $this->config->useBracketedPaste()) {
- printf("\e[?2004h"); // Enable bracketed paste
+ \printf("\e[?2004h"); // Enable bracketed paste
}
$line = $this->readline->readline($this->getPrompt());
if ($bracketedPaste) {
- printf("\e[?2004l"); // ... and disable it again
+ \printf("\e[?2004l"); // ... and disable it again
}
return $line;
*/
protected function getHeader()
{
- return sprintf('<aside>%s by Justin Hileman</aside>', $this->getVersion());
+ return \sprintf('<aside>%s by Justin Hileman</aside>', $this->getVersion());
}
/**
{
$separator = $this->config->useUnicode() ? '—' : '-';
- return sprintf('Psy Shell %s (PHP %s %s %s)', self::VERSION, phpversion(), $separator, php_sapi_name());
+ return \sprintf('Psy Shell %s (PHP %s %s %s)', self::VERSION, PHP_VERSION, $separator, PHP_SAPI);
}
/**
*/
protected function autocomplete($text)
{
- @trigger_error('Tab completion is provided by the AutoCompleter service', E_USER_DEPRECATED);
+ @\trigger_error('Tab completion is provided by the AutoCompleter service', E_USER_DEPRECATED);
}
/**
try {
$client = $this->config->getChecker();
if (!$client->isLatest()) {
- $this->output->writeln(sprintf('New version is available (current: %s, latest: %s)', self::VERSION, $client->getLatest()));
+ $this->output->writeln(\sprintf('New version is available (current: %s, latest: %s)', self::VERSION, $client->getLatest()));
}
} catch (\InvalidArgumentException $e) {
$this->output->writeln($e->getMessage());