update v 1.0.7.5

This commit is contained in:
Sujit Prasad
2016-06-13 20:41:55 +05:30
parent aa9786d829
commit 283d97e3ea
5078 changed files with 339851 additions and 175995 deletions

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,7 +11,6 @@
namespace Psy;
use PhpParser\Lexer;
use PhpParser\NodeTraverser;
use PhpParser\Parser;
use PhpParser\PrettyPrinter\Standard as Printer;
@@ -19,6 +18,7 @@ use Psy\CodeCleaner\AbstractClassPass;
use Psy\CodeCleaner\AssignThisVariablePass;
use Psy\CodeCleaner\CalledClassPass;
use Psy\CodeCleaner\CallTimePassByReferencePass;
use Psy\CodeCleaner\ExitPass;
use Psy\CodeCleaner\FunctionReturnInWriteContextPass;
use Psy\CodeCleaner\ImplicitReturnPass;
use Psy\CodeCleaner\InstanceOfPass;
@@ -27,6 +27,7 @@ use Psy\CodeCleaner\LegacyEmptyPass;
use Psy\CodeCleaner\MagicConstantsPass;
use Psy\CodeCleaner\NamespacePass;
use Psy\CodeCleaner\StaticConstructorPass;
use Psy\CodeCleaner\StrictTypesPass;
use Psy\CodeCleaner\UseStatementPass;
use Psy\CodeCleaner\ValidClassNamePass;
use Psy\CodeCleaner\ValidConstantPass;
@@ -53,7 +54,12 @@ class CodeCleaner
*/
public function __construct(Parser $parser = null, Printer $printer = null, NodeTraverser $traverser = null)
{
$this->parser = $parser ?: new Parser(new Lexer());
if ($parser === null) {
$parserFactory = new ParserFactory();
$parser = $parserFactory->createParser();
}
$this->parser = $parser;
$this->printer = $printer ?: new Printer();
$this->traverser = $traverser ?: new NodeTraverser();
@@ -81,11 +87,13 @@ class CodeCleaner
new ImplicitReturnPass(),
new UseStatementPass(), // must run before namespace and validation passes
new NamespacePass($this), // must run after the implicit return pass
new StrictTypesPass(),
new StaticConstructorPass(),
new ValidFunctionNamePass(),
new ValidClassNamePass(),
new ValidConstantPass(),
new MagicConstantsPass(),
new ExitPass(),
);
}
@@ -101,7 +109,7 @@ class CodeCleaner
*/
public function clean(array $codeLines, $requireSemicolons = false)
{
$stmts = $this->parse("<?php " . implode(PHP_EOL, $codeLines) . PHP_EOL, $requireSemicolons);
$stmts = $this->parse('<?php ' . implode(PHP_EOL, $codeLines) . PHP_EOL, $requireSemicolons);
if ($stmts === false) {
return false;
}
@@ -149,6 +157,10 @@ class CodeCleaner
try {
return $this->parser->parse($code);
} catch (\PhpParser\Error $e) {
if ($this->parseErrorIsUnclosedString($e, $code)) {
return false;
}
if (!$this->parseErrorIsEOF($e)) {
throw ParseErrorException::fromParseError($e);
}
@@ -170,6 +182,33 @@ class CodeCleaner
{
$msg = $e->getRawMessage();
return ($msg === "Unexpected token EOF") || (strpos($msg, "Syntax error, unexpected EOF") !== false);
return ($msg === 'Unexpected token EOF') || (strpos($msg, 'Syntax error, unexpected EOF') !== false);
}
/**
* A special test for unclosed single-quoted strings.
*
* Unlike (all?) other unclosed statements, single quoted strings have
* their own special beautiful snowflake syntax error just for
* themselves.
*
* @param \PhpParser\Error $e
* @param string $code
*
* @return bool
*/
private function parseErrorIsUnclosedString(\PhpParser\Error $e, $code)
{
if ($e->getRawMessage() !== 'Syntax error, unexpected T_ENCAPSED_AND_WHITESPACE') {
return false;
}
try {
$this->parser->parse($code . "';");
} catch (\Exception $e) {
return false;
}
return true;
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\CodeCleaner;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Exit_;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Throw_;
class ExitPass extends CodeCleanerPass
{
/**
* Converts exit calls to BreakExceptions.
*
* @param \PhpParser\Node $node
*/
public function leaveNode(Node $node)
{
if ($node instanceof Exit_) {
$args = array(new Arg(new String_('Goodbye.')));
return new Throw_(new New_(new Name('Psy\Exception\BreakException'), $args));
}
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,6 +12,7 @@
namespace Psy\CodeCleaner;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Exit_;
use PhpParser\Node\Stmt\Return_ as ReturnStmt;
/**
@@ -26,7 +27,7 @@ class ImplicitReturnPass extends CodeCleanerPass
{
$last = end($nodes);
if ($last instanceof Expr) {
if ($last instanceof Expr && !($last instanceof Exit_)) {
$nodes[count($nodes) - 1] = new ReturnStmt($last, array(
'startLine' => $last->getLine(),
'endLine' => $last->getLine(),

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -29,7 +29,7 @@ class LeavePsyshAlonePass extends CodeCleanerPass
*/
public function enterNode(Node $node)
{
if ($node instanceof Variable && $node->name === "__psysh__") {
if ($node instanceof Variable && $node->name === '__psysh__') {
throw new RuntimeException('Don\'t mess with $__psysh__. Bad things will happen.');
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -16,7 +16,7 @@ use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\MagicConst\Dir;
use PhpParser\Node\Scalar\MagicConst\File;
use PhpParser\Node\Scalar\String as String;
use PhpParser\Node\Scalar\String_ as StringNode;
/**
* Swap out __DIR__ and __FILE__ magic constants with our best guess?
@@ -36,7 +36,7 @@ class MagicConstantsPass extends CodeCleanerPass
if ($node instanceof Dir) {
return new FuncCall(new Name('getcwd'), array(), $node->getAttributes());
} elseif ($node instanceof File) {
return new String('', $node->getAttributes());
return new StringNode('', $node->getAttributes());
}
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -0,0 +1,76 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\CodeCleaner;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt\Declare_ as DeclareStmt;
use PhpParser\Node\Stmt\DeclareDeclare;
use Psy\Exception\FatalErrorException;
/**
* Provide implicit strict types declarations for for subsequent execution.
*
* The strict types pass remembers the last strict types declaration:
*
* declare(strict_types=1);
*
* ... which it then applies implicitly to all future evaluated code, until it
* is replaced by a new declaration.
*/
class StrictTypesPass extends CodeCleanerPass
{
private $strictTypes = false;
/**
* If this is a standalone strict types declaration, remember it for later.
*
* Otherwise, apply remembered strict types declaration to to the code until
* a new declaration is encountered.
*
* @throws FatalErrorException if an invalid `strict_types` declaration is found.
*
* @param array $nodes
*/
public function beforeTraverse(array $nodes)
{
if (version_compare(PHP_VERSION, '7.0', '<')) {
return;
}
$prependStrictTypes = $this->strictTypes;
foreach ($nodes as $key => $node) {
if ($node instanceof DeclareStmt) {
foreach ($node->declares as $declare) {
if ($declare->key === 'strict_types') {
$value = $declare->value;
if (!$value instanceof LNumber || ($value->value !== 0 && $value->value !== 1)) {
throw new FatalErrorException('strict_types declaration must have 0 or 1 as its value');
}
$this->strictTypes = $value->value === 1;
}
}
}
}
if ($prependStrictTypes) {
$first = reset($nodes);
if (!$first instanceof DeclareStmt) {
$declare = new DeclareStmt(array(new DeclareDeclare('strict_types', new LNumber(1))));
array_unshift($nodes, $declare);
}
}
return $nodes;
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -42,7 +42,29 @@ class ValidClassNamePass extends NamespaceAwarePass
}
/**
* Validate class, interface and trait statements, and `new` expressions.
* Validate class, interface and trait definitions.
*
* Validate them upon entering the node, so that we know about their
* presence and can validate constant fetches and static calls in class or
* trait methods.
*
* @param Node
*/
public function enterNode(Node $node)
{
parent::enterNode($node);
if ($node instanceof ClassStmt) {
$this->validateClassStatement($node);
} elseif ($node instanceof InterfaceStmt) {
$this->validateInterfaceStatement($node);
} elseif ($node instanceof TraitStmt) {
$this->validateTraitStatement($node);
}
}
/**
* Validate `new` expressions, class constant fetches, and static calls.
*
* @throws FatalErrorException if a class, interface or trait is referenced which does not exist.
* @throws FatalErrorException if a class extends something that is not a class.
@@ -54,13 +76,7 @@ class ValidClassNamePass extends NamespaceAwarePass
*/
public function leaveNode(Node $node)
{
if ($node instanceof ClassStmt) {
$this->validateClassStatement($node);
} elseif ($node instanceof InterfaceStmt) {
$this->validateInterfaceStatement($node);
} elseif ($node instanceof TraitStmt) {
$this->validateTraitStatement($node);
} elseif ($node instanceof NewExpr) {
if ($node instanceof NewExpr) {
$this->validateNewExpression($node);
} elseif ($node instanceof ClassConstFetch) {
$this->validateClassConstFetchExpression($node);
@@ -111,8 +127,8 @@ class ValidClassNamePass extends NamespaceAwarePass
*/
protected function validateNewExpression(NewExpr $stmt)
{
// if class name is an expression, give it a pass for now
if (!$stmt->class instanceof Expr) {
// if class name is an expression or an anonymous class, give it a pass for now
if (!$stmt->class instanceof Expr && !$stmt->class instanceof ClassStmt) {
$this->ensureClassExists($this->getFullyQualifiedName($stmt->class), $stmt);
}
}
@@ -124,9 +140,15 @@ class ValidClassNamePass extends NamespaceAwarePass
*/
protected function validateClassConstFetchExpression(ClassConstFetch $stmt)
{
// there is no need to check exists for ::class const for php 5.5 or newer
if (strtolower($stmt->name) === 'class'
&& version_compare(PHP_VERSION, '5.5', '>=')) {
return;
}
// if class name is an expression, give it a pass for now
if (!$stmt->class instanceof Expr) {
$this->ensureClassExists($this->getFullyQualifiedName($stmt->class), $stmt);
$this->ensureClassOrInterfaceExists($this->getFullyQualifiedName($stmt->class), $stmt);
}
}
@@ -188,6 +210,21 @@ class ValidClassNamePass extends NamespaceAwarePass
}
}
/**
* Ensure that a referenced class _or interface_ exists.
*
* @throws FatalErrorException
*
* @param string $name
* @param Stmt $stmt
*/
protected function ensureClassOrInterfaceExists($name, $stmt)
{
if (!$this->classExists($name) && !$this->interfaceExists($name)) {
throw $this->createError(sprintf('Class \'%s\' not found', $name), $stmt);
}
}
/**
* Ensure that a statically called method exists.
*
@@ -201,6 +238,11 @@ class ValidClassNamePass extends NamespaceAwarePass
{
$this->ensureClassExists($class, $stmt);
// let's pretend all calls to self, parent and static are valid
if (in_array(strtolower($class), array('self', 'parent', 'static'))) {
return;
}
// if method name is an expression, give it a pass for now
if ($name instanceof Expr) {
return;
@@ -251,12 +293,21 @@ class ValidClassNamePass extends NamespaceAwarePass
/**
* Check whether a class exists, or has been defined in the current code snippet.
*
* Gives `self`, `static` and `parent` a free pass.
*
* @param string $name
*
* @return boolean
* @return bool
*/
protected function classExists($name)
{
// Give `self`, `static` and `parent` a pass. This will actually let
// some errors through, since we're not checking whether the keyword is
// being used in a class scope.
if (in_array(strtolower($name), array('self', 'static', 'parent'))) {
return true;
}
return class_exists($name) || $this->findInScope($name) === self::CLASS_TYPE;
}
@@ -265,7 +316,7 @@ class ValidClassNamePass extends NamespaceAwarePass
*
* @param string $name
*
* @return boolean
* @return bool
*/
protected function interfaceExists($name)
{
@@ -277,7 +328,7 @@ class ValidClassNamePass extends NamespaceAwarePass
*
* @param string $name
*
* @return boolean
* @return bool
*/
protected function traitExists($name)
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -61,16 +61,22 @@ class ValidConstantPass extends NamespaceAwarePass
*/
protected function validateClassConstFetchExpression(ClassConstFetch $stmt)
{
// give the `class` pseudo-constant a pass
if ($stmt->name === 'class') {
return;
}
// if class name is an expression, give it a pass for now
if (!$stmt->class instanceof Expr) {
$className = $this->getFullyQualifiedName($stmt->class);
// if the class doesn't exist, don't throw an exception… it might be
// defined in the same line it's used or something stupid like that.
if (class_exists($className)) {
if (class_exists($className) || interface_exists($className)) {
$constName = sprintf('%s::%s', $className, $stmt->name);
if (!defined($constName)) {
$msg = sprintf('Class constant \'%s\' not found', $constName);
$constType = class_exists($className) ? 'Class' : 'Interface';
$msg = sprintf('%s constant \'%s\' not found', $constType, $constName);
throw new FatalErrorException($msg, 0, 1, null, $stmt->getLine());
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,6 +12,7 @@
namespace Psy\CodeCleaner;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Function_ as FunctionStmt;
@@ -25,6 +26,26 @@ use Psy\Exception\FatalErrorException;
*/
class ValidFunctionNamePass extends NamespaceAwarePass
{
/**
* Store newly defined function names on the way in, to allow recursion.
*
* @param Node $node
*/
public function enterNode(Node $node)
{
parent::enterNode($node);
if ($node instanceof FunctionStmt) {
$name = $this->getFullyQualifiedName($node->name);
if (function_exists($name) || isset($this->currentScope[strtolower($name)])) {
throw new FatalErrorException(sprintf('Cannot redeclare %s()', $name), 0, 1, null, $node->getLine());
}
$this->currentScope[strtolower($name)] = true;
}
}
/**
* Validate that function calls will succeed.
*
@@ -35,18 +56,10 @@ class ValidFunctionNamePass extends NamespaceAwarePass
*/
public function leaveNode(Node $node)
{
if ($node instanceof FunctionStmt) {
$name = $this->getFullyQualifiedName($node->name);
if (function_exists($name) || isset($this->currentScope[strtolower($name)])) {
throw new FatalErrorException(sprintf('Cannot redeclare %s()', $name), 0, 1, null, $node->getLine());
}
$this->currentScope[strtolower($name)] = true;
} elseif ($node instanceof FuncCall) {
if ($node instanceof FuncCall) {
// if function name is an expression or a variable, give it a pass for now.
$name = $node->name;
if (!$name instanceof Expression && !$name instanceof Variable) {
if (!$name instanceof Expr && !$name instanceof Variable) {
$shortName = implode('\\', $name->parts);
$fullName = $this->getFullyQualifiedName($name);
$inScope = isset($this->currentScope[strtolower($fullName)]);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -36,7 +36,7 @@ class BufferCommand extends Command
))
->setDescription('Show (or clear) the contents of the code input buffer.')
->setHelp(
<<<HELP
<<<'HELP'
Show the contents of the code buffer for the current multi-line expression.
Optionally, clear the buffer by passing the <info>--clear</info> option.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -31,7 +31,7 @@ class ClearCommand extends Command
->setDefinition(array())
->setDescription('Clear the Psy Shell screen.')
->setHelp(
<<<HELP
<<<'HELP'
Clear the Psy Shell screen.
Pro Tip: If your PHP has readline support, you should be able to use ctrl+l too!

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,9 +12,8 @@
namespace Psy\Command;
use Psy\Exception\RuntimeException;
use Psy\Presenter\Presenter;
use Psy\Presenter\PresenterManager;
use Psy\Presenter\PresenterManagerAware;
use Psy\VarDumper\Presenter;
use Psy\VarDumper\PresenterAware;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -25,18 +24,18 @@ use Symfony\Component\Console\Output\OutputInterface;
*
* This is like var_dump but *way* awesomer.
*/
class DumpCommand extends ReflectingCommand implements PresenterManagerAware
class DumpCommand extends ReflectingCommand implements PresenterAware
{
private $presenterManager;
private $presenter;
/**
* PresenterManagerAware interface.
* PresenterAware interface.
*
* @param PresenterManager $manager
* @param Presenter $presenter
*/
public function setPresenterManager(PresenterManager $manager)
public function setPresenter(Presenter $presenter)
{
$this->presenterManager = $manager;
$this->presenter = $presenter;
}
/**
@@ -53,14 +52,14 @@ class DumpCommand extends ReflectingCommand implements PresenterManagerAware
))
->setDescription('Dump an object or primitive.')
->setHelp(
<<<HELP
<<<'HELP'
Dump an object or primitive.
This is like var_dump but <strong>way</strong> awesomer.
e.g.
<return>>>> dump \$_</return>
<return>>>> dump \$someVar</return>
<return>>>> dump $_</return>
<return>>>> dump $someVar</return>
HELP
);
}
@@ -72,7 +71,7 @@ HELP
{
$depth = $input->getOption('depth');
$target = $this->resolveTarget($input->getArgument('target'));
$output->page($this->presenterManager->present($target, $depth, $input->getOption('all') ? Presenter::VERBOSE : 0));
$output->page($this->presenter->present($target, $depth, $input->getOption('all') ? Presenter::VERBOSE : 0));
}
/**

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -33,7 +33,7 @@ class ExitCommand extends Command
->setDefinition(array())
->setDescription('End the current session and return to caller.')
->setHelp(
<<<HELP
<<<'HELP'
End the current session and return to caller.
e.g.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -60,7 +60,7 @@ class HistoryCommand extends Command
))
->setDescription('Show the Psy Shell history.')
->setHelp(
<<<HELP
<<<'HELP'
Show, search, save or replay the Psy Shell history.
e.g.
@@ -212,7 +212,7 @@ HELP
*
* @param string $pattern
*
* @return boolean
* @return bool
*/
private function validateRegex($pattern)
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -22,8 +22,8 @@ use Psy\Command\ListCommand\PropertyEnumerator;
use Psy\Command\ListCommand\TraitEnumerator;
use Psy\Command\ListCommand\VariableEnumerator;
use Psy\Exception\RuntimeException;
use Psy\Presenter\PresenterManager;
use Psy\Presenter\PresenterManagerAware;
use Psy\VarDumper\Presenter;
use Psy\VarDumper\PresenterAware;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\TableHelper;
use Symfony\Component\Console\Input\InputArgument;
@@ -34,19 +34,19 @@ use Symfony\Component\Console\Output\OutputInterface;
/**
* List available local variables, object properties, etc.
*/
class ListCommand extends ReflectingCommand implements PresenterManagerAware
class ListCommand extends ReflectingCommand implements PresenterAware
{
protected $presenterManager;
protected $presenter;
protected $enumerators;
/**
* PresenterManagerAware interface.
* PresenterAware interface.
*
* @param PresenterManager $manager
* @param Presenter $manager
*/
public function setPresenterManager(PresenterManager $manager)
public function setPresenter(Presenter $presenter)
{
$this->presenterManager = $manager;
$this->presenter = $presenter;
}
/**
@@ -84,7 +84,7 @@ class ListCommand extends ReflectingCommand implements PresenterManagerAware
))
->setDescription('List local, instance or class variables, methods and constants.')
->setHelp(
<<<HELP
<<<'HELP'
List variables, constants, classes, interfaces, traits, functions, methods,
and properties.
@@ -96,7 +96,7 @@ and methods on that class.
e.g.
<return>>>> ls</return>
<return>>>> ls \$foo</return>
<return>>>> ls $foo</return>
<return>>>> ls -k --grep mongo -i</return>
<return>>>> ls -al ReflectionClass</return>
<return>>>> ls --constants --category date</return>
@@ -141,7 +141,7 @@ HELP
protected function initEnumerators()
{
if (!isset($this->enumerators)) {
$mgr = $this->presenterManager;
$mgr = $this->presenter;
$this->enumerators = array(
new ClassConstantEnumerator($mgr),

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,8 +12,8 @@
namespace Psy\Command\ListCommand;
use Psy\Formatter\SignatureFormatter;
use Psy\Presenter\PresenterManager;
use Psy\Util\Mirror;
use Psy\VarDumper\Presenter;
use Symfony\Component\Console\Input\InputInterface;
/**
@@ -30,7 +30,7 @@ abstract class Enumerator
const IS_CLASS = 'class';
const IS_FUNCTION = 'function';
private $presenterManager;
private $presenter;
private $filter = false;
private $invertFilter = false;
@@ -39,11 +39,11 @@ abstract class Enumerator
/**
* Enumerator constructor.
*
* @param PresenterManager $presenterManager
* @param Presenter $presenter
*/
public function __construct(PresenterManager $presenterManager)
public function __construct(Presenter $presenter)
{
$this->presenterManager = $presenterManager;
$this->presenter = $presenter;
}
/**
@@ -87,7 +87,7 @@ abstract class Enumerator
protected function presentRef($value)
{
return $this->presenterManager->presentRef($value);
return $this->presenter->presentRef($value);
}
protected function showItem($name)
@@ -121,7 +121,7 @@ abstract class Enumerator
*
* @param string $pattern
*
* @return boolean
* @return bool
*/
private function validateRegex($pattern)
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -55,7 +55,7 @@ class MethodEnumerator extends Enumerator
/**
* Get defined methods for the given class or object Reflector.
*
* @param boolean $showAll Include private and protected methods.
* @param bool $showAll Include private and protected methods.
* @param \Reflector $reflector
*
* @return array

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -55,7 +55,7 @@ class PropertyEnumerator extends Enumerator
/**
* Get defined properties for the given class or object Reflector.
*
* @param boolean $showAll Include private and protected properties.
* @param bool $showAll Include private and protected properties.
* @param \Reflector $reflector
*
* @return array

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,7 +12,7 @@
namespace Psy\Command\ListCommand;
use Psy\Context;
use Psy\Presenter\PresenterManager;
use Psy\VarDumper\Presenter;
use Symfony\Component\Console\Input\InputInterface;
/**
@@ -29,13 +29,13 @@ class VariableEnumerator extends Enumerator
* Unlike most other enumerators, the Variable Enumerator needs access to
* the current scope variables, so we need to pass it a Context instance.
*
* @param PresenterManager $presenterManager
* @param Context $context
* @param Presenter $presenter
* @param Context $context
*/
public function __construct(PresenterManager $presenterManager, Context $context)
public function __construct(Presenter $presenter, Context $context)
{
$this->context = $context;
parent::__construct($presenterManager);
parent::__construct($presenter);
}
/**
@@ -68,7 +68,7 @@ class VariableEnumerator extends Enumerator
/**
* Get scope variables.
*
* @param boolean $showAll Include special variables (e.g. $_).
* @param bool $showAll Include special variables (e.g. $_).
*
* @return array
*/

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,38 +11,59 @@
namespace Psy\Command;
use PhpParser\Lexer;
use PhpParser\Node;
use PhpParser\Parser;
use Psy\Presenter\PHPParserPresenter;
use Psy\Presenter\PresenterManager;
use Psy\Presenter\PresenterManagerAware;
use Psy\ParserFactory;
use Psy\VarDumper\Presenter;
use Psy\VarDumper\PresenterAware;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\VarDumper\Caster\Caster;
/**
* Parse PHP code and show the abstract syntax tree.
*/
class ParseCommand extends Command implements PresenterManagerAware
class ParseCommand extends Command implements PresenterAware
{
private $presenterManager;
private $parser;
private $presenter;
private $parserFactory;
private $parsers;
/**
* PresenterManagerAware interface.
*
* @param PresenterManager $manager
* {@inheritdoc}
*/
public function setPresenterManager(PresenterManager $manager)
public function __construct($name = null)
{
$this->presenterManager = new PresenterManager();
$this->parserFactory = new ParserFactory();
$this->parsers = array();
foreach ($manager as $presenter) {
$this->presenterManager->addPresenter($presenter);
}
parent::__construct($name);
}
$this->presenterManager->addPresenter(new PHPParserPresenter());
/**
* PresenterAware interface.
*
* @param Presenter $presenter
*/
public function setPresenter(Presenter $presenter)
{
$this->presenter = clone $presenter;
$this->presenter->addCasters(array(
'PhpParser\Node' => function (Node $node, array $a) {
$a = array(
Caster::PREFIX_VIRTUAL . 'type' => $node->getType(),
Caster::PREFIX_VIRTUAL . 'attributes' => $node->getAttributes(),
);
foreach ($node->getSubNodeNames() as $name) {
$a[Caster::PREFIX_VIRTUAL . $name] = $node->$name;
}
return $a;
},
));
}
/**
@@ -50,15 +71,26 @@ class ParseCommand extends Command implements PresenterManagerAware
*/
protected function configure()
{
$definition = array(
new InputArgument('code', InputArgument::REQUIRED, 'PHP code to parse.'),
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse', 10),
);
if ($this->parserFactory->hasKindsSupport()) {
$msg = 'One of PhpParser\\ParserFactory constants: '
. implode(', ', ParserFactory::getPossibleKinds())
. " (default is based on current interpreter's version)";
$defaultKind = $this->parserFactory->getDefaultKind();
$definition[] = new InputOption('kind', '', InputOption::VALUE_REQUIRED, $msg, $defaultKind);
}
$this
->setName('parse')
->setDefinition(array(
new InputArgument('code', InputArgument::REQUIRED, 'PHP code to parse.'),
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse', 10),
))
->setDefinition($definition)
->setDescription('Parse PHP code and show the abstract syntax tree.')
->setHelp(
<<<HELP
<<<'HELP'
Parse PHP code and show the abstract syntax tree.
This command is used in the development of PsySH. Given a string of PHP code,
@@ -81,22 +113,22 @@ HELP
$code = '<?php ' . $code;
}
$depth = $input->getOption('depth');
$nodes = $this->parse($code);
$output->page($this->presenterManager->present($nodes, $depth));
$parserKind = $input->getOption('kind');
$depth = $input->getOption('depth');
$nodes = $this->parse($this->getParser($parserKind), $code);
$output->page($this->presenter->present($nodes, $depth));
}
/**
* Lex and parse a string of code into statements.
*
* @param Parser $parser
* @param string $code
*
* @return array Statements
*/
private function parse($code)
private function parse(Parser $parser, $code)
{
$parser = $this->getParser();
try {
return $parser->parse($code);
} catch (\PhpParser\Error $e) {
@@ -112,14 +144,16 @@ HELP
/**
* Get (or create) the Parser instance.
*
* @param string|null $kind One of Psy\ParserFactory constants (only for PHP parser 2.0 and above).
*
* @return Parser
*/
private function getParser()
private function getParser($kind = null)
{
if (!isset($this->parser)) {
$this->parser = new Parser(new Lexer());
if (!array_key_exists($kind, $this->parsers)) {
$this->parsers[$kind] = $this->parserFactory->createParser($kind);
}
return $this->parser;
return $this->parsers[$kind];
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -50,8 +50,8 @@ abstract class ReflectingCommand extends Command implements ContextAware
*
* @throws \InvalidArgumentException when the value specified can't be resolved.
*
* @param string $valueName Function, class, variable, constant, method or property name.
* @param boolean $classOnly True if the name should only refer to a class, function or instance
* @param string $valueName Function, class, variable, constant, method or property name.
* @param bool $classOnly True if the name should only refer to a class, function or instance
*
* @return array (class or instance name, member name, kind)
*/
@@ -66,13 +66,13 @@ abstract class ReflectingCommand extends Command implements ContextAware
case preg_match(self::INSTANCE, $valueName, $matches):
return array($this->resolveInstance($matches[1]), null, 0);
case (!$classOnly && preg_match(self::CLASS_MEMBER, $valueName, $matches)):
case !$classOnly && preg_match(self::CLASS_MEMBER, $valueName, $matches):
return array($this->resolveName($matches[1]), $matches[2], Mirror::CONSTANT | Mirror::METHOD);
case (!$classOnly && preg_match(self::CLASS_STATIC, $valueName, $matches)):
case !$classOnly && preg_match(self::CLASS_STATIC, $valueName, $matches):
return array($this->resolveName($matches[1]), $matches[2], Mirror::STATIC_PROPERTY | Mirror::PROPERTY);
case (!$classOnly && preg_match(self::INSTANCE_MEMBER, $valueName, $matches)):
case !$classOnly && preg_match(self::INSTANCE_MEMBER, $valueName, $matches):
if ($matches[2] === '->') {
$kind = Mirror::METHOD | Mirror::PROPERTY;
} else {
@@ -81,7 +81,7 @@ abstract class ReflectingCommand extends Command implements ContextAware
return array($this->resolveInstance($matches[1]), $matches[3], $kind);
case (!$classOnly && preg_match(self::INSTANCE_STATIC, $valueName, $matches)):
case !$classOnly && preg_match(self::INSTANCE_STATIC, $valueName, $matches):
return array($this->resolveInstance($matches[1]), $matches[2], Mirror::STATIC_PROPERTY);
default:
@@ -117,8 +117,8 @@ abstract class ReflectingCommand extends Command implements ContextAware
/**
* Get a Reflector and documentation for a function, class or instance, constant, method or property.
*
* @param string $valueName Function, class, variable, constant, method or property name.
* @param boolean $classOnly True if the name should only refer to a class, function or instance
* @param string $valueName Function, class, variable, constant, method or property name.
* @param bool $classOnly True if the name should only refer to a class, function or instance
*
* @return array (value, Reflector)
*/

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,6 +11,7 @@
namespace Psy\Command;
use Psy\Configuration;
use Psy\Exception\RuntimeException;
use Psy\Formatter\CodeFormatter;
use Psy\Formatter\SignatureFormatter;
@@ -24,6 +25,18 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class ShowCommand extends ReflectingCommand
{
private $colorMode;
/**
* @param null|string $colorMode (default: null)
*/
public function __construct($colorMode = null)
{
$this->colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
return parent::__construct();
}
/**
* {@inheritdoc}
*/
@@ -54,7 +67,7 @@ HELP
list($value, $reflector) = $this->getTargetAndReflector($input->getArgument('value'));
try {
$output->page(CodeFormatter::format($reflector), ShellOutput::OUTPUT_RAW);
$output->page(CodeFormatter::format($reflector, $this->colorMode), ShellOutput::OUTPUT_RAW);
} catch (RuntimeException $e) {
$output->writeln(SignatureFormatter::format($reflector));
throw $e;

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -52,14 +52,14 @@ class ThrowUpCommand extends Command implements ContextAware
))
->setDescription('Throw an exception out of the Psy Shell.')
->setHelp(
<<<HELP
<<<'HELP'
Throws an exception out of the current the Psy Shell instance.
By default it throws the most recent exception.
e.g.
<return>>>> throw-up</return>
<return>>>> throw-up \$e</return>
<return>>>> throw-up $e</return>
HELP
);
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -35,7 +35,7 @@ class TraceCommand extends Command
))
->setDescription('Show the current call stack.')
->setHelp(
<<<HELP
<<<'HELP'
Show the current call stack.
Optionally, include PsySH in the call stack by passing the <info>--include-psy</info> option.
@@ -53,7 +53,7 @@ HELP
protected function execute(InputInterface $input, OutputInterface $output)
{
$trace = $this->getBacktrace(new \Exception(), $input->getOption('num'), $input->getOption('include-psy'));
$output->page($trace, ShellOutput::NUMBER_LINES | ShellOutput::OUTPUT_RAW);
$output->page($trace, ShellOutput::NUMBER_LINES);
}
/**
@@ -106,7 +106,7 @@ HELP
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
$lines[] = sprintf(
' %s%s%s() at <info>%s:%s</info>',
' <class>%s</class>%s%s() at <info>%s:%s</info>',
OutputFormatter::escape($class),
OutputFormatter::escape($type),
OutputFormatter::escape($function),

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,8 +11,9 @@
namespace Psy\Command;
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
use Psy\Configuration;
use Psy\ConsoleColorFactory;
use Psy\Output\ShellOutput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -23,8 +24,15 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class WhereamiCommand extends Command
{
public function __construct()
private $colorMode;
/**
* @param null|string $colorMode (default: null)
*/
public function __construct($colorMode = null)
{
$this->colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
if (version_compare(PHP_VERSION, '5.3.6', '>=')) {
$this->backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
} else {
@@ -46,7 +54,7 @@ class WhereamiCommand extends Command
))
->setDescription('Show where you are in the code.')
->setHelp(
<<<HELP
<<<'HELP'
Show where you are in the code.
Optionally, include how many lines before and after you want to display.
@@ -106,8 +114,8 @@ HELP
{
$info = $this->fileInfo();
$num = $input->getOption('num');
$colors = new ConsoleColor();
$colors->addTheme('line_number', array('blue'));
$factory = new ConsoleColorFactory($this->colorMode);
$colors = $factory->getConsoleColor();
$highlighter = new Highlighter($colors);
$contents = file_get_contents($info['file']);
$output->page($highlighter->getCodeSnippet($contents, $info['line'], $num, $num), ShellOutput::OUTPUT_RAW);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -55,7 +55,7 @@ class WtfCommand extends TraceCommand implements ContextAware
))
->setDescription('Show the backtrace of the most recent exception.')
->setHelp(
<<<HELP
<<<'HELP'
Shows a few lines of the backtrace of the most recent exception.
If you want to see more lines, add more question marks or exclamation marks:

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -53,33 +53,17 @@ class Compiler
->ignoreVCS(true)
->name('*.php')
->exclude('Tests')
->in(__DIR__ . '/../../vendor/dnoegel/php-xdg-base-dir/src')
->in(__DIR__ . '/../../vendor/jakub-onderka/php-console-color')
->in(__DIR__ . '/../../vendor/jakub-onderka/php-console-highlighter')
->in(__DIR__ . '/../../vendor/nikic/php-parser/lib')
->in(__DIR__ . '/../../vendor/symfony/console')
->in(__DIR__ . '/../../vendor/symfony/yaml');
->in(__DIR__ . '/../../build-vendor');
foreach ($finder as $file) {
$this->addFile($phar, $file);
}
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/include_paths.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_files.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_psr4.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_real.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/autoload_classmap.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/composer/ClassLoader.php'));
// Stubs
$phar->setStub($this->getStub());
$phar->stopBuffering();
// $this->addFile($phar, new \SplFileInfo(__DIR__.'/../../LICENSE'), false);
unset($phar);
}
@@ -139,6 +123,20 @@ class Compiler
return $output;
}
private static function getStubLicense()
{
$license = file_get_contents(__DIR__ . '/../../LICENSE');
$license = str_replace('The MIT License (MIT)', '', $license);
$license = str_replace("\n", "\n * ", trim($license));
return $license;
}
const STUB_AUTOLOAD = <<<'EOS'
Phar::mapPhar('psysh.phar');
require 'phar://psysh.phar/build-vendor/autoload.php';
EOS;
/**
* Get a Phar stub for psysh.
*
@@ -148,14 +146,11 @@ class Compiler
*/
private function getStub()
{
$autoload = <<<'EOS'
Phar::mapPhar('psysh.phar');
require 'phar://psysh.phar/vendor/autoload.php';
EOS;
$content = file_get_contents(__DIR__ . '/../../bin/psysh');
$content = preg_replace('{/\* <<<.*?>>> \*/}sm', $autoload, $content);
$content .= "__HALT_COMPILER();";
$content = preg_replace('{/\* <<<.*?>>> \*/}sm', self::STUB_AUTOLOAD, $content);
$content = preg_replace('/\\(c\\) .*?with this source code./sm', self::getStubLicense(), $content);
$content .= '__HALT_COMPILER();';
return $content;
}

183
vendor/psy/psysh/src/Psy/ConfigPaths.php vendored Normal file
View File

@@ -0,0 +1,183 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy;
use XdgBaseDir\Xdg;
/**
* A Psy Shell configuration path helper.
*/
class ConfigPaths
{
/**
* Get potential config directory paths.
*
* Returns `~/.psysh`, `%APPDATA%/PsySH` (when on Windows), and all
* XDG Base Directory config directories:
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*
* @return string[]
*/
public static function getConfigDirs()
{
$xdg = new Xdg();
return self::getDirNames($xdg->getConfigDirs());
}
/**
* Get potential home config directory paths.
*
* Returns `~/.psysh`, `%APPDATA%/PsySH` (when on Windows), and the
* XDG Base Directory home config directory:
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*
* @return string[]
*/
public static function getHomeConfigDirs()
{
$xdg = new Xdg();
return self::getDirNames(array($xdg->getHomeConfigDir()));
}
/**
* Get the current home config directory.
*
* Returns the highest precedence home config directory which actually
* exists. If none of them exists, returns the highest precedence home
* config directory (`%APPDATA%/PsySH` on Windows, `~/.config/psysh`
* everywhere else).
*
* @see self::getHomeConfigDirs
*
* @return string
*/
public static function getCurrentConfigDir()
{
$configDirs = self::getHomeConfigDirs();
foreach ($configDirs as $configDir) {
if (@is_dir($configDir)) {
return $configDir;
}
}
return $configDirs[0];
}
/**
* Find real config files in config directories.
*
* @param string[] $names Config file names
* @param string $configDir Optionally use a specific config directory
*
* @return string[]
*/
public static function getConfigFiles(array $names, $configDir = null)
{
$dirs = ($configDir === null) ? self::getConfigDirs() : array($configDir);
return self::getRealFiles($dirs, $names);
}
/**
* Get potential data directory paths.
*
* If a `dataDir` option was explicitly set, returns an array containing
* just that directory.
*
* Otherwise, it returns `~/.psysh` and all XDG Base Directory data directories:
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*
* @return string[]
*/
public static function getDataDirs()
{
$xdg = new Xdg();
return self::getDirNames($xdg->getDataDirs());
}
/**
* Find real data files in config directories.
*
* @param string[] $names Config file names
* @param string $dataDir Optionally use a specific config directory
*
* @return string[]
*/
public static function getDataFiles(array $names, $dataDir = null)
{
$dirs = ($dataDir === null) ? self::getDataDirs() : array($dataDir);
return self::getRealFiles($dirs, $names);
}
/**
* Get a runtime directory.
*
* Defaults to `/psysh` inside the system's temp dir.
*
* @return string
*/
public static function getRuntimeDir()
{
$xdg = new Xdg();
return $xdg->getRuntimeDir(false) . '/psysh';
}
private static function getDirNames(array $baseDirs)
{
$dirs = array_map(function ($dir) {
return strtr($dir, '\\', '/') . '/psysh';
}, $baseDirs);
// Add ~/.psysh
if ($home = getenv('HOME')) {
$dirs[] = strtr($home, '\\', '/') . '/.psysh';
}
// Add some Windows specific ones :)
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
if ($appData = getenv('APPDATA')) {
// AppData gets preference
array_unshift($dirs, strtr($appData, '\\', '/') . '/PsySH');
}
$dir = strtr(getenv('HOMEDRIVE') . '/' . getenv('HOMEPATH'), '\\', '/') . '/.psysh';
if (!in_array($dir, $dirs)) {
$dirs[] = $dir;
}
}
return $dirs;
}
private static function getRealFiles(array $dirNames, array $fileNames)
{
$files = array();
foreach ($dirNames as $dir) {
foreach ($fileNames as $name) {
$file = $dir . '/' . $name;
if (@is_file($file)) {
$files[] = $file;
}
}
}
return $files;
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,17 +11,18 @@
namespace Psy;
use Psy\Exception\DeprecatedException;
use Psy\Exception\RuntimeException;
use Psy\ExecutionLoop\ForkingLoop;
use Psy\ExecutionLoop\Loop;
use Psy\Output\OutputPager;
use Psy\Output\ShellOutput;
use Psy\Presenter\PresenterManager;
use Psy\Readline\GNUReadline;
use Psy\Readline\Libedit;
use Psy\Readline\Readline;
use Psy\Readline\Transient;
use Psy\TabCompletion\AutoCompleter;
use Psy\VarDumper\Presenter;
use XdgBaseDir\Xdg;
/**
@@ -29,10 +30,16 @@ use XdgBaseDir\Xdg;
*/
class Configuration
{
const COLOR_MODE_AUTO = 'auto';
const COLOR_MODE_FORCED = 'forced';
const COLOR_MODE_DISABLED = 'disabled';
private static $AVAILABLE_OPTIONS = array(
'defaultIncludes', 'useReadline', 'usePcntl', 'codeCleaner', 'pager',
'loop', 'configDir', 'dataDir', 'runtimeDir', 'manualDbFile',
'requireSemicolons', 'historySize', 'eraseDuplicates', 'tabCompletion',
'requireSemicolons', 'useUnicode', 'historySize', 'eraseDuplicates',
'tabCompletion', 'errorLoggingLevel', 'warnOnMultipleConfigs',
'colorMode',
);
private $defaultIncludes;
@@ -50,8 +57,12 @@ class Configuration
private $usePcntl;
private $newCommands = array();
private $requireSemicolons = false;
private $useUnicode;
private $tabCompletion;
private $tabCompletionMatchers = array();
private $errorLoggingLevel = E_ALL;
private $warnOnMultipleConfigs = false;
private $colorMode;
// services
private $readline;
@@ -61,7 +72,7 @@ class Configuration
private $pager;
private $loop;
private $manualDb;
private $presenters;
private $presenter;
private $completer;
/**
@@ -73,6 +84,8 @@ class Configuration
*/
public function __construct(array $config = array())
{
$this->setColorMode(self::COLOR_MODE_AUTO);
// explicit configFile option
if (isset($config['configFile'])) {
$this->configFile = $config['configFile'];
@@ -84,10 +97,7 @@ class Configuration
if (isset($config['baseDir'])) {
$msg = "The 'baseDir' configuration option is deprecated. " .
"Please specify 'configDir' and 'dataDir' options instead.";
trigger_error($msg, E_USER_DEPRECATED);
$this->setConfigDir($config['baseDir']);
$this->setDataDir($config['baseDir']);
throw new DeprecatedException($msg);
}
unset($config['configFile'], $config['baseDir']);
@@ -103,6 +113,9 @@ class Configuration
* This checks for the presence of Readline and Pcntl extensions.
*
* If a config file is available, it will be loaded and merged with the current config.
*
* If no custom config file was specified and a local project config file
* is available, it will be loaded and merged with the current config.
*/
public function init()
{
@@ -113,6 +126,10 @@ class Configuration
if ($configFile = $this->getConfigFile()) {
$this->loadConfigFile($configFile);
}
if (!$this->configFile && $localConfig = $this->getLocalConfigFile()) {
$this->loadConfigFile($localConfig);
}
}
/**
@@ -135,111 +152,33 @@ class Configuration
return $this->configFile;
}
foreach ($this->getConfigDirs() as $dir) {
$file = $dir . '/config.php';
if (@is_file($file)) {
return $this->configFile = $file;
$files = ConfigPaths::getConfigFiles(array('config.php', 'rc.php'), $this->configDir);
if (!empty($files)) {
if ($this->warnOnMultipleConfigs && count($files) > 1) {
$msg = sprintf('Multiple configuration files found: %s. Using %s', implode($files, ', '), $files[0]);
trigger_error($msg, E_USER_NOTICE);
}
$file = $dir . '/rc.php';
if (@is_file($file)) {
return $this->configFile = $file;
}
return $files[0];
}
}
/**
* Helper function to get the proper home directory.
* Get the local PsySH config file.
*
* Searches for a project specific config file `.psysh.php` in the current
* working directory.
*
* @return string
*/
private function getPsyHome()
public function getLocalConfigFile()
{
if ($home = getenv('HOME')) {
return $home . '/.psysh';
$localConfig = getenv('PWD') . '/.psysh.php';
if (@is_file($localConfig)) {
return $localConfig;
}
if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
// Check the old default
$oldHome = strtr(getenv('HOMEDRIVE') . '/' . getenv('HOMEPATH') . '/.psysh', '\\', '/');
if ($appData = getenv('APPDATA')) {
$home = strtr($appData, '\\', '/') . '/PsySH';
if (is_dir($oldHome) && !is_dir($home)) {
$msg = sprintf(
"Config directory found at '%s'. Please move it to '%s'.",
strtr($oldHome, '/', '\\'),
strtr($home, '/', '\\')
);
trigger_error($msg, E_USER_DEPRECATED);
return $oldHome;
}
return $home;
}
}
}
/**
* Get potential config directory paths.
*
* If a `configDir` option was explicitly set, returns an array containing
* just that directory.
*
* Otherwise, it returns `~/.psysh` and all XDG Base Directory config directories:
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*
* @return string[]
*/
protected function getConfigDirs()
{
if (isset($this->configDir)) {
return array($this->configDir);
}
$xdg = new Xdg();
$dirs = array_map(function ($dir) {
return $dir . '/psysh';
}, $xdg->getConfigDirs());
if ($home = $this->getPsyHome()) {
array_unshift($dirs, $home);
}
return $dirs;
}
/**
* Get potential data directory paths.
*
* If a `dataDir` option was explicitly set, returns an array containing
* just that directory.
*
* Otherwise, it returns `~/.psysh` and all XDG Base Directory data directories:
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
*
* @return string[]
*/
protected function getDataDirs()
{
if (isset($this->dataDir)) {
return array($this->dataDir);
}
$xdg = new Xdg();
$dirs = array_map(function ($dir) {
return $dir . '/psysh';
}, $xdg->getDataDirs());
if ($home = $this->getPsyHome()) {
array_unshift($dirs, $home);
}
return $dirs;
}
/**
@@ -256,7 +195,7 @@ class Configuration
}
}
foreach (array('commands', 'tabCompletionMatchers', 'presenters') as $option) {
foreach (array('commands', 'tabCompletionMatchers', 'casters') as $option) {
if (isset($options[$option])) {
$method = 'add' . ucfirst($option);
$this->$method($options[$option]);
@@ -376,8 +315,7 @@ class Configuration
public function getRuntimeDir()
{
if (!isset($this->runtimeDir)) {
$xdg = new Xdg();
$this->runtimeDir = $xdg->getRuntimeDir() . '/psysh';
$this->runtimeDir = ConfigPaths::getRuntimeDir();
}
if (!is_dir($this->runtimeDir)) {
@@ -387,30 +325,6 @@ class Configuration
return $this->runtimeDir;
}
/**
* @deprecated Use setRuntimeDir() instead.
*
* @param string $dir
*/
public function setTempDir($dir)
{
trigger_error("'setTempDir' is deprecated. Use 'setRuntimeDir' instead.", E_USER_DEPRECATED);
return $this->setRuntimeDir($dir);
}
/**
* @deprecated Use getRuntimeDir() instead.
*
* @return string
*/
public function getTempDir()
{
trigger_error("'getTempDir' is deprecated. Use 'getRuntimeDir' instead.", E_USER_DEPRECATED);
return $this->getRuntimeDir();
}
/**
* Set the readline history file path.
*
@@ -435,33 +349,42 @@ class Configuration
return $this->historyFile;
}
foreach ($this->getConfigDirs() as $dir) {
$file = $dir . '/psysh_history';
if (@is_file($file)) {
return $this->historyFile = $file;
}
// Deprecation warning for incorrect psysh_history path.
// TODO: remove this before v0.8.0
$xdg = new Xdg();
$oldHistory = $xdg->getHomeConfigDir() . '/psysh_history';
if (@is_file($oldHistory)) {
$dir = $this->configDir ?: ConfigPaths::getCurrentConfigDir();
$newHistory = $dir . '/psysh_history';
$file = $dir . '/history';
if (@is_file($file)) {
return $this->historyFile = $file;
}
$msg = sprintf(
"PsySH history file found at '%s'. Please delete it or move it to '%s'.",
strtr($oldHistory, '\\', '/'),
$newHistory
);
trigger_error($msg, E_USER_DEPRECATED);
return $this->historyFile = $oldHistory;
}
// fallback: create our own
if (isset($this->configDir)) {
$dir = $this->configDir;
} else {
$xdg = new Xdg();
$dir = $xdg->getHomeConfigDir();
$files = ConfigPaths::getConfigFiles(array('psysh_history', 'history'), $this->configDir);
if (!empty($files)) {
if ($this->warnOnMultipleConfigs && count($files) > 1) {
$msg = sprintf('Multiple history files found: %s. Using %s', implode($files, ', '), $files[0]);
trigger_error($msg, E_USER_NOTICE);
}
return $this->historyFile = $files[0];
}
// fallback: create our own history file
$dir = $this->configDir ?: ConfigPaths::getCurrentConfigDir();
if (!is_dir($dir)) {
mkdir($dir, 0700, true);
}
$file = $dir . '/psysh_history';
return $this->historyFile = $file;
return $this->historyFile = $dir . '/psysh_history';
}
/**
@@ -683,6 +606,69 @@ class Configuration
return $this->requireSemicolons;
}
/**
* Enable or disable Unicode in PsySH specific output.
*
* Note that this does not disable Unicode output in general, it just makes
* it so PsySH won't output any itself.
*
* @param bool $useUnicode
*/
public function setUseUnicode($useUnicode)
{
$this->useUnicode = (bool) $useUnicode;
}
/**
* Check whether to use Unicode in PsySH specific output.
*
* Note that this does not disable Unicode output in general, it just makes
* it so PsySH won't output any itself.
*
* @return bool
*/
public function useUnicode()
{
if (isset($this->useUnicode)) {
return $this->useUnicode;
}
// TODO: detect `chsh` != 65001 on Windows and return false
return true;
}
/**
* Set the error logging level.
*
* @see self::errorLoggingLevel
*
* @param bool $errorLoggingLevel
*/
public function setErrorLoggingLevel($errorLoggingLevel)
{
$this->errorLoggingLevel = (E_ALL | E_STRICT) & $errorLoggingLevel;
}
/**
* Get the current error logging level.
*
* By default, PsySH will automatically log all errors, regardless of the
* current `error_reporting` level. Additionally, if the `error_reporting`
* level warrants, an ErrorException will be thrown.
*
* Set `errorLoggingLevel` to 0 to prevent logging non-thrown errors. Set it
* to any valid error_reporting value to log only errors which match that
* level.
*
* http://php.net/manual/en/function.error-reporting.php
*
* @return int
*/
public function errorLoggingLevel()
{
return $this->errorLoggingLevel;
}
/**
* Set a CodeCleaner service instance.
*
@@ -755,12 +741,33 @@ class Configuration
public function getOutput()
{
if (!isset($this->output)) {
$this->output = new ShellOutput(ShellOutput::VERBOSITY_NORMAL, null, null, $this->getPager());
$this->output = new ShellOutput(
ShellOutput::VERBOSITY_NORMAL,
$this->getOutputDecorated(),
null,
$this->getPager()
);
}
return $this->output;
}
/**
* Get the decoration (i.e. color) setting for the Shell Output service.
*
* @return null|bool 3-state boolean corresponding to the current color mode
*/
public function getOutputDecorated()
{
if ($this->colorMode() === self::COLOR_MODE_AUTO) {
return;
} elseif ($this->colorMode() === self::COLOR_MODE_FORCED) {
return true;
} elseif ($this->colorMode() === self::COLOR_MODE_DISABLED) {
return false;
}
}
/**
* Set the OutputPager service.
*
@@ -946,11 +953,14 @@ class Configuration
return $this->manualDbFile;
}
foreach ($this->getDataDirs() as $dir) {
$file = $dir . '/php_manual.sqlite';
if (@is_file($file)) {
return $this->manualDbFile = $file;
$files = ConfigPaths::getDataFiles(array('php_manual.sqlite'), $this->dataDir);
if (!empty($files)) {
if ($this->warnOnMultipleConfigs && count($files) > 1) {
$msg = sprintf('Multiple manual database files found: %s. Using %s', implode($files, ', '), $files[0]);
trigger_error($msg, E_USER_NOTICE);
}
return $this->manualDbFile = $files[0];
}
}
@@ -980,29 +990,85 @@ class Configuration
}
/**
* Add an array of Presenters.
* Add an array of casters definitions.
*
* @param array $presenters
* @param array $casters
*/
public function addPresenters(array $presenters)
public function addCasters(array $casters)
{
$manager = $this->getPresenterManager();
foreach ($presenters as $presenter) {
$manager->addPresenter($presenter);
$this->getPresenter()->addCasters($casters);
}
/**
* Get the Presenter service.
*
* @return Presenter
*/
public function getPresenter()
{
if (!isset($this->presenter)) {
$this->presenter = new Presenter($this->getOutput()->getFormatter());
}
return $this->presenter;
}
/**
* Enable or disable warnings on multiple configuration or data files.
*
* @see self::warnOnMultipleConfigs()
*
* @param bool $warnOnMultipleConfigs
*/
public function setWarnOnMultipleConfigs($warnOnMultipleConfigs)
{
$this->warnOnMultipleConfigs = (bool) $warnOnMultipleConfigs;
}
/**
* Check whether to warn on multiple configuration or data files.
*
* By default, PsySH will use the file with highest precedence, and will
* silently ignore all others. With this enabled, a warning will be emitted
* (but not an exception thrown) if multiple configuration or data files
* are found.
*
* This will default to true in a future release, but is false for now.
*
* @return bool
*/
public function warnOnMultipleConfigs()
{
return $this->warnOnMultipleConfigs;
}
/**
* Set the current color mode.
*
* @param string $colorMode
*/
public function setColorMode($colorMode)
{
$validColorModes = array(
self::COLOR_MODE_AUTO,
self::COLOR_MODE_FORCED,
self::COLOR_MODE_DISABLED,
);
if (in_array($colorMode, $validColorModes)) {
$this->colorMode = $colorMode;
} else {
throw new \InvalidArgumentException('invalid color mode: ' . $colorMode);
}
}
/**
* Get the PresenterManager service.
* Get the current color mode.
*
* @return PresenterManager
* @return string
*/
public function getPresenterManager()
public function colorMode()
{
if (!isset($this->presenters)) {
$this->presenters = new PresenterManager();
}
return $this->presenters;
return $this->colorMode;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy;
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
/**
* Builds `ConsoleColor` instances configured according to the given color mode.
*/
class ConsoleColorFactory
{
private $colorMode;
/**
* @param string $colorMode
*/
public function __construct($colorMode)
{
$this->colorMode = $colorMode;
}
/**
* Get a `ConsoleColor` instance configured according to the given color
* mode.
*
* @return ConsoleColor
*/
public function getConsoleColor()
{
if ($this->colorMode === Configuration::COLOR_MODE_AUTO) {
return $this->getDefaultConsoleColor();
} elseif ($this->colorMode === Configuration::COLOR_MODE_FORCED) {
return $this->getForcedConsoleColor();
} elseif ($this->colorMode === Configuration::COLOR_MODE_DISABLED) {
return $this->getDisabledConsoleColor();
}
}
private function getDefaultConsoleColor()
{
$color = new ConsoleColor();
$color->addTheme(Highlighter::LINE_NUMBER, array('blue'));
return $color;
}
private function getForcedConsoleColor()
{
$color = $this->getDefaultConsoleColor();
$color->setForceStyle(true);
return $color;
}
private function getDisabledConsoleColor()
{
$color = new ConsoleColor();
$color->addTheme(Highlighter::TOKEN_STRING, array('none'));
$color->addTheme(Highlighter::TOKEN_COMMENT, array('none'));
$color->addTheme(Highlighter::TOKEN_KEYWORD, array('none'));
$color->addTheme(Highlighter::TOKEN_DEFAULT, array('none'));
$color->addTheme(Highlighter::TOKEN_HTML, array('none'));
$color->addTheme(Highlighter::ACTUAL_LINE_MARK, array('none'));
$color->addTheme(Highlighter::LINE_NUMBER, array('none'));
return $color;
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -21,7 +21,7 @@ class BreakException extends \Exception implements Exception
/**
* {@inheritdoc}
*/
public function __construct($message = "", $code = 0, \Exception $previous = null)
public function __construct($message = '', $code = 0, \Exception $previous = null)
{
$this->rawMessage = $message;
parent::__construct(sprintf('Exit: %s', $message), $code, $previous);

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Exception;
/**
* A DeprecatedException for Psy.
*/
class DeprecatedException extends RuntimeException
{
// This space intentionally left blank.
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -28,12 +28,12 @@ class ErrorException extends \ErrorException implements Exception
* @param int $lineno (default: null)
* @param Exception $previous (default: null)
*/
public function __construct($message = "", $code = 0, $severity = 1, $filename = null, $lineno = null, $previous = null)
public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, $previous = null)
{
$this->rawMessage = $message;
if (!empty($filename) && preg_match('{Psy[/\\\\]ExecutionLoop}', $filename)) {
$filename = null;
$filename = '';
}
switch ($severity) {
@@ -83,6 +83,6 @@ class ErrorException extends \ErrorException implements Exception
*/
public static function throwException($errno, $errstr, $errfile, $errline)
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
throw new self($errstr, 0, $errno, $errfile, $errline);
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -28,7 +28,7 @@ class FatalErrorException extends \ErrorException implements Exception
* @param int $lineno (default: null)
* @param \Exception $previous (default: null)
*/
public function __construct($message = "", $code = 0, $severity = 9000, $filename = null, $lineno = null, $previous = null)
public function __construct($message = '', $code = 0, $severity = 9000, $filename = null, $lineno = null, $previous = null)
{
$this->rawMessage = $message;
$message = sprintf('PHP Fatal error: %s in %s on line %d', $message, $filename ?: "eval()'d code", $lineno);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -22,7 +22,7 @@ class ParseErrorException extends \PhpParser\Error implements Exception
* @param string $message (default: "")
* @param int $line (default: -1)
*/
public function __construct($message = "", $line = -1)
public function __construct($message = '', $line = -1)
{
$message = sprintf('PHP Parse error: %s', $message);
parent::__construct($message, $line);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -25,7 +25,7 @@ class RuntimeException extends \RuntimeException implements Exception
* @param int $code (default: 0)
* @param \Exception $previous (default: null)
*/
public function __construct($message = "", $code = 0, \Exception $previous = null)
public function __construct($message = '', $code = 0, \Exception $previous = null)
{
$this->rawMessage = $message;
parent::__construct($message, $code, $previous);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -0,0 +1,55 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Exception;
/**
* A "type error" Exception for Psy.
*/
class TypeErrorException extends \Exception implements Exception
{
private $rawMessage;
/**
* Constructor!
*
* @param string $message (default: "")
* @param int $code (default: 0)
*/
public function __construct($message = '', $code = 0)
{
$this->rawMessage = $message;
$message = preg_replace('/, called in .*?: eval\\(\\)\'d code/', '', $message);
parent::__construct(sprintf('TypeError: %s', $message), $code);
}
/**
* Get the raw (unformatted) message for this error.
*
* @return string
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Create a TypeErrorException from a TypeError.
*
* @param \TypeError $e
*
* @return TypeErrorException
*/
public static function fromTypeError(\TypeError $e)
{
return new self($e->getMessage(), $e->getLine());
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -149,15 +149,26 @@ class ForkingLoop extends Loop
private function serializeReturn(array $return)
{
$serializable = array();
foreach ($return as $key => $value) {
// No need to return magic variables
if ($key === '_' || $key === '_e') {
continue;
}
// Resources don't error, but they don't serialize well either.
if (is_resource($value) || $value instanceof \Closure) {
continue;
}
try {
serialize($value);
@serialize($value);
$serializable[$key] = $value;
} catch (\Exception $e) {
// we'll just ignore this one...
}
}
return serialize($serializable);
return @serialize($serializable);
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -14,6 +14,7 @@ namespace Psy\ExecutionLoop;
use Psy\Configuration;
use Psy\Exception\BreakException;
use Psy\Exception\ThrowUpException;
use Psy\Exception\TypeErrorException;
use Psy\Shell;
/**
@@ -21,6 +22,8 @@ use Psy\Shell;
*/
class Loop
{
const NOOP_INPUT = 'return null;';
/**
* Loop constructor.
*
@@ -73,7 +76,7 @@ class Loop
);
set_error_handler(array($__psysh__, 'handleError'));
$_ = eval($__psysh__->flushCode());
$_ = eval($__psysh__->flushCode() ?: Loop::NOOP_INPUT);
restore_error_handler();
ob_end_flush();
@@ -95,6 +98,12 @@ class Loop
$__psysh__->writeException($_e);
throw $_e;
} catch (\TypeError $_e) {
restore_error_handler();
if (ob_get_level() > 0) {
ob_end_clean();
}
$__psysh__->writeException(TypeErrorException::fromTypeError($_e));
} catch (\Exception $_e) {
restore_error_handler();
if (ob_get_level() > 0) {
@@ -103,8 +112,6 @@ class Loop
$__psysh__->writeException($_e);
}
// a bit of housekeeping
unset($__psysh_out__);
$__psysh__->afterLoop();
} while (true);
};
@@ -153,7 +160,7 @@ class Loop
/**
* Decide whether to bind the execution loop.
*
* @return boolean
* @return bool
*/
protected static function bindLoop()
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,8 +11,9 @@
namespace Psy\Formatter;
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
use Psy\Configuration;
use Psy\ConsoleColorFactory;
use Psy\Exception\RuntimeException;
/**
@@ -23,12 +24,15 @@ class CodeFormatter implements Formatter
/**
* Format the code represented by $reflector.
*
* @param \Reflector $reflector
* @param \Reflector $reflector
* @param null|string $colorMode (default: null)
*
* @return string formatted code
*/
public static function format(\Reflector $reflector)
public static function format(\Reflector $reflector, $colorMode = null)
{
$colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
if ($fileName = $reflector->getFileName()) {
if (!is_file($fileName)) {
throw new RuntimeException('Source code unavailable.');
@@ -38,8 +42,8 @@ class CodeFormatter implements Formatter
$start = $reflector->getStartLine();
$end = $reflector->getEndLine() - $start;
$colors = new ConsoleColor();
$colors->addTheme('line_number', array('blue'));
$factory = new ConsoleColorFactory($colorMode);
$colors = $factory->getConsoleColor();
$highlighter = new Highlighter($colors);
return $highlighter->getCodeSnippet($file, $start, 0, $end);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -111,6 +111,8 @@ class SignatureFormatter implements Formatter
$interfaces = $reflector->getInterfaceNames();
if (!empty($interfaces)) {
sort($interfaces);
$chunks[] = 'implements';
$chunks[] = implode(', ', array_map(function ($name) {
return sprintf('<class>%s</class>', $name);

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -43,8 +43,8 @@ class ProcOutputPager extends StreamOutput implements OutputPager
/**
* Writes a message to the output.
*
* @param string $message A message to write to the output
* @param Boolean $newline Whether to add a newline or not
* @param string $message A message to write to the output
* @param bool $newline Whether to add a newline or not
*
* @throws \RuntimeException When unable to write output (should never happen)
*/

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,6 +11,7 @@
namespace Psy\Output;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Output\ConsoleOutput;
@@ -28,7 +29,7 @@ class ShellOutput extends ConsoleOutput
* Construct a ShellOutput instance.
*
* @param mixed $verbosity (default: self::VERBOSITY_NORMAL)
* @param boolean $decorated (default: null)
* @param bool $decorated (default: null)
* @param OutputFormatterInterface $formatter (default: null)
* @param null|string|OutputPager $pager (default: null)
*/
@@ -109,8 +110,8 @@ class ShellOutput extends ConsoleOutput
* @throws \InvalidArgumentException When unknown output type is given
*
* @param string|array $messages The message as an array of lines or a single string
* @param Boolean $newline Whether to add a newline or not
* @param integer $type The type of output
* @param bool $newline Whether to add a newline or not
* @param int $type The type of output
*/
public function write($messages, $newline = false, $type = 0)
{
@@ -144,8 +145,8 @@ class ShellOutput extends ConsoleOutput
*
* Handles paged output, or writes directly to the output stream.
*
* @param string $message A message to write to the output
* @param Boolean $newline Whether to add a newline or not
* @param string $message A message to write to the output
* @param bool $newline Whether to add a newline or not
*/
public function doWrite($message, $newline)
{
@@ -188,6 +189,7 @@ class ShellOutput extends ConsoleOutput
$formatter->setStyle('const', new OutputFormatterStyle('cyan'));
$formatter->setStyle('class', new OutputFormatterStyle('blue', null, array('underscore')));
$formatter->setStyle('function', new OutputFormatterStyle(null));
$formatter->setStyle('default', new OutputFormatterStyle(null));
// Types
$formatter->setStyle('number', new OutputFormatterStyle('magenta'));

View File

@@ -0,0 +1,91 @@
<?php
/*
* This file is part of Psy Shell.
*
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy;
use PhpParser\Lexer;
use PhpParser\Parser;
use PhpParser\ParserFactory as OriginalParserFactory;
/**
* Parser factory to abstract over PHP parser library versions.
*/
class ParserFactory
{
const ONLY_PHP5 = 'ONLY_PHP5';
const ONLY_PHP7 = 'ONLY_PHP7';
const PREFER_PHP5 = 'PREFER_PHP5';
const PREFER_PHP7 = 'PREFER_PHP7';
/**
* Possible kinds of parsers for the factory, from PHP parser library.
*
* @return array
*/
public static function getPossibleKinds()
{
return array('ONLY_PHP5', 'ONLY_PHP7', 'PREFER_PHP5', 'PREFER_PHP7');
}
/**
* Is this parser factory supports kinds?
*
* PHP parser < 2.0 doesn't support kinds, >= 2.0 — does.
*
* @return bool
*/
public function hasKindsSupport()
{
return class_exists('PhpParser\ParserFactory');
}
/**
* Default kind (if supported, based on current interpreter's version).
*
* @return string|null
*/
public function getDefaultKind()
{
if ($this->hasKindsSupport()) {
return version_compare(PHP_VERSION, '7.0', '>=') ? static::ONLY_PHP7 : static::ONLY_PHP5;
}
}
/**
* New parser instance with given kind.
*
* @param string|null $kind One of class constants (only for PHP parser 2.0 and above).
*
* @return Parser
*/
public function createParser($kind = null)
{
if ($this->hasKindsSupport()) {
$originalFactory = new OriginalParserFactory();
$kind = $kind ?: $this->getDefaultKind();
if (!in_array($kind, static::getPossibleKinds())) {
throw new \InvalidArgumentException('Unknown parser kind');
}
$parser = $originalFactory->create(constant('PhpParser\ParserFactory::' . $kind));
} else {
if ($kind !== null) {
throw new \InvalidArgumentException('Install PHP Parser v2.x to specify parser kind');
}
$parser = new Parser(new Lexer());
}
return $parser;
}
}

View File

@@ -1,174 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
use Psy\Util\Json;
/**
* An array Presenter.
*/
class ArrayPresenter extends RecursivePresenter
{
const ARRAY_OBJECT_FMT = '<object>\\<<class>%s</class> <strong>#%s</strong>></object>';
/**
* ArrayPresenter can present arrays.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return is_array($value) || $this->isArrayObject($value);
}
/**
* Determine whether something is an ArrayObject.
*
* This is a useful extension point for Presenter subclasses for Array-like
* objects which aren't necessarily subclasses of ArrayObject.
*
* @return boolean
*/
protected function isArrayObject($value)
{
return $value instanceof \ArrayObject;
}
/**
* Present a reference to the array.
*
* @param array $value
*
* @return string
*/
public function presentRef($value)
{
if ($this->isArrayObject($value)) {
return $this->presentArrayObjectRef($value);
} elseif (empty($value)) {
return '[]';
} else {
return sprintf('Array(<number>%d</number>)', count($value));
}
}
/**
* Present a reference to an ArrayObject.
*
* @param ArrayObject $value
*
* @return string
*/
protected function presentArrayObjectRef($value)
{
return sprintf(self::ARRAY_OBJECT_FMT, get_class($value), spl_object_hash($value));
}
/**
* Get an array of values from an ArrayObject.
*
* This is a useful extension point for Presenter subclasses for Array-like
* objects which aren't necessarily subclasses of ArrayObject.
*
* @return array
*/
protected function getArrayObjectValue($value)
{
return iterator_to_array($value->getIterator());
}
/**
* Present the array.
*
* @param object $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
protected function presentValue($value, $depth = null, $options = 0)
{
$prefix = '';
if ($this->isArrayObject($value)) {
$prefix = $this->presentArrayObjectRef($value) . ' ';
$value = $this->getArrayObjectValue($value);
}
if (empty($value) || $depth === 0) {
return $prefix . $this->presentRef($value);
}
$formatted = array();
foreach ($value as $key => $val) {
$formatted[$key] = $this->presentSubValue($val);
}
if ($this->shouldShowKeys($value)) {
$pad = max(array_map('strlen', array_map(array('Psy\Util\Json', 'encode'), array_keys($value))));
foreach ($formatted as $key => $val) {
$formatted[$key] = $this->formatKeyAndValue($key, $val, $pad);
}
} else {
$formatted = array_map(array($this, 'indentValue'), $formatted);
}
$template = sprintf('%s[%s%s%%s%s]', $prefix, PHP_EOL, self::INDENT, PHP_EOL);
$glue = sprintf(',%s%s', PHP_EOL, self::INDENT);
return sprintf($template, implode($glue, $formatted));
}
/**
* Helper method for determining whether to render array keys.
*
* Keys are only rendered for associative arrays or non-consecutive integer-
* based arrays.
*
* @param array $array
*
* @return boolean
*/
protected function shouldShowKeys(array $array)
{
$i = 0;
foreach (array_keys($array) as $k) {
if ($k !== $i++) {
return true;
}
}
return false;
}
/**
* Format a key => value pair.
*
* @param mixed $key
* @param string $value
* @param integer $pad Maximum key width, to align the hashrockets.
*
* @return string
*/
protected function formatKeyAndValue($key, $value, $pad = 0)
{
$type = is_string($value) ? 'string' : 'number';
$tpl = "<$type>%-${pad}s</$type> => %s";
return sprintf(
$tpl,
Json::encode($key),
$this->indentValue($value)
);
}
}

View File

@@ -1,173 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* A Closure Presenter.
*/
class ClosurePresenter implements Presenter, PresenterManagerAware
{
const FMT = '<keyword>function</keyword> (%s)%s { <comment>...</comment> }';
const USE_FMT = ' use (%s)';
protected $manager;
/**
* PresenterManagerAware interface.
*
* @param PresenterManager $manager
*/
public function setPresenterManager(PresenterManager $manager)
{
$this->manager = $manager;
}
/**
* ClosurePresenter can present closures.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return $value instanceof \Closure;
}
/**
* Present a reference to the value.
*
* @param mixed $value
*
* @return string
*/
public function presentRef($value)
{
return sprintf(
self::FMT,
$this->formatParams($value),
$this->formatStaticVariables($value)
);
}
/**
* Present the Closure.
*
* @param \Closure $value
* @param int $depth (default:null)
* @param int $options One of Presenter constants
*
* @return string
*/
public function present($value, $depth = null, $options = 0)
{
return $this->presentRef($value);
}
/**
* Format a list of Closure parameters.
*
* @param \Closure $value
*
* @return string
*/
protected function formatParams(\Closure $value)
{
$r = new \ReflectionFunction($value);
$params = array_map(array($this, 'formatParam'), $r->getParameters());
return implode(', ', $params);
}
/**
* Format an individual Closure parameter.
*
* @param \ReflectionParameter $param
*
* @return string
*/
protected function formatParam(\ReflectionParameter $param)
{
$ret = $this->formatParamName($param->name);
if ($param->isOptional()) {
$ret .= ' = ';
if (self::isParamDefaultValueConstant($param)) {
$name = $param->getDefaultValueConstantName();
$ret .= '<const>' . $name . '</const>';
} elseif ($param->isDefaultValueAvailable()) {
$ret .= $this->manager->presentRef($param->getDefaultValue());
} else {
$ret .= '<urgent>?</urgent>';
}
}
return $ret;
}
/**
* Format static (used) variable names.
*
* @param \Closure $value
*
* @return string
*/
protected function formatStaticVariables(\Closure $value)
{
$r = new \ReflectionFunction($value);
$used = $r->getStaticVariables();
if (empty($used)) {
return '';
}
$names = array_map(array($this, 'formatParamName'), array_keys($used));
return sprintf(
self::USE_FMT,
implode(', ', $names)
);
}
/**
* Format a Closure parameter name.
*
* @param string $name
*
* @return string
*/
protected function formatParamName($name)
{
return sprintf('$<strong>%s</strong>', $name);
}
/**
* Check whether a parameter's default value is a constant.
*
* This is only supported in PHP >= 5.4.3, and currently unimplemented in
* HHVM.
*
* @param \ReflectionParameter $param
*
* @return boolean
*/
protected static function isParamDefaultValueConstant(\ReflectionParameter $param)
{
// HHVM doesn't currently support `isDefaultValueConstant`, skip for now
// see https://github.com/facebook/hhvm/issues/3812
if (defined('HHVM_VERSION')) {
return false;
}
return version_compare(PHP_VERSION, '5.4.3', '>=') && $param->isDefaultValueConstant();
}
}

View File

@@ -1,52 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* An Exception Presenter.
*/
class ExceptionPresenter extends ObjectPresenter
{
/**
* ExceptionPresenter can present Exceptions.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return $value instanceof \Exception;
}
/**
* Get an array of exception object properties.
*
* @param object $value
* @param \ReflectionClass $class
* @param int $options One of Presenter constants
*
* @return array
*/
protected function getProperties($value, \ReflectionClass $class, $options = 0)
{
$props = array(
'<protected>message</protected>' => $value->getMessage(),
'<protected>code</protected>' => $value->getCode(),
'<protected>file</protected>' => $value->getFile(),
'<protected>line</protected>' => $value->getLine(),
'<private>previous</private>' => $value->getPrevious(),
);
return array_merge(array_filter($props), parent::getProperties($value, $class, $options));
}
}

View File

@@ -1,119 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* A Mongo Cursor Presenter.
*/
class MongoCursorPresenter extends ObjectPresenter
{
private static $boringFields = array('limit', 'batchSize', 'skip', 'flags');
private static $ignoreFields = array('server', 'host', 'port', 'connection_type_desc');
/**
* MongoCursorPresenter can present Mongo Cursors.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return $value instanceof \MongoCursor;
}
/**
* Get an array of object properties.
*
* @param object $value
* @param \ReflectionClass $class
* @param int $propertyFilter One of \ReflectionProperty constants
*
* @return array
*/
protected function getProperties($value, \ReflectionClass $class, $propertyFilter)
{
$info = $value->info();
$this->normalizeQueryArray($info);
$this->normalizeFieldsArray($info);
$this->unsetBoringFields($info);
$this->unsetIgnoredFields($info);
if ($value->dead()) {
$info['dead'] = true;
}
return array_merge(
$info,
parent::getProperties($value, $class, $propertyFilter)
);
}
/**
* Normalize (empty) cursor query to always be an actual array.
*
* @param array $info Cursor info
*/
private function normalizeQueryArray(array &$info)
{
if (isset($info['query'])) {
if ($info['query'] === new \StdClass()) {
$info['query'] = array();
} elseif (is_array($info['query']) && isset($info['query']['$query'])) {
if ($info['query']['$query'] === new \StdClass()) {
$info['query']['$query'] = array();
}
}
}
}
/**
* Normalize (empty) cursor fields to always be an actual array.
*
* @param array $info Cursor info
*/
private function normalizeFieldsArray(array &$info)
{
if (isset($info['fields']) && $info['fields'] === new \StdClass()) {
$info['fields'] = array();
}
}
/**
* Unset boring fields from the Cursor info array.
*
* @param array $info Cursor info
*/
private function unsetBoringFields(array &$info)
{
foreach (self::$boringFields as $boring) {
if ($info[$boring] === 0) {
unset($info[$boring]);
}
}
}
/**
* Unset ignored fields from the Cursor info array.
*
* @param array $info Cursor info
*/
private function unsetIgnoredFields(array &$info)
{
foreach (self::$ignoreFields as $ignore) {
if (isset($info[$ignore])) {
unset($info[$ignore]);
}
}
}
}

View File

@@ -1,143 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* An object Presenter.
*/
class ObjectPresenter extends RecursivePresenter
{
const FMT = '<object>\\<<class>%s</class> <strong>#%s</strong>></object>';
/**
* ObjectPresenter can present objects.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return is_object($value);
}
/**
* Present a reference to the object.
*
* @param object $value
*
* @return string
*/
public function presentRef($value)
{
return sprintf(self::FMT, get_class($value), spl_object_hash($value));
}
/**
* Present the object.
*
* @param object $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
protected function presentValue($value, $depth = null, $options = 0)
{
if ($depth === 0) {
return $this->presentRef($value);
}
$class = new \ReflectionObject($value);
$propertyFilter = \ReflectionProperty::IS_PUBLIC;
if ($options & Presenter::VERBOSE) {
$propertyFilter |= \ReflectionProperty::IS_PRIVATE | \ReflectionProperty::IS_PROTECTED;
}
$props = $this->getProperties($value, $class, $propertyFilter);
return sprintf('%s %s', $this->presentRef($value), $this->formatProperties($props));
}
/**
* Format object properties.
*
* @param array $props
*
* @return string
*/
protected function formatProperties($props)
{
if (empty($props)) {
return '{}';
}
$formatted = array();
foreach ($props as $name => $value) {
$formatted[] = sprintf('%s: %s', $name, $this->indentValue($this->presentSubValue($value)));
}
$template = sprintf('{%s%s%%s%s}', PHP_EOL, self::INDENT, PHP_EOL);
$glue = sprintf(',%s%s', PHP_EOL, self::INDENT);
return sprintf($template, implode($glue, $formatted));
}
/**
* Get an array of object properties.
*
* @param object $value
* @param \ReflectionClass $class
* @param int $propertyFilter One of \ReflectionProperty constants
*
* @return array
*/
protected function getProperties($value, \ReflectionClass $class, $propertyFilter)
{
$deprecated = false;
set_error_handler(function ($errno, $errstr) use (&$deprecated) {
if (in_array($errno, array(E_DEPRECATED, E_USER_DEPRECATED))) {
$deprecated = true;
} else {
// not a deprecation error, let someone else handle this
return false;
}
});
$props = array();
foreach ($class->getProperties($propertyFilter) as $prop) {
$deprecated = false;
$prop->setAccessible(true);
$val = $prop->getValue($value);
if (!$deprecated) {
$props[$this->propertyKey($prop)] = $val;
}
}
restore_error_handler();
return $props;
}
protected function propertyKey(\ReflectionProperty $prop)
{
$key = $prop->getName();
if ($prop->isProtected()) {
return sprintf('<protected>%s</protected>', $key);
} elseif ($prop->isPrivate()) {
return sprintf('<private>%s</private>', $key);
}
return $key;
}
}

View File

@@ -1,69 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
use PhpParser\Node;
/**
* A PhpParser Presenter.
*/
class PHPParserPresenter extends ObjectPresenter
{
const FMT = '<object>\\<<class>%s</class>></object>';
/**
* PHPParserPresenter can present parse trees.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return $value instanceof Node;
}
/**
* Present a reference to the object.
*
* @param object $value
*
* @return string
*/
public function presentRef($value)
{
return sprintf(self::FMT, get_class($value));
}
/**
* Get an array of object properties.
*
* @param object $value
* @param \ReflectionClass $class
* @param int $propertyFilter One of \ReflectionProperty constants
*
* @return array
*/
protected function getProperties($value, \ReflectionClass $class, $propertyFilter)
{
$props = array();
$props['type'] = $value->getType();
$props['attributes'] = $value->getAttributes();
foreach ($value->getSubNodeNames() as $name) {
$props[$name] = $value->$name;
}
return $props;
}
}

View File

@@ -1,52 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* Presenter classes are able to pretty-print values for display. Think
* `var_dump`, but with sane and beautiful output.
*/
interface Presenter
{
const VERBOSE = 1;
/**
* Check whether this Presenter can present $value.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value);
/**
* Present a reference to the value.
*
* @param mixed $value
*
* @return string
*/
public function presentRef($value);
/**
* Present a full representation of the value.
*
* Optionally pass a $depth argument to limit the depth of recursive values.
*
* @param mixed $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
public function present($value, $depth = null, $options = 0);
}

View File

@@ -1,177 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* A Presenter manager service.
*
* Presenters are registered with the PresenterManager, which then delegates
* value presentation to the most recently registered Presenter capable of
* presenting that value.
*/
class PresenterManager implements Presenter, \IteratorAggregate
{
protected $presenters = array();
/**
* PresenterManager constructor.
*
* Initializes default Presenters.
*/
public function __construct()
{
$this->addPresenters(array(
new ObjectPresenter(), // lowest precedence
new ArrayPresenter(),
new ClosurePresenter(),
new ExceptionPresenter(),
new ResourcePresenter(),
new ScalarPresenter(),
));
}
/**
* Register Presenters.
*
* Presenters should be passed in an array from lowest to highest precedence.
*
* @see self::addPresenter
*
* @param Presenter[] $presenters
*/
public function addPresenters(array $presenters)
{
foreach ($presenters as $presenter) {
$this->addPresenter($presenter);
}
}
/**
* Register a Presenter.
*
* If multiple Presenters are able to present a value, the most recently
* registered Presenter takes precedence.
*
* If $presenter is already registered, it will be re-registered as the
* highest precedence Presenter.
*
* @param Presenter $presenter
*/
public function addPresenter(Presenter $presenter)
{
$this->removePresenter($presenter);
if ($presenter instanceof PresenterManagerAware) {
$presenter->setPresenterManager($this);
}
array_unshift($this->presenters, $presenter);
}
/**
* Unregister a Presenter.
*
* @param Presenter $presenter
*/
public function removePresenter(Presenter $presenter)
{
foreach ($this->presenters as $i => $p) {
if ($p === $presenter) {
unset($this->presenters[$i]);
}
}
}
/**
* Check whether a Presenter is registered for $value.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return $this->getPresenter($value) !== null;
}
/**
* Present a reference to the value.
*
* @param mixed $value
*
* @throws \InvalidArgumentException If no Presenter is registered for $value
*
* @return string
*/
public function presentRef($value)
{
if ($presenter = $this->getPresenter($value)) {
return $presenter->presentRef($value);
}
throw new \InvalidArgumentException(sprintf('Unable to present %s', $value));
}
/**
* Present a full representation of the value.
*
* If $depth is 0, the value will be presented as a ref instead.
*
* @param mixed $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @throws \InvalidArgumentException If no Presenter is registered for $value
*
* @return string
*/
public function present($value, $depth = null, $options = 0)
{
if ($presenter = $this->getPresenter($value)) {
if ($depth === 0) {
return $presenter->presentRef($value);
}
return $presenter->present($value, $depth, $options);
}
throw new \InvalidArgumentException(sprintf('Unable to present %s', $value));
}
/**
* IteratorAggregate interface.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator(array_reverse($this->presenters));
}
/**
* Find the highest precedence Presenter available for $value.
*
* Returns null if none is present.
*
* @param mixed $value
*
* @return null|Presenter
*/
protected function getPresenter($value)
{
foreach ($this->presenters as $presenter) {
if ($presenter->canPresent($value)) {
return $presenter;
}
}
}
}

View File

@@ -1,26 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* PresenterManager injects itself as a dependency to all Presenters which
* implement PresenterManagerAware.
*/
interface PresenterManagerAware
{
/**
* Set a reference to the PresenterManager.
*
* @param PresenterManager $manager
*/
public function setPresenterManager(PresenterManager $manager);
}

View File

@@ -1,113 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* An abstract Presenter capable of recursively presenting sub-values.
*/
abstract class RecursivePresenter implements Presenter, PresenterManagerAware
{
const MAX_DEPTH = 5;
const INDENT = ' ';
protected $manager;
protected $depth;
/**
* PresenterManagerAware interface.
*
* @param PresenterManager $manager
*/
public function setPresenterManager(PresenterManager $manager)
{
$this->manager = $manager;
}
/**
* Present the recursive value.
*
* Subclasses should implement `presentValue` rather than overriding this
* method.
*
* @see self::presentValue()
*
* @param mixed $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
public function present($value, $depth = null, $options = 0)
{
$this->setDepth($depth);
return $this->presentValue($value, $depth, $options);
}
/**
* RecursivePresenter subclasses implement a `presentValue` method for
* actually doing the presentation.
*
* @param mixed $value
*
* @return string
*/
abstract protected function presentValue($value);
/**
* Keep track of the remaining recursion depth.
*
* If $depth is null, set it to `self::MAX_DEPTH`.
*
* @param int $depth (default: null)
*/
protected function setDepth($depth = null)
{
$this->depth = $depth === null ? self::MAX_DEPTH : $depth;
}
/**
* Present a sub-value.
*
* If the current recursion depth is greater than self::MAX_DEPTH, it will
* present a reference, otherwise it will present the full representation
* of the sub-value.
*
* @see PresenterManager::present()
* @see PresenterManager::presentRef()
*
* @param mixed $value
* @param int $options One of Presenter constants
*
* @return string
*/
protected function presentSubValue($value, $options = 0)
{
$depth = $this->depth;
$formatted = $this->manager->present($value, $depth - 1, $options);
$this->setDepth($depth);
return $formatted;
}
/**
* Indent every line of a value.
*
* @param string $value
*
* @return string
*/
protected function indentValue($value)
{
return str_replace(PHP_EOL, PHP_EOL . self::INDENT, $value);
}
}

View File

@@ -1,115 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
/**
* A resource Presenter.
*/
class ResourcePresenter extends RecursivePresenter
{
const FMT = '<resource>\\<%s <strong>resource #%s</strong>></resource>';
/**
* Resource presenter can present resources.
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return is_resource($value);
}
/**
* Present a reference to the value.
*
* @param mixed $value
*
* @return string
*/
public function presentRef($value)
{
$type = get_resource_type($value);
if ($type === 'stream') {
$meta = stream_get_meta_data($value);
$type = sprintf('%s stream', $meta['stream_type']);
}
$id = str_replace('Resource id #', '', (string) $value);
return sprintf(self::FMT, $type, $id);
}
/**
* Present the resource.
*
* @param resource $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
public function presentValue($value, $depth = null, $options = 0)
{
if ($depth === 0 || !($options & Presenter::VERBOSE)) {
return $this->presentRef($value);
}
return sprintf('%s %s', $this->presentRef($value), $this->formatMetadata($value));
}
/**
* Format resource metadata.
*
* @param resource $value
*
* @return string
*/
protected function formatMetadata($value)
{
$props = array();
switch (get_resource_type($value)) {
case 'stream':
$props = stream_get_meta_data($value);
break;
case 'curl':
$props = curl_getinfo($value);
break;
case 'xml':
$props = array(
'current_byte_index' => xml_get_current_byte_index($value),
'current_column_number' => xml_get_current_column_number($value),
'current_line_number' => xml_get_current_line_number($value),
'error_code' => xml_get_error_code($value),
);
break;
}
if (empty($props)) {
return '{}';
}
$formatted = array();
foreach ($props as $name => $value) {
$formatted[] = sprintf('%s: %s', $name, $this->indentValue($this->presentSubValue($value)));
}
$template = sprintf('{%s%s%%s%s}', PHP_EOL, self::INDENT, PHP_EOL);
$glue = sprintf(',%s%s', PHP_EOL, self::INDENT);
return sprintf($template, implode($glue, $formatted));
}
}

View File

@@ -1,109 +0,0 @@
<?php
/*
* This file is part of Psy Shell
*
* (c) 2012-2014 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Psy\Presenter;
use Psy\Util\Json;
use Symfony\Component\Console\Formatter\OutputFormatter;
/**
* A scalar (and null) Presenter.
*/
class ScalarPresenter implements Presenter
{
/**
* Scalar presenter can present scalars and null.
*
* Technically this would make it a ScalarOrNullPresenter, but that's a much
* lamer name :)
*
* @param mixed $value
*
* @return boolean
*/
public function canPresent($value)
{
return is_scalar($value) || is_null($value);
}
/**
* Present a reference to the value.
*
* @param mixed $value
*
* @return string
*/
public function presentRef($value)
{
return $this->present($value);
}
/**
* Present the scalar value.
*
* @param mixed $value
* @param int $depth (default: null)
* @param int $options One of Presenter constants
*
* @return string
*/
public function present($value, $depth = null, $options = 0)
{
$formatted = $this->format($value);
if ($typeStyle = $this->getTypeStyle($value)) {
return sprintf('<%s>%s</%s>', $typeStyle, $formatted, $typeStyle);
} else {
return $formatted;
}
}
private function format($value)
{
// Handle floats.
if (is_float($value)) {
// Some are unencodable...
if (is_nan($value)) {
return 'NAN';
} elseif (is_infinite($value)) {
return $value === INF ? 'INF' : '-INF';
}
// ... others just encode as ints when there's no decimal
$float = Json::encode($value);
if (strpos($float, '.') === false) {
$float .= '.0';
}
return $float;
}
return OutputFormatter::escape(Json::encode($value));
}
/**
* Get the output style for a value of a given type.
*
* @param mixed $value
*
* @return string
*/
private function getTypeStyle($value)
{
if (is_int($value) || is_float($value)) {
return 'number';
} elseif (is_string($value)) {
return 'string';
} elseif (is_bool($value) || is_null($value)) {
return 'bool';
}
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -47,7 +47,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function addHistory($line)
{
@@ -59,7 +59,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function clearHistory()
{
@@ -71,7 +71,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function listHistory()
{
@@ -79,7 +79,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function readHistory()
{
@@ -99,7 +99,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function readline($prompt = null)
{
@@ -107,7 +107,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function redisplay()
{
@@ -115,7 +115,7 @@ class GNUReadline implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function writeHistory()
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -11,7 +11,7 @@
namespace Psy\Readline;
use Psy\Util\String;
use Psy\Util\Str;
/**
* A Libedit-based Readline implementation.
@@ -25,7 +25,7 @@ class Libedit extends GNUReadline
/**
* Let's emulate GNU Readline by manually reading and parsing the history file!
*
* @return boolean
* @return bool
*/
public static function isSupported()
{
@@ -33,7 +33,7 @@ class Libedit extends GNUReadline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function listHistory()
{
@@ -78,6 +78,6 @@ class Libedit extends GNUReadline
$line = substr($line, 0, $pos);
}
return ($line !== '') ? String::unvis($line) : null;
return ($line !== '') ? Str::unvis($line) : null;
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -19,7 +19,7 @@ interface Readline
/**
* Check whether this Readline class is supported by the current system.
*
* @return boolean
* @return bool
*/
public static function isSupported();

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -25,7 +25,7 @@ class Transient implements Readline
/**
* Transient Readline is always supported.
*
* {@inheritDoc}
* {@inheritdoc}
*/
public static function isSupported()
{
@@ -44,7 +44,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function addHistory($line)
{
@@ -69,7 +69,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function clearHistory()
{
@@ -79,7 +79,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function listHistory()
{
@@ -87,7 +87,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function readHistory()
{
@@ -95,7 +95,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*
* @throws BreakException if user hits Ctrl+D
*
@@ -109,7 +109,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function redisplay()
{
@@ -117,7 +117,7 @@ class Transient implements Readline
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function writeHistory()
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -30,7 +30,7 @@ class ReflectionConstant implements \Reflector
*/
public function __construct($class, $name)
{
if (! $class instanceof \ReflectionClass) {
if (!$class instanceof \ReflectionClass) {
$class = new \ReflectionClass($class);
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -16,8 +16,8 @@ use Psy\Exception\ErrorException;
use Psy\Exception\Exception as PsyException;
use Psy\Exception\ThrowUpException;
use Psy\Output\ShellOutput;
use Psy\Presenter\PresenterManagerAware;
use Psy\TabCompletion\Matcher;
use Psy\VarDumper\PresenterAware;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command as BaseCommand;
use Symfony\Component\Console\Formatter\OutputFormatter;
@@ -41,7 +41,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class Shell extends Application
{
const VERSION = 'v0.4.4';
const VERSION = 'v0.7.2';
const PROMPT = '>>> ';
const BUFF_PROMPT = '... ';
@@ -80,18 +80,6 @@ class Shell extends Application
parent::__construct('Psy Shell', self::VERSION);
$this->config->setShell($this);
// auto completer needs shell to be linked to configuration because of the context aware matchers
if ($this->config->getTabCompletion()) {
$this->completion = $this->config->getAutoCompleter();
$this->addTabCompletionMatchers($this->config->getTabCompletionMatchers());
foreach ($this->getTabCompletionMatchers() as $matcher) {
if ($matcher instanceof ContextAware) {
$matcher->setContext($this->context);
}
$this->completion->addMatcher($matcher);
}
$this->completion->activate();
}
}
/**
@@ -158,7 +146,7 @@ class Shell extends Application
/**
* Adds a command object.
*
* {@inheritDoc}
* {@inheritdoc}
*
* @param BaseCommand $command A Symfony Console Command object
*
@@ -171,8 +159,8 @@ class Shell extends Application
$ret->setContext($this->context);
}
if ($ret instanceof PresenterManagerAware) {
$ret->setPresenterManager($this->config->getPresenterManager());
if ($ret instanceof PresenterAware) {
$ret->setPresenter($this->config->getPresenter());
}
}
@@ -207,9 +195,9 @@ class Shell extends Application
new Command\ListCommand(),
new Command\DumpCommand(),
new Command\DocCommand(),
new Command\ShowCommand(),
new Command\ShowCommand($this->config->colorMode()),
new Command\WtfCommand(),
new Command\WhereamiCommand(),
new Command\WhereamiCommand($this->config->colorMode()),
new Command\ThrowUpCommand(),
new Command\TraceCommand(),
new Command\BufferCommand(),
@@ -267,10 +255,12 @@ class Shell extends Application
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return integer 0 if everything went fine, or an error code
* @return int 0 if everything went fine, or an error code
*/
public function run(InputInterface $input = null, OutputInterface $output = null)
{
$this->initializeTabCompletion();
if ($input === null && !isset($_SERVER['argv'])) {
$input = new ArgvInput(array());
}
@@ -279,7 +269,11 @@ class Shell extends Application
$output = $this->config->getOutput();
}
return parent::run($input, $output);
try {
return parent::run($input, $output);
} catch (\Exception $e) {
$this->writeException($e);
}
}
/**
@@ -290,7 +284,7 @@ class Shell extends Application
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return integer 0 if everything went fine, or an error code
* @return int 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
@@ -299,7 +293,7 @@ class Shell extends Application
$this->resetCodeBuffer();
$this->setAutoExit(false);
$this->setCatchExceptions(true);
$this->setCatchExceptions(false);
$this->readline->readHistory();
@@ -312,8 +306,6 @@ class Shell extends Application
try {
$this->loop->run($this);
} catch (ThrowUpException $e) {
$this->setCatchExceptions(false);
throw $e->getPrevious();
}
}
@@ -612,14 +604,14 @@ class Shell extends Application
}
// Incremental flush
if (!empty($out) && !$isCleaning) {
if ($out !== '' && !$isCleaning) {
$this->output->write($out, false, ShellOutput::OUTPUT_RAW);
$this->outputWantsNewline = (substr($out, -1) !== "\n");
}
// Output buffering is done!
if ($this->outputWantsNewline && $phase & PHP_OUTPUT_HANDLER_END) {
$this->output->writeln('<aside></aside>');
$this->output->writeln(sprintf('<aside>%s</aside>', $this->config->useUnicode() ? '⏎' : '\\n'));
$this->outputWantsNewline = false;
}
}
@@ -643,18 +635,6 @@ class Shell extends Application
$this->output->writeln(self::RETVAL . str_replace(PHP_EOL, PHP_EOL . $indent, $ret));
}
/**
* Write a caught Exception to stdout.
*
* @see self::renderException
*
* @param \Exception $e
*/
public function writeException(\Exception $e)
{
$this->renderException($e, $this->output);
}
/**
* Renders a caught Exception.
*
@@ -666,7 +646,7 @@ class Shell extends Application
* @param \Exception $e An exception instance
* @param OutputInterface $output An OutputInterface instance
*/
public function renderException($e, $output)
public function writeException(\Exception $e)
{
$this->context->setLastException($e);
@@ -676,7 +656,7 @@ class Shell extends Application
}
$severity = ($e instanceof \ErrorException) ? $this->getSeverity($e) : 'error';
$output->writeln(sprintf('<%s>%s</%s>', $severity, OutputFormatter::escape($message), $severity));
$this->output->writeln(sprintf('<%s>%s</%s>', $severity, OutputFormatter::escape($message), $severity));
$this->resetCodeBuffer();
}
@@ -724,9 +704,14 @@ class Shell extends Application
* threshold. This should probably only be used in the inner execution loop
* of the shell, as most of the time a thrown exception is much more useful.
*
* If the error type matches the `errorLoggingLevel` config, it will be
* logged as well, regardless of the `error_reporting` level.
*
* @see \Psy\Exception\ErrorException::throwException
* @see \Psy\Shell::writeException
*
* @throws \Psy\Exception\ErrorException depending on the current error_reporting level.
*
* @param int $errno Error type
* @param string $errstr Message
* @param string $errfile Filename
@@ -736,7 +721,7 @@ class Shell extends Application
{
if ($errno & error_reporting()) {
ErrorException::throwException($errno, $errstr, $errfile, $errline);
} else {
} elseif ($errno & $this->config->errorLoggingLevel()) {
// log it and continue...
$this->writeException(new ErrorException($errstr, 0, $errno, $errfile, $errline));
}
@@ -745,7 +730,7 @@ class Shell extends Application
/**
* Format a value for display.
*
* @see PresenterManager::present
* @see Presenter::present
*
* @param mixed $val
*
@@ -753,7 +738,7 @@ class Shell extends Application
*/
protected function presentValue($val)
{
return $this->config->getPresenterManager()->present($val);
return $this->config->getPresenter()->present($val);
}
/**
@@ -828,7 +813,7 @@ class Shell extends Application
*/
protected function getHeader()
{
return sprintf("<aside>%s by Justin Hileman</aside>", $this->getVersion());
return sprintf('<aside>%s by Justin Hileman</aside>', $this->getVersion());
}
/**
@@ -838,7 +823,9 @@ class Shell extends Application
*/
public function getVersion()
{
return sprintf("Psy Shell %s (PHP %s — %s)", self::VERSION, phpversion(), php_sapi_name());
$separator = $this->config->useUnicode() ? '—' : '-';
return sprintf('Psy Shell %s (PHP %s %s %s)', self::VERSION, phpversion(), $separator, php_sapi_name());
}
/**
@@ -875,4 +862,26 @@ class Shell extends Application
return $this->getScopeVariableNames();
}
}
/**
* Initialize tab completion matchers.
*
* If tab completion is enabled this adds tab completion matchers to the
* auto completer and sets context if needed.
*/
protected function initializeTabCompletion()
{
// auto completer needs shell to be linked to configuration because of the context aware matchers
if ($this->config->getTabCompletion()) {
$this->completion = $this->config->getAutoCompleter();
$this->addTabCompletionMatchers($this->config->getTabCompletionMatchers());
foreach ($this->getTabCompletionMatchers() as $matcher) {
if ($matcher instanceof ContextAware) {
$matcher->setContext($this->context);
}
$this->completion->addMatcher($matcher);
}
$this->completion->activate();
}
}
}

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -22,7 +22,7 @@ namespace Psy\TabCompletion\Matcher;
class ClassAttributesMatcher extends AbstractMatcher
{
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function getMatches(array $tokens, array $info = array())
{
@@ -61,7 +61,7 @@ class ClassAttributesMatcher extends AbstractMatcher
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function hasMatched(array $tokens)
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -22,7 +22,7 @@ namespace Psy\TabCompletion\Matcher;
class ClassMethodsMatcher extends AbstractMatcher
{
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function getMatches(array $tokens, array $info = array())
{
@@ -53,7 +53,7 @@ class ClassMethodsMatcher extends AbstractMatcher
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function hasMatched(array $tokens)
{

View File

@@ -1,9 +1,9 @@
<?php
/*
* This file is part of Psy Shell
* This file is part of Psy Shell.
*
* (c) 2012-2014 Justin Hileman
* (c) 2012-2015 Justin Hileman
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -21,7 +21,7 @@ namespace Psy\TabCompletion\Matcher;
class ClassNamesMatcher extends AbstractMatcher
{
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function getMatches(array $tokens, array $info = array())
{
@@ -49,7 +49,7 @@ class ClassNamesMatcher extends AbstractMatcher
}
/**
* {@inheritDoc}
* {@inheritdoc}
*/
public function hasMatched(array $tokens)
{

Some files were not shown because too many files have changed in this diff Show More