Laravel version update
Laravel version update
This commit is contained in:
12
vendor/psy/psysh/.editorconfig
vendored
12
vendor/psy/psysh/.editorconfig
vendored
@@ -1,12 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
6
vendor/psy/psysh/.gitignore
vendored
6
vendor/psy/psysh/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
build-vendor/
|
||||
vendor/
|
||||
composer.lock
|
||||
manual/
|
||||
__pycache__
|
||||
.php_cs.cache
|
43
vendor/psy/psysh/.php_cs
vendored
43
vendor/psy/psysh/.php_cs
vendored
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\CS\Config\Config;
|
||||
use Symfony\CS\FixerInterface;
|
||||
use Symfony\CS\Fixer\Contrib\HeaderCommentFixer;
|
||||
|
||||
$header = <<<EOF
|
||||
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.
|
||||
EOF;
|
||||
|
||||
HeaderCommentFixer::setHeader($header);
|
||||
|
||||
$config = Config::create()
|
||||
// use symfony level and extra fixers:
|
||||
->level(FixerInterface::SYMFONY_LEVEL)
|
||||
->fixers(array(
|
||||
'align_double_arrow',
|
||||
'concat_with_spaces',
|
||||
'header_comment',
|
||||
'long_array_syntax',
|
||||
'ordered_use',
|
||||
'strict',
|
||||
'-concat_without_spaces',
|
||||
'-method_argument_space',
|
||||
'-pre_increment',
|
||||
'-unalign_double_arrow',
|
||||
'-unalign_equals',
|
||||
))
|
||||
->setUsingLinter(false);
|
||||
|
||||
$finder = $config->getFinder()
|
||||
->in(__DIR__)
|
||||
->name('.php_cs')
|
||||
->name('build-manual')
|
||||
->name('build-phar')
|
||||
->exclude('build-vendor');
|
||||
|
||||
return $config;
|
22
vendor/psy/psysh/.styleci.yml
vendored
22
vendor/psy/psysh/.styleci.yml
vendored
@@ -1,22 +0,0 @@
|
||||
preset: symfony
|
||||
|
||||
enabled:
|
||||
- align_double_arrow
|
||||
- concat_with_spaces
|
||||
- long_array_syntax
|
||||
- ordered_use
|
||||
- strict
|
||||
|
||||
disabled:
|
||||
- concat_without_spaces
|
||||
- method_argument_space
|
||||
- pre_increment
|
||||
- unalign_double_arrow
|
||||
- unalign_equals
|
||||
|
||||
finder:
|
||||
name:
|
||||
- "*.php"
|
||||
- ".php_cs"
|
||||
- "build-manual"
|
||||
- "build-phar"
|
24
vendor/psy/psysh/.travis.yml
vendored
24
vendor/psy/psysh/.travis.yml
vendored
@@ -1,24 +0,0 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-source
|
||||
- '[ -z "$MIN_VERSIONS" ] || composer require --no-interaction --prefer-source $MIN_VERSIONS'
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 5.3
|
||||
env: MIN_VERSIONS="symfony/console:2.3.10 symfony/var-dumper:2.7.0 nikic/php-parser:1.2.1 jakub-onderka/php-console-highlighter:0.3.0"
|
||||
allow_failures:
|
||||
- env: MIN_VERSIONS="symfony/console:2.3.10 symfony/var-dumper:2.7.0 nikic/php-parser:1.2.1 jakub-onderka/php-console-highlighter:0.3.0"
|
18
vendor/psy/psysh/CONTRIBUTING.md
vendored
18
vendor/psy/psysh/CONTRIBUTING.md
vendored
@@ -1,18 +0,0 @@
|
||||
## Code style
|
||||
|
||||
Please make your code look like the other code in the project. PsySH follows [PSR-1](http://php-fig.org/psr/psr-1/) and [PSR-2](http://php-fig.org/psr/psr-2/). The easiest way to do make sure you're following the coding standard is to run `vendor/bin/php-cs-fixer fix` before committing.
|
||||
|
||||
## Branching model
|
||||
|
||||
Please branch off and send pull requests to the `develop` branch.
|
||||
|
||||
## Building the manual
|
||||
|
||||
```sh
|
||||
svn co https://svn.php.net/repository/phpdoc/en/trunk/reference/ php_manual
|
||||
bin/build_manual phpdoc_manual ~/.local/share/psysh/php_manual.sqlite
|
||||
```
|
||||
|
||||
To build the manual for another language, switch out `en` above for `de`, `es`, or any of the other languages listed in the README.
|
||||
|
||||
[Partial or outdated documentation is available for other languages](http://www.php.net/manual/help-translate.php) but these translations are outdated, so their content may be completely wrong or insecure!
|
21
vendor/psy/psysh/LICENSE
vendored
21
vendor/psy/psysh/LICENSE
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2015 Justin Hileman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
179
vendor/psy/psysh/README.md
vendored
179
vendor/psy/psysh/README.md
vendored
@@ -1,179 +0,0 @@
|
||||
# PsySH
|
||||
|
||||
[](https://packagist.org/packages/psy/psysh)
|
||||
[](https://packagist.org/packages/psy/psysh)
|
||||
[](http://psysh.org)
|
||||
|
||||
[](http://travis-ci.org/bobthecow/psysh)
|
||||
[](https://styleci.io/repos/4549925)
|
||||
|
||||
|
||||
## About
|
||||
|
||||
PsySH is a runtime developer console, interactive debugger and [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) for PHP. Learn more at [psysh.org](http://psysh.org/). Check out the [Interactive Debugging in PHP talk from OSCON](https://presentate.com/bobthecow/talks/php-for-pirates) on Presentate.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Download the `psysh` phar to install:
|
||||
|
||||
```
|
||||
wget psysh.org/psysh
|
||||
chmod +x psysh
|
||||
./psysh
|
||||
```
|
||||
|
||||
It's even awesomer if you put it somewhere in your system path (like `/usr/local/bin` or `~/bin`)!
|
||||
|
||||
PsySH [is available via Composer](https://packagist.org/packages/psy/psysh), so you can use it in your project as well:
|
||||
|
||||
```
|
||||
composer require psy/psysh:@stable
|
||||
./vendor/bin/psysh
|
||||
```
|
||||
|
||||
Or you can use by checking out the the repository directly:
|
||||
|
||||
```
|
||||
git clone https://github.com/bobthecow/psysh.git
|
||||
cd psysh
|
||||
./bin/psysh
|
||||
```
|
||||
|
||||
|
||||
## PsySH configuration
|
||||
|
||||
While PsySH strives to detect the right settings automatically, you might want to configure it yourself. Just add a file to `~/.config/psysh/config.php` (or `C:\Users\{USER}\AppData\Roaming\PsySH\config.php` on Windows):
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return array(
|
||||
// In PHP 5.4+, PsySH will default to your `cli.pager` ini setting. If this
|
||||
// is not set, it falls back to `less`. It is recommended that you set up
|
||||
// `cli.pager` in your `php.ini` with your preferred output pager.
|
||||
//
|
||||
// If you are running PHP 5.3, or if you want to use a different pager only
|
||||
// for Psy shell sessions, you can override it here.
|
||||
'pager' => 'more',
|
||||
|
||||
// Sets the maximum number of entries the history can contain.
|
||||
// If set to zero, the history size is unlimited.
|
||||
'historySize' => 0,
|
||||
|
||||
// If set to true, the history will not keep duplicate entries.
|
||||
// Newest entries override oldest.
|
||||
// This is the equivalent of the HISTCONTROL=erasedups setting in bash.
|
||||
'eraseDuplicates' => false,
|
||||
|
||||
// By default, PsySH will use a 'forking' execution loop if pcntl is
|
||||
// installed. This is by far the best way to use it, but you can override
|
||||
// the default by explicitly enabling or disabling this functionality here.
|
||||
'usePcntl' => false,
|
||||
|
||||
// PsySH uses readline if you have it installed, because interactive input
|
||||
// is pretty awful without it. But you can explicitly disable it if you hate
|
||||
// yourself or something.
|
||||
'useReadline' => false,
|
||||
|
||||
// PsySH automatically inserts semicolons at the end of input if a statement
|
||||
// is missing one. To disable this, set `requireSemicolons` to true.
|
||||
'requireSemicolons' => true,
|
||||
|
||||
// PsySH uses a couple of UTF-8 characters in its own output. These can be
|
||||
// disabled, mostly to work around code page issues. Because Windows.
|
||||
//
|
||||
// Note that this does not disable Unicode output in general, it just makes
|
||||
// it so PsySH won't output any itself.
|
||||
'useUnicode' => false,
|
||||
|
||||
// While PsySH respects the current `error_reporting` level, and doesn't throw
|
||||
// exceptions for all errors, it does log all errors regardless of level. 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.
|
||||
'errorLoggingLevel' => E_ALL & ~E_NOTICE,
|
||||
|
||||
// "Default includes" will be included once at the beginning of every PsySH
|
||||
// session. This is a good place to add autoloaders for your favorite
|
||||
// libraries.
|
||||
'defaultIncludes' => array(
|
||||
__DIR__ . '/include/bootstrap.php',
|
||||
),
|
||||
|
||||
// While PsySH ships with a bunch of great commands, it's possible to add
|
||||
// your own for even more awesome. Any Psy command added here will be
|
||||
// available in your Psy shell sessions.
|
||||
'commands' => array(
|
||||
// The `parse` command is a command used in the development of PsySH.
|
||||
// Given a string of PHP code, it pretty-prints the
|
||||
// [PHP Parser](https://github.com/nikic/PHP-Parser) parse tree. It
|
||||
// prolly won't be super useful for most of you, but it's there if you
|
||||
// want to play :)
|
||||
new \Psy\Command\ParseCommand,
|
||||
),
|
||||
|
||||
// PsySH uses symfony/var-dumper's casters for presenting scalars, resources,
|
||||
// arrays and objects. You can enable additional casters, or write your own!
|
||||
// See http://symfony.com/doc/current/components/var_dumper/advanced.html#casters
|
||||
'casters' => array(
|
||||
'MyFooClass' => 'MyFooClassCaster::castMyFooObject',
|
||||
),
|
||||
|
||||
// You can disable tab completion if you want to. Not sure why you'd want to.
|
||||
'tabCompletion' => false,
|
||||
|
||||
// You can write your own tab completion matchers, too! Here are some that enable
|
||||
// tab completion for MongoDB database and collection names:
|
||||
'tabCompletionMatchers' => array(
|
||||
new \Psy\TabCompletion\Matcher\MongoClientMatcher,
|
||||
new \Psy\TabCompletion\Matcher\MongoDatabaseMatcher,
|
||||
),
|
||||
|
||||
// If multiple versions of the same configuration or data file exist, 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.
|
||||
'warnOnMultipleConfigs' => true,
|
||||
|
||||
// By default, output contains colors if support for them is detected. To override:
|
||||
'colorMode' => \Psy\Configuration::COLOR_MODE_FORCED, // force colors in output
|
||||
'colorMode' => \Psy\Configuration::COLOR_MODE_DISABLED, // disable colors in output
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
## Downloading the manual
|
||||
|
||||
The PsySH `doc` command is great for documenting source code, but you'll need a little something extra for PHP core documentation. Download one of the following PHP Manual files and drop it in `~/.local/share/psysh/`, `/usr/local/share/psysh/` or `C:\Users\{USER}\AppData\Roaming\PsySH\` on Windows:
|
||||
|
||||
* **[English](http://psysh.org/manual/en/php_manual.sqlite)**
|
||||
* [Brazilian Portuguese](http://psysh.org/manual/pt_BR/php_manual.sqlite)
|
||||
* [Chinese (Simplified)](http://psysh.org/manual/zh/php_manual.sqlite)
|
||||
* [French](http://psysh.org/manual/fr/php_manual.sqlite)
|
||||
* [German](http://psysh.org/manual/de/php_manual.sqlite)
|
||||
* [Italian](http://psysh.org/manual/it/php_manual.sqlite)
|
||||
* [Japanese](http://psysh.org/manual/ja/php_manual.sqlite)
|
||||
* [Polish](http://psysh.org/manual/pl/php_manual.sqlite)
|
||||
* [Romanian](http://psysh.org/manual/ro/php_manual.sqlite)
|
||||
* [Russian](http://psysh.org/manual/ru/php_manual.sqlite)
|
||||
* [Persian](http://psysh.org/manual/fa/php_manual.sqlite)
|
||||
* [Spanish](http://psysh.org/manual/es/php_manual.sqlite)
|
||||
* [Turkish](http://psysh.org/manual/tr/php_manual.sqlite)
|
||||
|
||||
|
||||
|
||||
## As Seen On…
|
||||
|
||||
* Cake: [`cake console`](http://book.cakephp.org/3.0/en/console-and-shells/repl.html)
|
||||
* Drupal: [`drush php`](http://drushcommands.com/drush-8x/core/core-cli/), [drush-psysh](https://github.com/grota/drush-psysh)
|
||||
* eZ Publish: [`ezsh`](https://github.com/lolautruche/ezsh)
|
||||
* Laravel: [`artisan tinker`](https://github.com/laravel/framework/blob/5.0/src/Illuminate/Foundation/Console/TinkerCommand.php)
|
||||
* Lumen: [`artisan tinker`](https://github.com/vluzrmos/lumen-tinker)
|
||||
* Magento: [`magerun console`](https://github.com/netz98/n98-magerun/blob/develop/src/N98/Magento/Command/Developer/ConsoleCommand.php)
|
||||
* Pantheon CLI: [`terminus cli console`](https://github.com/pantheon-systems/terminus)
|
||||
* Symfony: [sf1-psysh-bootstrap](https://github.com/varas/sf1-psysh-bootstrap)
|
||||
* Symfony2: [`psymf`](https://github.com/navitronic/psymf), [sf2-psysh-bootstrap](https://github.com/varas/sf2-psysh-bootstrap), [symfony-repl](https://github.com/luxifer/symfony-repl), [PsyshBundle](https://github.com/theofidry/PsyshBundle)
|
||||
* WordPress: [`wp-cli shell`](https://github.com/wp-cli/wp-cli/blob/master/php/commands/shell.php)
|
||||
* Zend Framework 2: [PsyshModule](https://zfmodules.com/gianarb/zf2-psysh-module)
|
6
vendor/psy/psysh/bin/build
vendored
6
vendor/psy/psysh/bin/build
vendored
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd "${BASH_SOURCE%/*}/.."
|
||||
|
||||
./bin/build-vendor || exit 1
|
||||
./bin/build-phar
|
285
vendor/psy/psysh/bin/build-manual
vendored
285
vendor/psy/psysh/bin/build-manual
vendored
@@ -1,285 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?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.
|
||||
*/
|
||||
|
||||
define('WRAP_WIDTH', 100);
|
||||
|
||||
$count = 0;
|
||||
|
||||
if (count($argv) !== 3 || !is_dir($argv[1])) {
|
||||
echo "usage: build_manual path/to/manual output_filename.db\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
function htmlwrap($text, $width = null)
|
||||
{
|
||||
if ($width === null) {
|
||||
$width = WRAP_WIDTH;
|
||||
}
|
||||
|
||||
$len = strlen($text);
|
||||
|
||||
$return = array();
|
||||
$lastSpace = null;
|
||||
$inTag = false;
|
||||
$i = $tagWidth = 0;
|
||||
do {
|
||||
switch (substr($text, $i, 1)) {
|
||||
case "\n":
|
||||
$return[] = trim(substr($text, 0, $i));
|
||||
$text = substr($text, $i);
|
||||
$len = strlen($text);
|
||||
|
||||
$i = $lastSpace = 0;
|
||||
continue;
|
||||
|
||||
case ' ':
|
||||
if (!$inTag) {
|
||||
$lastSpace = $i;
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
$inTag = true;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
$inTag = false;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
if ($inTag) {
|
||||
$tagWidth++;
|
||||
}
|
||||
|
||||
$i++;
|
||||
|
||||
if (!$inTag && ($i - $tagWidth > $width)) {
|
||||
$lastSpace = $lastSpace ?: $width;
|
||||
|
||||
$return[] = trim(substr($text, 0, $lastSpace));
|
||||
$text = substr($text, $lastSpace);
|
||||
$len = strlen($text);
|
||||
|
||||
$i = $tagWidth = 0;
|
||||
}
|
||||
} while ($i < $len);
|
||||
|
||||
$return[] = trim($text);
|
||||
|
||||
return implode("\n", $return);
|
||||
}
|
||||
|
||||
function extract_paragraphs($element)
|
||||
{
|
||||
$paragraphs = array();
|
||||
foreach ($element->getElementsByTagName('para') as $p) {
|
||||
$text = '';
|
||||
foreach ($p->childNodes as $child) {
|
||||
// @todo: figure out if there's something we can do with tables.
|
||||
if ($child instanceof DOMElement && $child->tagName === 'table') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip references, because ugh.
|
||||
if (preg_match('{^\s*&[a-z][a-z\.]+;\s*$}', $child->textContent)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$text .= $child->ownerDocument->saveXML($child);
|
||||
}
|
||||
|
||||
if ($text = trim(preg_replace('{\n[ \t]+}', ' ', $text))) {
|
||||
$paragraphs[] = $text;
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n\n", $paragraphs);
|
||||
}
|
||||
|
||||
function format_doc($doc)
|
||||
{
|
||||
$chunks = array();
|
||||
|
||||
if (!empty($doc['description'])) {
|
||||
$chunks[] = '<comment>Description:</comment>';
|
||||
$chunks[] = indent_text(htmlwrap(thunk_tags($doc['description']), WRAP_WIDTH - 2));
|
||||
$chunks[] = '';
|
||||
}
|
||||
|
||||
if (!empty($doc['params'])) {
|
||||
$chunks[] = '<comment>Param:</comment>';
|
||||
|
||||
$typeMax = max(array_map(function ($param) {
|
||||
return strlen($param['type']);
|
||||
}, $doc['params']));
|
||||
|
||||
$max = max(array_map(function ($param) {
|
||||
return strlen($param['name']);
|
||||
}, $doc['params']));
|
||||
|
||||
$template = ' <info>%-' . $typeMax . 's</info> <strong>%-' . $max . 's</strong> %s';
|
||||
$indent = str_repeat(' ', $typeMax + $max + 6);
|
||||
$wrapWidth = WRAP_WIDTH - strlen($indent);
|
||||
|
||||
foreach ($doc['params'] as $param) {
|
||||
$desc = indent_text(htmlwrap(thunk_tags($param['description']), $wrapWidth), $indent, false);
|
||||
$chunks[] = sprintf($template, $param['type'], $param['name'], $desc);
|
||||
}
|
||||
$chunks[] = '';
|
||||
}
|
||||
|
||||
if (isset($doc['return']) || isset($doc['return_type'])) {
|
||||
$chunks[] = '<comment>Return:</comment>';
|
||||
|
||||
$type = isset($doc['return_type']) ? $doc['return_type'] : 'unknown';
|
||||
$desc = isset($doc['return']) ? $doc['return'] : '';
|
||||
|
||||
$indent = str_repeat(' ', strlen($type) + 4);
|
||||
$wrapWidth = WRAP_WIDTH - strlen($indent);
|
||||
|
||||
if (!empty($desc)) {
|
||||
$desc = indent_text(htmlwrap(thunk_tags($doc['return']), $wrapWidth), $indent, false);
|
||||
}
|
||||
|
||||
$chunks[] = sprintf(' <info>%s</info> %s', $type, $desc);
|
||||
$chunks[] = '';
|
||||
}
|
||||
|
||||
array_pop($chunks); // get rid of the trailing newline
|
||||
|
||||
return implode("\n", $chunks);
|
||||
}
|
||||
|
||||
function thunk_tags($text)
|
||||
{
|
||||
$tagMap = array(
|
||||
'parameter>' => 'strong>',
|
||||
'function>' => 'strong>',
|
||||
'literal>' => 'return>',
|
||||
'type>' => 'info>',
|
||||
'constant>' => 'info>',
|
||||
);
|
||||
|
||||
$andBack = array(
|
||||
'&' => '&',
|
||||
'&true;' => '<return>true</return>',
|
||||
'&false;' => '<return>false</return>',
|
||||
'&null;' => '<return>null</return>',
|
||||
);
|
||||
|
||||
return strtr(strip_tags(strtr($text, $tagMap), '<strong><return><info>'), $andBack);
|
||||
}
|
||||
|
||||
function indent_text($text, $indent = ' ', $leading = true)
|
||||
{
|
||||
return ($leading ? $indent : '') . str_replace("\n", "\n" . $indent, $text);
|
||||
}
|
||||
|
||||
function find_type($xml, $paramName)
|
||||
{
|
||||
foreach ($xml->getElementsByTagName('methodparam') as $param) {
|
||||
if ($type = $param->getElementsByTagName('type')->item(0)) {
|
||||
if ($parameter = $param->getElementsByTagName('parameter')->item(0)) {
|
||||
if ($paramName === $parameter->textContent) {
|
||||
return $type->textContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$docs = array();
|
||||
foreach (glob($argv[1] . '/*/*/*.xml') as $function) {
|
||||
$funcname = basename($function);
|
||||
if ($funcname === 'main.xml' || strpos($funcname, 'entities.') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xmlstr = str_replace('&', '&', file_get_contents($function));
|
||||
|
||||
$xml = new DOMDocument();
|
||||
$xml->preserveWhiteSpace = false;
|
||||
|
||||
if (!@$xml->loadXml($xmlstr)) {
|
||||
echo "XML Parse Error: $function\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$doc = array();
|
||||
$refsect1s = $xml->getElementsByTagName('refsect1');
|
||||
foreach ($refsect1s as $refsect1) {
|
||||
$role = $refsect1->getAttribute('role');
|
||||
switch ($role) {
|
||||
case 'description':
|
||||
$doc['description'] = extract_paragraphs($refsect1);
|
||||
|
||||
if ($synopsis = $refsect1->getElementsByTagName('methodsynopsis')->item(0)) {
|
||||
foreach ($synopsis->childNodes as $node) {
|
||||
if ($node instanceof DOMElement && $node->tagName === 'type') {
|
||||
$doc['return_type'] = $node->textContent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'returnvalues':
|
||||
// do nothing.
|
||||
$doc['return'] = extract_paragraphs($refsect1);
|
||||
break;
|
||||
|
||||
case 'parameters':
|
||||
$params = array();
|
||||
$vars = $refsect1->getElementsByTagName('varlistentry');
|
||||
foreach ($vars as $var) {
|
||||
if ($name = $var->getElementsByTagName('parameter')->item(0)) {
|
||||
$params[] = array(
|
||||
'name' => '$' . $name->textContent,
|
||||
'type' => find_type($xml, $name->textContent),
|
||||
'description' => extract_paragraphs($var),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$doc['params'] = $params;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// and the purpose
|
||||
if ($purpose = $xml->getElementsByTagName('refpurpose')->item(0)) {
|
||||
$desc = htmlwrap($purpose->textContent);
|
||||
if (isset($doc['description'])) {
|
||||
$desc .= "\n\n" . $doc['description'];
|
||||
}
|
||||
|
||||
$doc['description'] = trim($desc);
|
||||
}
|
||||
|
||||
$formatted = format_doc($doc);
|
||||
foreach ($xml->getElementsByTagName('refname') as $ref) {
|
||||
$docs[$ref->textContent] = $formatted;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_file($argv[2])) {
|
||||
unlink($argv[2]);
|
||||
}
|
||||
|
||||
$db = new PDO('sqlite:' . $argv[2]);
|
||||
|
||||
$db->query('CREATE TABLE php_manual (id char(256) PRIMARY KEY, doc TEXT)');
|
||||
$cmd = $db->prepare('INSERT INTO php_manual (id, doc) VALUES (?, ?)');
|
||||
foreach ($docs as $id => $doc) {
|
||||
$cmd->execute(array($id, $doc));
|
||||
}
|
33
vendor/psy/psysh/bin/build-phar
vendored
33
vendor/psy/psysh/bin/build-phar
vendored
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?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.
|
||||
*/
|
||||
|
||||
if (!is_file(dirname(__DIR__) . '/vendor/autoload.php')) {
|
||||
throw new RuntimeException('Missing PsySH dev dependencies in ' . dirname(__DIR__) . '/vendor/' . ', install with `composer.phar install --dev`.');
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if (!class_exists('Symfony\Component\Finder\Finder')) {
|
||||
throw new RuntimeException('Missing PsySH dev dependencies, install with `composer.phar install --dev`.');
|
||||
}
|
||||
|
||||
if (!is_file(dirname(__DIR__) . '/build-vendor/autoload.php')) {
|
||||
throw new RuntimeException('Missing phar vendor dependencies, install with bin/build-vendor');
|
||||
}
|
||||
|
||||
use Psy\Compiler;
|
||||
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
$compiler = new Compiler();
|
||||
$compiler->compile();
|
7
vendor/psy/psysh/bin/build-vendor
vendored
7
vendor/psy/psysh/bin/build-vendor
vendored
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd "${BASH_SOURCE%/*}/.."
|
||||
|
||||
rm -rf build-vendor
|
||||
|
||||
COMPOSER_VENDOR_DIR=build-vendor composer install --ignore-platform-reqs --no-dev --no-progress --classmap-authoritative
|
135
vendor/psy/psysh/bin/psysh
vendored
135
vendor/psy/psysh/bin/psysh
vendored
@@ -1,135 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?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.
|
||||
*/
|
||||
|
||||
// Try to find an autoloader for a local psysh version.
|
||||
// We'll wrap this whole mess in a Closure so it doesn't leak any globals.
|
||||
call_user_func(function () {
|
||||
$cwd = null;
|
||||
|
||||
// Find the cwd arg (if present)
|
||||
$argv = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
|
||||
foreach ($argv as $i => $arg) {
|
||||
if ($arg === '--cwd') {
|
||||
if ($i >= count($argv) - 1) {
|
||||
echo 'Missing --cwd argument.' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$cwd = $argv[$i + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
if (preg_match('/^--cwd=/', $arg)) {
|
||||
$cwd = substr($arg, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Or fall back to the actual cwd
|
||||
if (!isset($cwd)) {
|
||||
$cwd = getcwd();
|
||||
}
|
||||
|
||||
$cwd = str_replace('\\', '/', $cwd);
|
||||
|
||||
$chunks = explode('/', $cwd);
|
||||
while (!empty($chunks)) {
|
||||
$path = implode('/', $chunks);
|
||||
|
||||
// Find composer.json
|
||||
if (is_file($path . '/composer.json')) {
|
||||
if ($cfg = json_decode(file_get_contents($path . '/composer.json'), true)) {
|
||||
if (isset($cfg['name']) && $cfg['name'] === 'psy/psysh') {
|
||||
// We're inside the psysh project. Let's use the local
|
||||
// Composer autoload.
|
||||
if (is_file($path . '/vendor/autoload.php')) {
|
||||
require $path . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Or a composer.lock
|
||||
if (is_file($path . '/composer.lock')) {
|
||||
if ($cfg = json_decode(file_get_contents($path . '/composer.lock'), true)) {
|
||||
foreach (array_merge($cfg['packages'], $cfg['packages-dev']) as $pkg) {
|
||||
if (isset($pkg['name']) && $pkg['name'] === 'psy/psysh') {
|
||||
// We're inside a project which requires psysh. We'll
|
||||
// use the local Composer autoload.
|
||||
if (is_file($path . '/vendor/autoload.php')) {
|
||||
require $path . '/vendor/autoload.php';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array_pop($chunks);
|
||||
}
|
||||
});
|
||||
|
||||
// We didn't find an autoloader for a local version, so use the autoloader that
|
||||
// came with this script.
|
||||
if (!class_exists('Psy\Shell')) {
|
||||
/* <<< */
|
||||
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
} elseif (is_file(__DIR__ . '/../../../autoload.php')) {
|
||||
require __DIR__ . '/../../../autoload.php';
|
||||
} else {
|
||||
echo 'PsySH dependencies not found, be sure to run `composer install`.' . PHP_EOL;
|
||||
echo 'See https://getcomposer.org to get Composer.' . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
/* >>> */
|
||||
}
|
||||
|
||||
// If the psysh binary was included directly, assume they just wanted an
|
||||
// autoloader and bail early.
|
||||
if (version_compare(PHP_VERSION, '5.3.6', '<')) {
|
||||
$trace = debug_backtrace();
|
||||
} elseif (version_compare(PHP_VERSION, '5.4.0', '<')) {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
} else {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
||||
}
|
||||
|
||||
if (Psy\Shell::isIncluded($trace)) {
|
||||
unset($trace);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up after ourselves.
|
||||
unset($trace);
|
||||
|
||||
// If the local version is too old, we can't do this
|
||||
if (!function_exists('Psy\bin')) {
|
||||
$argv = $_SERVER['argv'];
|
||||
$first = array_shift($argv);
|
||||
if (preg_match('/php(\.exe)?$/', $first)) {
|
||||
array_shift($argv);
|
||||
}
|
||||
array_unshift($argv, 'vendor/bin/psysh');
|
||||
|
||||
echo 'A local PsySH dependency was found, but it cannot be loaded. Please update to' . PHP_EOL;
|
||||
echo 'the latest version, or run the local copy directly, e.g.:' . PHP_EOL;
|
||||
echo PHP_EOL;
|
||||
echo ' ' . implode(' ', $argv) . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// And go!
|
||||
call_user_func(Psy\bin());
|
52
vendor/psy/psysh/composer.json
vendored
52
vendor/psy/psysh/composer.json
vendored
@@ -1,52 +0,0 @@
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"description": "An interactive shell for modern PHP.",
|
||||
"type": "library",
|
||||
"keywords": ["console", "interactive", "shell", "repl"],
|
||||
"homepage": "http://psysh.org",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Justin Hileman",
|
||||
"email": "justin@justinhileman.info",
|
||||
"homepage": "http://justinhileman.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/console": "~2.3.10|^2.4.2|~3.0",
|
||||
"symfony/var-dumper": "~2.7|~3.0",
|
||||
"nikic/php-parser": "^1.2.1|~2.0",
|
||||
"dnoegel/php-xdg-base-dir": "0.1",
|
||||
"jakub-onderka/php-console-highlighter": "0.3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7|~4.0|~5.0",
|
||||
"symfony/finder": "~2.1|~3.0",
|
||||
"squizlabs/php_codesniffer": "~2.0",
|
||||
"fabpot/php-cs-fixer": "~1.5"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
|
||||
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
|
||||
"ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.",
|
||||
"ext-pdo-sqlite": "The doc command requires SQLite to work."
|
||||
},
|
||||
"autoload": {
|
||||
"files": ["src/Psy/functions.php"],
|
||||
"psr-4": {
|
||||
"Psy\\": "src/Psy/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Psy\\Test\\": "test/Psy/Test/"
|
||||
}
|
||||
},
|
||||
"bin": ["bin/psysh"],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "0.8.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
11
vendor/psy/psysh/phpcs.xml
vendored
11
vendor/psy/psysh/phpcs.xml
vendored
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="PsySH Coding Standard">
|
||||
<description>The coding standard for PsySH</description>
|
||||
|
||||
<exclude-pattern>*/bin/*</exclude-pattern>
|
||||
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||
|
||||
<rule ref="PSR2">
|
||||
<exclude name="Generic.Functions.FunctionCallArgumentSpacing.TooMuchSpaceAfterComma"/>
|
||||
</rule>
|
||||
</ruleset>
|
12
vendor/psy/psysh/phpunit.xml.dist
vendored
12
vendor/psy/psysh/phpunit.xml.dist
vendored
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false" colors="true" bootstrap="vendor/autoload.php">
|
||||
<testsuite name="PsySH">
|
||||
<directory suffix="Test.php">./test</directory>
|
||||
</testsuite>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./src/Psy</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
45
vendor/psy/psysh/src/Psy/Autoloader.php
vendored
45
vendor/psy/psysh/src/Psy/Autoloader.php
vendored
@@ -1,45 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Psy class autoloader.
|
||||
*/
|
||||
class Autoloader
|
||||
{
|
||||
/**
|
||||
* Register autoload() as an SPL autoloader.
|
||||
*
|
||||
* @see self::autoload
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
spl_autoload_register(array(__CLASS__, 'autoload'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoload Psy classes.
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
public static function autoload($class)
|
||||
{
|
||||
if (0 !== strpos($class, 'Psy')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file = dirname(__DIR__) . '/' . strtr($class, '\\', '/') . '.php';
|
||||
if (is_file($file)) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
}
|
214
vendor/psy/psysh/src/Psy/CodeCleaner.php
vendored
214
vendor/psy/psysh/src/Psy/CodeCleaner.php
vendored
@@ -1,214 +0,0 @@
|
||||
<?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\NodeTraverser;
|
||||
use PhpParser\Parser;
|
||||
use PhpParser\PrettyPrinter\Standard as Printer;
|
||||
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;
|
||||
use Psy\CodeCleaner\LeavePsyshAlonePass;
|
||||
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;
|
||||
use Psy\CodeCleaner\ValidFunctionNamePass;
|
||||
use Psy\Exception\ParseErrorException;
|
||||
|
||||
/**
|
||||
* A service to clean up user input, detect parse errors before they happen,
|
||||
* and generally work around issues with the PHP code evaluation experience.
|
||||
*/
|
||||
class CodeCleaner
|
||||
{
|
||||
private $parser;
|
||||
private $printer;
|
||||
private $traverser;
|
||||
private $namespace;
|
||||
|
||||
/**
|
||||
* CodeCleaner constructor.
|
||||
*
|
||||
* @param Parser $parser A PhpParser Parser instance. One will be created if not explicitly supplied.
|
||||
* @param Printer $printer A PhpParser Printer instance. One will be created if not explicitly supplied.
|
||||
* @param NodeTraverser $traverser A PhpParser NodeTraverser instance. One will be created if not explicitly supplied.
|
||||
*/
|
||||
public function __construct(Parser $parser = null, Printer $printer = null, NodeTraverser $traverser = null)
|
||||
{
|
||||
if ($parser === null) {
|
||||
$parserFactory = new ParserFactory();
|
||||
$parser = $parserFactory->createParser();
|
||||
}
|
||||
|
||||
$this->parser = $parser;
|
||||
$this->printer = $printer ?: new Printer();
|
||||
$this->traverser = $traverser ?: new NodeTraverser();
|
||||
|
||||
foreach ($this->getDefaultPasses() as $pass) {
|
||||
$this->traverser->addVisitor($pass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default CodeCleaner passes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getDefaultPasses()
|
||||
{
|
||||
return array(
|
||||
new AbstractClassPass(),
|
||||
new AssignThisVariablePass(),
|
||||
new FunctionReturnInWriteContextPass(),
|
||||
new CallTimePassByReferencePass(),
|
||||
new CalledClassPass(),
|
||||
new InstanceOfPass(),
|
||||
new LeavePsyshAlonePass(),
|
||||
new LegacyEmptyPass(),
|
||||
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(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the given array of code.
|
||||
*
|
||||
* @throws ParseErrorException if the code is invalid PHP, and cannot be coerced into valid PHP.
|
||||
*
|
||||
* @param array $codeLines
|
||||
* @param bool $requireSemicolons
|
||||
*
|
||||
* @return string|false Cleaned PHP code, False if the input is incomplete.
|
||||
*/
|
||||
public function clean(array $codeLines, $requireSemicolons = false)
|
||||
{
|
||||
$stmts = $this->parse('<?php ' . implode(PHP_EOL, $codeLines) . PHP_EOL, $requireSemicolons);
|
||||
if ($stmts === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Catch fatal errors before they happen
|
||||
$stmts = $this->traverser->traverse($stmts);
|
||||
|
||||
return $this->printer->prettyPrint($stmts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current local namespace.
|
||||
*
|
||||
* @param null|array $namespace (default: null)
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
public function setNamespace(array $namespace = null)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current local namespace.
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lex and parse a block of code.
|
||||
*
|
||||
* @see Parser::parse
|
||||
*
|
||||
* @param string $code
|
||||
* @param bool $requireSemicolons
|
||||
*
|
||||
* @return array A set of statements
|
||||
*/
|
||||
protected function parse($code, $requireSemicolons = false)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if ($requireSemicolons) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Unexpected EOF, try again with an implicit semicolon
|
||||
return $this->parser->parse($code . ';');
|
||||
} catch (\PhpParser\Error $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function parseErrorIsEOF(\PhpParser\Error $e)
|
||||
{
|
||||
$msg = $e->getRawMessage();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
<?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\Stmt\Class_ as ClassStmt;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* The abstract class pass handles abstract classes and methods, complaining if there are too few or too many of either.
|
||||
*/
|
||||
class AbstractClassPass extends CodeCleanerPass
|
||||
{
|
||||
private $class;
|
||||
private $abstractMethods;
|
||||
|
||||
/**
|
||||
* @throws RuntimeException if the node is an abstract function with a body.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ClassStmt) {
|
||||
$this->class = $node;
|
||||
$this->abstractMethods = array();
|
||||
} elseif ($node instanceof ClassMethod) {
|
||||
if ($node->isAbstract()) {
|
||||
$name = sprintf('%s::%s', $this->class->name, $node->name);
|
||||
$this->abstractMethods[] = $name;
|
||||
|
||||
if ($node->stmts !== null) {
|
||||
throw new FatalErrorException(sprintf('Abstract function %s cannot contain body', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RuntimeException if the node is a non-abstract class with abstract methods.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ClassStmt) {
|
||||
$count = count($this->abstractMethods);
|
||||
if ($count > 0 && !$node->isAbstract()) {
|
||||
throw new FatalErrorException(sprintf(
|
||||
'Class %s contains %d abstract method%s must therefore be declared abstract or implement the remaining methods (%s)',
|
||||
$node->name,
|
||||
$count,
|
||||
($count === 0) ? '' : 's',
|
||||
implode(', ', $this->abstractMethods)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
<?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 as Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the user input does not assign the `$this` variable.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class AssignThisVariablePass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Validate that the user input does not assign the `$this` variable.
|
||||
*
|
||||
* @throws RuntimeException if the user assign the `$this` variable.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Assign && $node->var instanceof Variable && $node->var->name === 'this') {
|
||||
throw new FatalErrorException('Cannot re-assign $this');
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
<?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\Expr\FuncCall as FunctionCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the user did not use the call-time pass-by-reference that causes a fatal error.
|
||||
*
|
||||
* As of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class CallTimePassByReferencePass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Validate of use call-time pass-by-reference.
|
||||
*
|
||||
* @throws RuntimeException if the user used call-time pass-by-reference in PHP >= 5.4.0
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4', '<')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof FunctionCall && !$node instanceof MethodCall && !$node instanceof StaticCall) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($node->args as $arg) {
|
||||
if ($arg->byRef) {
|
||||
throw new FatalErrorException('Call-time pass-by-reference has been removed');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,83 +0,0 @@
|
||||
<?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\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Class_ as ClassStmt;
|
||||
use PhpParser\Node\Stmt\Trait_ as TraitStmt;
|
||||
use Psy\Exception\ErrorException;
|
||||
|
||||
/**
|
||||
* The called class pass throws warnings for get_class() and get_called_class()
|
||||
* outside a class context.
|
||||
*/
|
||||
class CalledClassPass extends CodeCleanerPass
|
||||
{
|
||||
private $inClass;
|
||||
|
||||
/**
|
||||
* @param array $nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->inClass = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ErrorException if get_class or get_called_class is called without an object from outside a class
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ClassStmt || $node instanceof TraitStmt) {
|
||||
$this->inClass = true;
|
||||
} elseif ($node instanceof FuncCall && !$this->inClass) {
|
||||
// We'll give any args at all (besides null) a pass.
|
||||
// Technically we should be checking whether the args are objects, but this will do for now.
|
||||
//
|
||||
// TODO: switch this to actually validate args when we get context-aware code cleaner passes.
|
||||
if (!empty($node->args) && !$this->isNull($node->args[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We'll ignore name expressions as well (things like `$foo()`)
|
||||
if (!($node->name instanceof Name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$name = strtolower($node->name);
|
||||
if (in_array($name, array('get_class', 'get_called_class'))) {
|
||||
$msg = sprintf('%s() called without object from outside a class', $name);
|
||||
throw new ErrorException($msg, 0, E_USER_WARNING, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ClassStmt) {
|
||||
$this->inClass = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function isNull(Node $node)
|
||||
{
|
||||
return $node->value instanceof ConstFetch && strtolower($node->value->name) === 'null';
|
||||
}
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
<?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\NodeVisitorAbstract;
|
||||
|
||||
/**
|
||||
* A CodeCleaner pass is a PhpParser Node Visitor.
|
||||
*/
|
||||
abstract class CodeCleanerPass extends NodeVisitorAbstract
|
||||
{
|
||||
// Wheee!
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
<?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\Expr\Array_ as ArrayNode;
|
||||
use PhpParser\Node\Expr\Assign as AssignNode;
|
||||
use PhpParser\Node\Expr\Empty_ as EmptyNode;
|
||||
use PhpParser\Node\Expr\FuncCall as FunctionCall;
|
||||
use PhpParser\Node\Expr\Isset_ as IssetNode;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the functions are used correctly.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class FunctionReturnInWriteContextPass extends CodeCleanerPass
|
||||
{
|
||||
const EXCEPTION_MESSAGE = "Can't use function return value in write context";
|
||||
|
||||
private $isPhp55;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->isPhp55 = version_compare(PHP_VERSION, '5.5', '>=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the functions are used correctly.
|
||||
*
|
||||
* @throws FatalErrorException if a function is passed as an argument reference
|
||||
* @throws FatalErrorException if a function is used as an argument in the isset
|
||||
* @throws FatalErrorException if a function is used as an argument in the empty, only for PHP < 5.5
|
||||
* @throws FatalErrorException if a value is assigned to a function
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ArrayNode || $this->isCallNode($node)) {
|
||||
$items = $node instanceof ArrayNode ? $node->items : $node->args;
|
||||
foreach ($items as $item) {
|
||||
if ($item->byRef && $this->isCallNode($item->value)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
} elseif ($node instanceof IssetNode) {
|
||||
foreach ($node->vars as $var) {
|
||||
if (!$this->isCallNode($var)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isPhp55) {
|
||||
throw new FatalErrorException('Cannot use isset() on the result of a function call (you can use "null !== func()" instead)');
|
||||
} else {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
} elseif ($node instanceof EmptyNode && !$this->isPhp55 && $this->isCallNode($node->expr)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE);
|
||||
} elseif ($node instanceof AssignNode && $this->isCallNode($node->var)) {
|
||||
throw new FatalErrorException(self::EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private function isCallNode(Node $node)
|
||||
{
|
||||
return $node instanceof FunctionCall || $node instanceof MethodCall || $node instanceof StaticCall;
|
||||
}
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
<?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\Expr;
|
||||
use PhpParser\Node\Expr\Exit_;
|
||||
use PhpParser\Node\Stmt\Return_ as ReturnStmt;
|
||||
|
||||
/**
|
||||
* Add an implicit "return" to the last statement, provided it can be returned.
|
||||
*/
|
||||
class ImplicitReturnPass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* @param array $nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$last = end($nodes);
|
||||
|
||||
if ($last instanceof Expr && !($last instanceof Exit_)) {
|
||||
$nodes[count($nodes) - 1] = new ReturnStmt($last, array(
|
||||
'startLine' => $last->getLine(),
|
||||
'endLine' => $last->getLine(),
|
||||
));
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
<?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\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\Instanceof_ as InstanceofStmt;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Scalar\Encapsed;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the instanceof statement does not receive a scalar value or a non-class constant.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class InstanceOfPass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Validate that the instanceof statement does not receive a scalar value or a non-class constant.
|
||||
*
|
||||
* @throws FatalErrorException if a scalar or a non-class constant is given
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if (!$node instanceof InstanceofStmt) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (($node->expr instanceof Scalar && !$node->expr instanceof Encapsed) || $node->expr instanceof ConstFetch) {
|
||||
throw new FatalErrorException('instanceof expects an object instance, constant given');
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?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\Expr\Variable;
|
||||
use Psy\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Validate that the user input does not reference the `$__psysh__` variable.
|
||||
*/
|
||||
class LeavePsyshAlonePass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Validate that the user input does not reference the `$__psysh__` variable.
|
||||
*
|
||||
* @throws RuntimeException if the user is messing with $__psysh__.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Variable && $node->name === '__psysh__') {
|
||||
throw new RuntimeException('Don\'t mess with $__psysh__. Bad things will happen.');
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
<?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\Expr\Empty_ as ExprEmpty;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Psy\Exception\ParseErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the user did not call the language construct `empty()` on a
|
||||
* statement in PHP < 5.5.
|
||||
*/
|
||||
class LegacyEmptyPass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Validate use of empty in PHP < 5.5.
|
||||
*
|
||||
* @throws ParseErrorException if the user used empty with anything but a variable.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5', '>=')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node instanceof ExprEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$node->expr instanceof Variable) {
|
||||
$msg = sprintf('syntax error, unexpected %s', $this->getUnexpectedThing($node->expr));
|
||||
|
||||
throw new ParseErrorException($msg, $node->expr->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
private function getUnexpectedThing(Node $node)
|
||||
{
|
||||
switch ($node->getType()) {
|
||||
case 'Scalar_String':
|
||||
case 'Scalar_LNumber':
|
||||
case 'Scalar_DNumber':
|
||||
return json_encode($node->value);
|
||||
|
||||
case 'Expr_ConstFetch':
|
||||
return (string) $node->name;
|
||||
|
||||
default:
|
||||
return $node->getType();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
<?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\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar\MagicConst\Dir;
|
||||
use PhpParser\Node\Scalar\MagicConst\File;
|
||||
use PhpParser\Node\Scalar\String_ as StringNode;
|
||||
|
||||
/**
|
||||
* Swap out __DIR__ and __FILE__ magic constants with our best guess?
|
||||
*/
|
||||
class MagicConstantsPass extends CodeCleanerPass
|
||||
{
|
||||
/**
|
||||
* Swap out __DIR__ and __FILE__ constants, because the default ones when
|
||||
* calling eval() don't make sense.
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @return null|FuncCall|StringNode
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Dir) {
|
||||
return new FuncCall(new Name('getcwd'), array(), $node->getAttributes());
|
||||
} elseif ($node instanceof File) {
|
||||
return new StringNode('', $node->getAttributes());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
<?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\Name;
|
||||
use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use PhpParser\Node\Stmt\Namespace_ as NamespaceStmt;
|
||||
|
||||
/**
|
||||
* Abstract namespace-aware code cleaner pass.
|
||||
*/
|
||||
abstract class NamespaceAwarePass extends CodeCleanerPass
|
||||
{
|
||||
protected $namespace;
|
||||
protected $currentScope;
|
||||
|
||||
/**
|
||||
* TODO: should this be final? Extending classes should be sure to either
|
||||
* use afterTraverse or call parent::beforeTraverse() when overloading.
|
||||
*
|
||||
* Reset the namespace and the current scope before beginning analysis.
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->namespace = array();
|
||||
$this->currentScope = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: should this be final? Extending classes should be sure to either use
|
||||
* leaveNode or call parent::enterNode() when overloading.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof NamespaceStmt) {
|
||||
$this->namespace = isset($node->name) ? $node->name->parts : array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fully-qualified name (class, function, interface, etc).
|
||||
*
|
||||
* @param mixed $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getFullyQualifiedName($name)
|
||||
{
|
||||
if ($name instanceof FullyQualifiedName) {
|
||||
return implode('\\', $name->parts);
|
||||
} elseif ($name instanceof Name) {
|
||||
$name = $name->parts;
|
||||
} elseif (!is_array($name)) {
|
||||
$name = array($name);
|
||||
}
|
||||
|
||||
return implode('\\', array_merge($this->namespace, $name));
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
<?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\Name;
|
||||
use PhpParser\Node\Stmt\Namespace_ as NamespaceStmt;
|
||||
use Psy\CodeCleaner;
|
||||
|
||||
/**
|
||||
* Provide implicit namespaces for subsequent execution.
|
||||
*
|
||||
* The namespace pass remembers the last standalone namespace line encountered:
|
||||
*
|
||||
* namespace Foo\Bar;
|
||||
*
|
||||
* ... which it then applies implicitly to all future evaluated code, until the
|
||||
* namespace is replaced by another namespace. To reset to the top level
|
||||
* namespace, enter `namespace {}`. This is a bit ugly, but it does the trick :)
|
||||
*/
|
||||
class NamespacePass extends CodeCleanerPass
|
||||
{
|
||||
private $namespace = null;
|
||||
private $cleaner;
|
||||
|
||||
/**
|
||||
* @param CodeCleaner $cleaner
|
||||
*/
|
||||
public function __construct(CodeCleaner $cleaner)
|
||||
{
|
||||
$this->cleaner = $cleaner;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a standalone namespace line, remember it for later.
|
||||
*
|
||||
* Otherwise, apply remembered namespaces to the code until a new namespace
|
||||
* is encountered.
|
||||
*
|
||||
* @param array $nodes
|
||||
*/
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$first = reset($nodes);
|
||||
if (count($nodes) === 1 && $first instanceof NamespaceStmt && empty($first->stmts)) {
|
||||
$this->setNamespace($first->name);
|
||||
} else {
|
||||
foreach ($nodes as $key => $node) {
|
||||
if ($node instanceof NamespaceStmt) {
|
||||
$this->setNamespace(null);
|
||||
} elseif ($this->namespace !== null) {
|
||||
$nodes[$key] = new NamespaceStmt($this->namespace, array($node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember the namespace and (re)set the namespace on the CodeCleaner as
|
||||
* well.
|
||||
*
|
||||
* @param null|Name $namespace
|
||||
*/
|
||||
private function setNamespace($namespace)
|
||||
{
|
||||
$this->namespace = $namespace;
|
||||
$this->cleaner->setNamespace($namespace === null ? null : $namespace->parts);
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
<?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\Stmt\Class_ as ClassStmt;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Namespace_ as NamespaceStmt;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that the old-style constructor function is not static.
|
||||
*
|
||||
* As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name
|
||||
* will no longer be treated as constructor. This change doesn't affect non-namespaced classes.
|
||||
*
|
||||
* Validation of the __construct method ensures the PHP Parser.
|
||||
*
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class StaticConstructorPass extends CodeCleanerPass
|
||||
{
|
||||
private $isPHP533;
|
||||
private $namespace;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->isPHP533 = version_compare(PHP_VERSION, '5.3.3', '>=');
|
||||
}
|
||||
|
||||
public function beforeTraverse(array $nodes)
|
||||
{
|
||||
$this->namespace = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the old-style constructor function is not static.
|
||||
*
|
||||
* @throws FatalErrorException if the old-style constructor function is static.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof NamespaceStmt) {
|
||||
$this->namespace = isset($node->name) ? $node->name->parts : array();
|
||||
} elseif ($node instanceof ClassStmt) {
|
||||
// Bail early if this is PHP 5.3.3 and we have a namespaced class
|
||||
if (!empty($this->namespace) && $this->isPHP533) {
|
||||
return;
|
||||
}
|
||||
|
||||
$constructor = null;
|
||||
foreach ($node->stmts as $stmt) {
|
||||
if ($stmt instanceof ClassMethod) {
|
||||
// Bail early if we find a new-style constructor
|
||||
if ('__construct' === strtolower($stmt->name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We found a possible old-style constructor
|
||||
// (unless there is also a __construct method)
|
||||
if (strtolower($node->name) === strtolower($stmt->name)) {
|
||||
$constructor = $stmt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($constructor && $constructor->isStatic()) {
|
||||
throw new FatalErrorException(sprintf(
|
||||
'Constructor %s::%s() cannot be static',
|
||||
implode('\\', array_merge($this->namespace, (array) $node->name)),
|
||||
$constructor->name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
@@ -1,111 +0,0 @@
|
||||
<?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\Name;
|
||||
use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
|
||||
use PhpParser\Node\Stmt\Namespace_ as NamespaceStmt;
|
||||
use PhpParser\Node\Stmt\Use_ as UseStmt;
|
||||
|
||||
/**
|
||||
* Provide implicit use statements for subsequent execution.
|
||||
*
|
||||
* The use statement pass remembers the last use statement line encountered:
|
||||
*
|
||||
* use Foo\Bar as Baz;
|
||||
*
|
||||
* ... which it then applies implicitly to all future evaluated code, until the
|
||||
* current namespace is replaced by another namespace.
|
||||
*/
|
||||
class UseStatementPass extends NamespaceAwarePass
|
||||
{
|
||||
private $aliases = array();
|
||||
private $lastAliases = array();
|
||||
private $lastNamespace = null;
|
||||
|
||||
/**
|
||||
* Re-load the last set of use statements on re-entering a namespace.
|
||||
*
|
||||
* This isn't how namespaces normally work, but because PsySH has to spin
|
||||
* up a new namespace for every line of code, we do this to make things
|
||||
* work like you'd expect.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function enterNode(Node $node)
|
||||
{
|
||||
if ($node instanceof NamespaceStmt) {
|
||||
// If this is the same namespace as last namespace, let's do ourselves
|
||||
// a favor and reload all the aliases...
|
||||
if (strtolower($node->name) === strtolower($this->lastNamespace)) {
|
||||
$this->aliases = $this->lastAliases;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this statement is a namespace, forget all the aliases we had.
|
||||
*
|
||||
* If it's a use statement, remember the alias for later. Otherwise, apply
|
||||
* remembered aliases to the code.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof UseStmt) {
|
||||
// Store a reference to every "use" statement, because we'll need
|
||||
// them in a bit.
|
||||
foreach ($node->uses as $use) {
|
||||
$this->aliases[strtolower($use->alias)] = $use->name;
|
||||
}
|
||||
|
||||
return false;
|
||||
} elseif ($node instanceof NamespaceStmt) {
|
||||
// Start fresh, since we're done with this namespace.
|
||||
$this->lastNamespace = $node->name;
|
||||
$this->lastAliases = $this->aliases;
|
||||
$this->aliases = array();
|
||||
} else {
|
||||
foreach ($node as $name => $subNode) {
|
||||
if ($subNode instanceof Name) {
|
||||
// Implicitly thunk all aliases.
|
||||
if ($replacement = $this->findAlias($subNode)) {
|
||||
$node->$name = $replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find class/namespace aliases.
|
||||
*
|
||||
* @param Name $name
|
||||
*
|
||||
* @return FullyQualifiedName|null
|
||||
*/
|
||||
private function findAlias(Name $name)
|
||||
{
|
||||
$that = strtolower($name);
|
||||
foreach ($this->aliases as $alias => $prefix) {
|
||||
if ($that === $alias) {
|
||||
return new FullyQualifiedName($prefix->toString());
|
||||
} elseif (substr($that, 0, strlen($alias) + 1) === $alias . '\\') {
|
||||
return new FullyQualifiedName($prefix->toString() . substr($name, strlen($alias)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,365 +0,0 @@
|
||||
<?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\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\New_ as NewExpr;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_ as ClassStmt;
|
||||
use PhpParser\Node\Stmt\Interface_ as InterfaceStmt;
|
||||
use PhpParser\Node\Stmt\Trait_ as TraitStmt;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that classes exist.
|
||||
*
|
||||
* This pass throws a FatalErrorException rather than letting PHP run
|
||||
* headfirst into a real fatal error and die.
|
||||
*/
|
||||
class ValidClassNamePass extends NamespaceAwarePass
|
||||
{
|
||||
const CLASS_TYPE = 'class';
|
||||
const INTERFACE_TYPE = 'interface';
|
||||
const TRAIT_TYPE = 'trait';
|
||||
|
||||
protected $checkTraits;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->checkTraits = function_exists('trait_exists');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws FatalErrorException if a class implements something that is not an interface.
|
||||
* @throws FatalErrorException if an interface extends something that is not an interface.
|
||||
* @throws FatalErrorException if a class, interface or trait redefines an existing class, interface or trait name.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof NewExpr) {
|
||||
$this->validateNewExpression($node);
|
||||
} elseif ($node instanceof ClassConstFetch) {
|
||||
$this->validateClassConstFetchExpression($node);
|
||||
} elseif ($node instanceof StaticCall) {
|
||||
$this->validateStaticCallExpression($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class definition statement.
|
||||
*
|
||||
* @param ClassStmt $stmt
|
||||
*/
|
||||
protected function validateClassStatement(ClassStmt $stmt)
|
||||
{
|
||||
$this->ensureCanDefine($stmt);
|
||||
if (isset($stmt->extends)) {
|
||||
$this->ensureClassExists($this->getFullyQualifiedName($stmt->extends), $stmt);
|
||||
}
|
||||
$this->ensureInterfacesExist($stmt->implements, $stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an interface definition statement.
|
||||
*
|
||||
* @param InterfaceStmt $stmt
|
||||
*/
|
||||
protected function validateInterfaceStatement(InterfaceStmt $stmt)
|
||||
{
|
||||
$this->ensureCanDefine($stmt);
|
||||
$this->ensureInterfacesExist($stmt->extends, $stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a trait definition statement.
|
||||
*
|
||||
* @param TraitStmt $stmt
|
||||
*/
|
||||
protected function validateTraitStatement(TraitStmt $stmt)
|
||||
{
|
||||
$this->ensureCanDefine($stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a `new` expression.
|
||||
*
|
||||
* @param NewExpr $stmt
|
||||
*/
|
||||
protected function validateNewExpression(NewExpr $stmt)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression's class.
|
||||
*
|
||||
* @param ClassConstFetch $stmt
|
||||
*/
|
||||
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->ensureClassOrInterfaceExists($this->getFullyQualifiedName($stmt->class), $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression's class.
|
||||
*
|
||||
* @param StaticCall $stmt
|
||||
*/
|
||||
protected function validateStaticCallExpression(StaticCall $stmt)
|
||||
{
|
||||
// if class name is an expression, give it a pass for now
|
||||
if (!$stmt->class instanceof Expr) {
|
||||
$this->ensureMethodExists($this->getFullyQualifiedName($stmt->class), $stmt->name, $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that no class, interface or trait name collides with a new definition.
|
||||
*
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureCanDefine(Stmt $stmt)
|
||||
{
|
||||
$name = $this->getFullyQualifiedName($stmt->name);
|
||||
|
||||
// check for name collisions
|
||||
$errorType = null;
|
||||
if ($this->classExists($name)) {
|
||||
$errorType = self::CLASS_TYPE;
|
||||
} elseif ($this->interfaceExists($name)) {
|
||||
$errorType = self::INTERFACE_TYPE;
|
||||
} elseif ($this->traitExists($name)) {
|
||||
$errorType = self::TRAIT_TYPE;
|
||||
}
|
||||
|
||||
if ($errorType !== null) {
|
||||
throw $this->createError(sprintf('%s named %s already exists', ucfirst($errorType), $name), $stmt);
|
||||
}
|
||||
|
||||
// Store creation for the rest of this code snippet so we can find local
|
||||
// issue too
|
||||
$this->currentScope[strtolower($name)] = $this->getScopeType($stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a referenced class exists.
|
||||
*
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureClassExists($name, $stmt)
|
||||
{
|
||||
if (!$this->classExists($name)) {
|
||||
throw $this->createError(sprintf('Class \'%s\' not found', $name), $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $name
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureMethodExists($class, $name, $stmt)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
if (!method_exists($class, $name) && !method_exists($class, '__callStatic')) {
|
||||
throw $this->createError(sprintf('Call to undefined method %s::%s()', $class, $name), $stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a referenced interface exists.
|
||||
*
|
||||
* @throws FatalErrorException
|
||||
*
|
||||
* @param $interfaces
|
||||
* @param Stmt $stmt
|
||||
*/
|
||||
protected function ensureInterfacesExist($interfaces, $stmt)
|
||||
{
|
||||
foreach ($interfaces as $interface) {
|
||||
/** @var string $name */
|
||||
$name = $this->getFullyQualifiedName($interface);
|
||||
if (!$this->interfaceExists($name)) {
|
||||
throw $this->createError(sprintf('Interface \'%s\' not found', $name), $stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a symbol type key for storing in the scope name cache.
|
||||
*
|
||||
* @param Stmt $stmt
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getScopeType(Stmt $stmt)
|
||||
{
|
||||
if ($stmt instanceof ClassStmt) {
|
||||
return self::CLASS_TYPE;
|
||||
} elseif ($stmt instanceof InterfaceStmt) {
|
||||
return self::INTERFACE_TYPE;
|
||||
} elseif ($stmt instanceof TraitStmt) {
|
||||
return self::TRAIT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an interface exists, or has been defined in the current code snippet.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function interfaceExists($name)
|
||||
{
|
||||
return interface_exists($name) || $this->findInScope($name) === self::INTERFACE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a trait exists, or has been defined in the current code snippet.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function traitExists($name)
|
||||
{
|
||||
return $this->checkTraits && (trait_exists($name) || $this->findInScope($name) === self::TRAIT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a symbol in the current code snippet scope.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function findInScope($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
if (isset($this->currentScope[$name])) {
|
||||
return $this->currentScope[$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error creation factory.
|
||||
*
|
||||
* @param string $msg
|
||||
* @param Stmt $stmt
|
||||
*
|
||||
* @return FatalErrorException
|
||||
*/
|
||||
protected function createError($msg, $stmt)
|
||||
{
|
||||
return new FatalErrorException($msg, 0, 1, null, $stmt->getLine());
|
||||
}
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
<?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\Expr;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that namespaced constant references will succeed.
|
||||
*
|
||||
* This pass throws a FatalErrorException rather than letting PHP run
|
||||
* headfirst into a real fatal error and die.
|
||||
*
|
||||
* @todo Detect constants defined in the current code snippet?
|
||||
* ... Might not be worth it, since it would need to both be defining and
|
||||
* referencing a namespaced constant, which doesn't seem like that big of
|
||||
* a target for failure.
|
||||
*/
|
||||
class ValidConstantPass extends NamespaceAwarePass
|
||||
{
|
||||
/**
|
||||
* Validate that namespaced constant references will succeed.
|
||||
*
|
||||
* Note that this does not (yet) detect constants defined in the current code
|
||||
* snippet. It won't happen very often, so we'll punt for now.
|
||||
*
|
||||
* @throws FatalErrorException if a constant reference is not defined.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
if ($node instanceof ConstFetch && count($node->name->parts) > 1) {
|
||||
$name = $this->getFullyQualifiedName($node->name);
|
||||
if (!defined($name)) {
|
||||
throw new FatalErrorException(sprintf('Undefined constant %s', $name), 0, 1, null, $node->getLine());
|
||||
}
|
||||
} elseif ($node instanceof ClassConstFetch) {
|
||||
$this->validateClassConstFetchExpression($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a class constant fetch expression.
|
||||
*
|
||||
* @throws FatalErrorException if a class constant is not defined.
|
||||
*
|
||||
* @param ClassConstFetch $stmt
|
||||
*/
|
||||
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) || interface_exists($className)) {
|
||||
$constName = sprintf('%s::%s', $className, $stmt->name);
|
||||
if (!defined($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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
<?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\Expr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Function_ as FunctionStmt;
|
||||
use Psy\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* Validate that function calls will succeed.
|
||||
*
|
||||
* This pass throws a FatalErrorException rather than letting PHP run
|
||||
* headfirst into a real fatal error and die.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @throws FatalErrorException if a function is redefined.
|
||||
* @throws FatalErrorException if the function name is a string (not an expression) and is not defined.
|
||||
*
|
||||
* @param Node $node
|
||||
*/
|
||||
public function leaveNode(Node $node)
|
||||
{
|
||||
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 Expr && !$name instanceof Variable) {
|
||||
$shortName = implode('\\', $name->parts);
|
||||
$fullName = $this->getFullyQualifiedName($name);
|
||||
$inScope = isset($this->currentScope[strtolower($fullName)]);
|
||||
if (!$inScope && !function_exists($shortName) && !function_exists($fullName)) {
|
||||
$message = sprintf('Call to undefined function %s()', $name);
|
||||
throw new FatalErrorException($message, 0, 1, null, $node->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,77 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Interact with the current code buffer.
|
||||
*
|
||||
* Shows and clears the buffer for the current multi-line expression.
|
||||
*/
|
||||
class BufferCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('buffer')
|
||||
->setAliases(array('buf'))
|
||||
->setDefinition(array(
|
||||
new InputOption('clear', '', InputOption::VALUE_NONE, 'Clear the current buffer.'),
|
||||
))
|
||||
->setDescription('Show (or clear) the contents of the code input buffer.')
|
||||
->setHelp(
|
||||
<<<'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.
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$buf = $this->getApplication()->getCodeBuffer();
|
||||
if ($input->getOption('clear')) {
|
||||
$this->getApplication()->resetCodeBuffer();
|
||||
$output->writeln($this->formatLines($buf, 'urgent'), ShellOutput::NUMBER_LINES);
|
||||
} else {
|
||||
$output->writeln($this->formatLines($buf), ShellOutput::NUMBER_LINES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for wrapping buffer lines in `<urgent>` and `<return>` formatter strings.
|
||||
*
|
||||
* @param array $lines
|
||||
* @param string $type (default: 'return')
|
||||
*
|
||||
* @return array Formatted strings
|
||||
*/
|
||||
protected function formatLines(array $lines, $type = 'return')
|
||||
{
|
||||
$template = sprintf('<%s>%%s</%s>', $type, $type);
|
||||
|
||||
return array_map(function ($line) use ($template) {
|
||||
return sprintf($template, $line);
|
||||
}, $lines);
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Clear the Psy Shell.
|
||||
*
|
||||
* Just what it says on the tin.
|
||||
*/
|
||||
class ClearCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('clear')
|
||||
->setDefinition(array())
|
||||
->setDescription('Clear the Psy Shell screen.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
Clear the Psy Shell screen.
|
||||
|
||||
Pro Tip: If your PHP has readline support, you should be able to use ctrl+l too!
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->write(sprintf('%c[2J%c[0;0f', 27, 27));
|
||||
}
|
||||
}
|
282
vendor/psy/psysh/src/Psy/Command/Command.php
vendored
282
vendor/psy/psysh/src/Psy/Command/Command.php
vendored
@@ -1,282 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Shell;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command as BaseCommand;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Helper\TableStyle;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* The Psy Shell base command.
|
||||
*/
|
||||
abstract class Command extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* Sets the application instance for this command.
|
||||
*
|
||||
* @param Application $application An Application instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setApplication(Application $application = null)
|
||||
{
|
||||
if ($application !== null && !$application instanceof Shell) {
|
||||
throw new \InvalidArgumentException('PsySH Commands require an instance of Psy\Shell.');
|
||||
}
|
||||
|
||||
return parent::setApplication($application);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function asText()
|
||||
{
|
||||
$messages = array(
|
||||
'<comment>Usage:</comment>',
|
||||
' ' . $this->getSynopsis(),
|
||||
'',
|
||||
);
|
||||
|
||||
if ($this->getAliases()) {
|
||||
$messages[] = $this->aliasesAsText();
|
||||
}
|
||||
|
||||
if ($this->getArguments()) {
|
||||
$messages[] = $this->argumentsAsText();
|
||||
}
|
||||
|
||||
if ($this->getOptions()) {
|
||||
$messages[] = $this->optionsAsText();
|
||||
}
|
||||
|
||||
if ($help = $this->getProcessedHelp()) {
|
||||
$messages[] = '<comment>Help:</comment>';
|
||||
$messages[] = ' ' . str_replace("\n", "\n ", $help) . "\n";
|
||||
}
|
||||
|
||||
return implode("\n", $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function getArguments()
|
||||
{
|
||||
$hidden = $this->getHiddenArguments();
|
||||
|
||||
return array_filter($this->getNativeDefinition()->getArguments(), function ($argument) use ($hidden) {
|
||||
return !in_array($argument->getName(), $hidden);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* These arguments will be excluded from help output.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHiddenArguments()
|
||||
{
|
||||
return array('command');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
private function getOptions()
|
||||
{
|
||||
$hidden = $this->getHiddenOptions();
|
||||
|
||||
return array_filter($this->getNativeDefinition()->getOptions(), function ($option) use ($hidden) {
|
||||
return !in_array($option->getName(), $hidden);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* These options will be excluded from help output.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHiddenOptions()
|
||||
{
|
||||
return array('verbose');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format command aliases as text..
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function aliasesAsText()
|
||||
{
|
||||
return '<comment>Aliases:</comment> <info>' . implode(', ', $this->getAliases()) . '</info>' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format command arguments as text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function argumentsAsText()
|
||||
{
|
||||
$max = $this->getMaxWidth();
|
||||
$messages = array();
|
||||
|
||||
$arguments = $this->getArguments();
|
||||
if (!empty($arguments)) {
|
||||
$messages[] = '<comment>Arguments:</comment>';
|
||||
foreach ($arguments as $argument) {
|
||||
if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($argument->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$description = str_replace("\n", "\n" . str_pad('', $max + 2, ' '), $argument->getDescription());
|
||||
|
||||
$messages[] = sprintf(" <info>%-${max}s</info> %s%s", $argument->getName(), $description, $default);
|
||||
}
|
||||
|
||||
$messages[] = '';
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format options as text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function optionsAsText()
|
||||
{
|
||||
$max = $this->getMaxWidth();
|
||||
$messages = array();
|
||||
|
||||
$options = $this->getOptions();
|
||||
if ($options) {
|
||||
$messages[] = '<comment>Options:</comment>';
|
||||
|
||||
foreach ($options as $option) {
|
||||
if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
|
||||
$default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($option->getDefault()));
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$multiple = $option->isArray() ? '<comment> (multiple values allowed)</comment>' : '';
|
||||
$description = str_replace("\n", "\n" . str_pad('', $max + 2, ' '), $option->getDescription());
|
||||
|
||||
$optionMax = $max - strlen($option->getName()) - 2;
|
||||
$messages[] = sprintf(
|
||||
" <info>%s</info> %-${optionMax}s%s%s%s",
|
||||
'--' . $option->getName(),
|
||||
$option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
|
||||
$description,
|
||||
$default,
|
||||
$multiple
|
||||
);
|
||||
}
|
||||
|
||||
$messages[] = '';
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the maximum padding width for a set of lines.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getMaxWidth()
|
||||
{
|
||||
$max = 0;
|
||||
|
||||
foreach ($this->getOptions() as $option) {
|
||||
$nameLength = strlen($option->getName()) + 2;
|
||||
if ($option->getShortcut()) {
|
||||
$nameLength += strlen($option->getShortcut()) + 3;
|
||||
}
|
||||
|
||||
$max = max($max, $nameLength);
|
||||
}
|
||||
|
||||
foreach ($this->getArguments() as $argument) {
|
||||
$max = max($max, strlen($argument->getName()));
|
||||
}
|
||||
|
||||
return ++$max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an option default as text.
|
||||
*
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatDefaultValue($default)
|
||||
{
|
||||
if (is_array($default) && $default === array_values($default)) {
|
||||
return sprintf("array('%s')", implode("', '", $default));
|
||||
}
|
||||
|
||||
return str_replace("\n", '', var_export($default, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Table instance.
|
||||
*
|
||||
* Falls back to legacy TableHelper.
|
||||
*
|
||||
* @return Table|TableHelper
|
||||
*/
|
||||
protected function getTable(OutputInterface $output)
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Console\Helper\Table')) {
|
||||
return $this->getTableHelper();
|
||||
}
|
||||
|
||||
$style = new TableStyle();
|
||||
$style
|
||||
->setVerticalBorderChar(' ')
|
||||
->setHorizontalBorderChar('')
|
||||
->setCrossingChar('');
|
||||
|
||||
$table = new Table($output);
|
||||
|
||||
return $table
|
||||
->setRows(array())
|
||||
->setStyle($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy fallback for getTable.
|
||||
*
|
||||
* @return TableHelper
|
||||
*/
|
||||
protected function getTableHelper()
|
||||
{
|
||||
$table = $this->getApplication()->getHelperSet()->get('table');
|
||||
|
||||
return $table
|
||||
->setRows(array())
|
||||
->setLayout(TableHelper::LAYOUT_BORDERLESS)
|
||||
->setHorizontalBorderChar('')
|
||||
->setCrossingChar('');
|
||||
}
|
||||
}
|
98
vendor/psy/psysh/src/Psy/Command/DocCommand.php
vendored
98
vendor/psy/psysh/src/Psy/Command/DocCommand.php
vendored
@@ -1,98 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Formatter\DocblockFormatter;
|
||||
use Psy\Formatter\SignatureFormatter;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Read the documentation for an object, class, constant, method or property.
|
||||
*/
|
||||
class DocCommand extends ReflectingCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('doc')
|
||||
->setAliases(array('rtfm', 'man'))
|
||||
->setDefinition(array(
|
||||
new InputArgument('value', InputArgument::REQUIRED, 'Function, class, instance, constant, method or property to document.'),
|
||||
))
|
||||
->setDescription('Read the documentation for an object, class, constant, method or property.')
|
||||
->setHelp(
|
||||
<<<HELP
|
||||
Read the documentation for an object, class, constant, method or property.
|
||||
|
||||
It's awesome for well-documented code, not quite as awesome for poorly documented code.
|
||||
|
||||
e.g.
|
||||
<return>>>> doc preg_replace</return>
|
||||
<return>>>> doc Psy\Shell</return>
|
||||
<return>>>> doc Psy\Shell::debug</return>
|
||||
<return>>>> \$s = new Psy\Shell</return>
|
||||
<return>>>> doc \$s->run</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
list($value, $reflector) = $this->getTargetAndReflector($input->getArgument('value'));
|
||||
|
||||
$doc = $this->getManualDoc($reflector) ?: DocblockFormatter::format($reflector);
|
||||
$db = $this->getApplication()->getManualDb();
|
||||
|
||||
$output->page(function ($output) use ($reflector, $doc, $db) {
|
||||
$output->writeln(SignatureFormatter::format($reflector));
|
||||
if (empty($doc) && !$db) {
|
||||
$output->writeln('');
|
||||
$output->writeln('<warning>PHP manual not found</warning>');
|
||||
$output->writeln(' To document core PHP functionality, download the PHP reference manual:');
|
||||
$output->writeln(' https://github.com/bobthecow/psysh#downloading-the-manual');
|
||||
} else {
|
||||
$output->writeln('');
|
||||
$output->writeln($doc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function getManualDoc($reflector)
|
||||
{
|
||||
switch (get_class($reflector)) {
|
||||
case 'ReflectionFunction':
|
||||
$id = $reflector->name;
|
||||
break;
|
||||
|
||||
case 'ReflectionMethod':
|
||||
$id = $reflector->class . '::' . $reflector->name;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($db = $this->getApplication()->getManualDb()) {
|
||||
return $db
|
||||
->query(sprintf('SELECT doc FROM php_manual WHERE id = %s', $db->quote($id)))
|
||||
->fetchColumn(0);
|
||||
}
|
||||
}
|
||||
}
|
95
vendor/psy/psysh/src/Psy/Command/DumpCommand.php
vendored
95
vendor/psy/psysh/src/Psy/Command/DumpCommand.php
vendored
@@ -1,95 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Exception\RuntimeException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Dump an object or primitive.
|
||||
*
|
||||
* This is like var_dump but *way* awesomer.
|
||||
*/
|
||||
class DumpCommand extends ReflectingCommand implements PresenterAware
|
||||
{
|
||||
private $presenter;
|
||||
|
||||
/**
|
||||
* PresenterAware interface.
|
||||
*
|
||||
* @param Presenter $presenter
|
||||
*/
|
||||
public function setPresenter(Presenter $presenter)
|
||||
{
|
||||
$this->presenter = $presenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('dump')
|
||||
->setDefinition(array(
|
||||
new InputArgument('target', InputArgument::REQUIRED, 'A target object or primitive to dump.', null),
|
||||
new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse', 10),
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Include private and protected methods and properties.'),
|
||||
))
|
||||
->setDescription('Dump an object or primitive.')
|
||||
->setHelp(
|
||||
<<<'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>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$depth = $input->getOption('depth');
|
||||
$target = $this->resolveTarget($input->getArgument('target'));
|
||||
$output->page($this->presenter->present($target, $depth, $input->getOption('all') ? Presenter::VERBOSE : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve dump target name.
|
||||
*
|
||||
* @throws RuntimeException if target name does not exist in the current scope.
|
||||
*
|
||||
* @param string $target
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveTarget($target)
|
||||
{
|
||||
$matches = array();
|
||||
if (preg_match(self::INSTANCE, $target, $matches)) {
|
||||
return $this->getScopeVariable($matches[1]);
|
||||
} else {
|
||||
throw new RuntimeException('Unknown target: ' . $target);
|
||||
}
|
||||
}
|
||||
}
|
52
vendor/psy/psysh/src/Psy/Command/ExitCommand.php
vendored
52
vendor/psy/psysh/src/Psy/Command/ExitCommand.php
vendored
@@ -1,52 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Exception\BreakException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Exit the Psy Shell.
|
||||
*
|
||||
* Just what it says on the tin.
|
||||
*/
|
||||
class ExitCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('exit')
|
||||
->setAliases(array('quit', 'q'))
|
||||
->setDefinition(array())
|
||||
->setDescription('End the current session and return to caller.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
End the current session and return to caller.
|
||||
|
||||
e.g.
|
||||
<return>>>> exit</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
throw new BreakException('Goodbye.');
|
||||
}
|
||||
}
|
98
vendor/psy/psysh/src/Psy/Command/HelpCommand.php
vendored
98
vendor/psy/psysh/src/Psy/Command/HelpCommand.php
vendored
@@ -1,98 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Help command.
|
||||
*
|
||||
* Lists available commands, and gives command-specific help when asked nicely.
|
||||
*/
|
||||
class HelpCommand extends Command
|
||||
{
|
||||
private $command;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('help')
|
||||
->setAliases(array('?'))
|
||||
->setDefinition(array(
|
||||
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', null),
|
||||
))
|
||||
->setDescription('Show a list of commands. Type `help [foo]` for information about [foo].')
|
||||
->setHelp('My. How meta.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for setting a subcommand to retrieve help for.
|
||||
*
|
||||
* @param Command $command
|
||||
*/
|
||||
public function setCommand($command)
|
||||
{
|
||||
$this->command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($this->command !== null) {
|
||||
// help for an individual command
|
||||
$output->page($this->command->asText());
|
||||
$this->command = null;
|
||||
} elseif ($name = $input->getArgument('command_name')) {
|
||||
// help for an individual command
|
||||
$output->page($this->getApplication()->get($name)->asText());
|
||||
} else {
|
||||
// list available commands
|
||||
$commands = $this->getApplication()->all();
|
||||
|
||||
$table = $this->getTable($output);
|
||||
|
||||
foreach ($commands as $name => $command) {
|
||||
if ($name !== $command->getName()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($command->getAliases()) {
|
||||
$aliases = sprintf('<comment>Aliases:</comment> %s', implode(', ', $command->getAliases()));
|
||||
} else {
|
||||
$aliases = '';
|
||||
}
|
||||
|
||||
$table->addRow(array(
|
||||
sprintf('<info>%s</info>', $name),
|
||||
$command->getDescription(),
|
||||
$aliases,
|
||||
));
|
||||
}
|
||||
|
||||
$output->startPaging();
|
||||
if ($table instanceof TableHelper) {
|
||||
$table->render($output);
|
||||
} else {
|
||||
$table->render();
|
||||
}
|
||||
$output->stopPaging();
|
||||
}
|
||||
}
|
||||
}
|
260
vendor/psy/psysh/src/Psy/Command/HistoryCommand.php
vendored
260
vendor/psy/psysh/src/Psy/Command/HistoryCommand.php
vendored
@@ -1,260 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Output\ShellOutput;
|
||||
use Psy\Readline\Readline;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Psy Shell history command.
|
||||
*
|
||||
* Shows, searches and replays readline history. Not too shabby.
|
||||
*/
|
||||
class HistoryCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Set the Shell's Readline service.
|
||||
*
|
||||
* @param Readline $readline
|
||||
*/
|
||||
public function setReadline(Readline $readline)
|
||||
{
|
||||
$this->readline = $readline;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('history')
|
||||
->setAliases(array('hist'))
|
||||
->setDefinition(array(
|
||||
new InputOption('show', 's', InputOption::VALUE_REQUIRED, 'Show the given range of lines'),
|
||||
new InputOption('head', 'H', InputOption::VALUE_REQUIRED, 'Display the first N items.'),
|
||||
new InputOption('tail', 'T', InputOption::VALUE_REQUIRED, 'Display the last N items.'),
|
||||
|
||||
new InputOption('grep', 'G', InputOption::VALUE_REQUIRED, 'Show lines matching the given pattern (string or regex).'),
|
||||
new InputOption('insensitive', 'i', InputOption::VALUE_NONE, 'Case insensitive search (requires --grep).'),
|
||||
new InputOption('invert', 'v', InputOption::VALUE_NONE, 'Inverted search (requires --grep).'),
|
||||
|
||||
new InputOption('no-numbers', 'N', InputOption::VALUE_NONE, 'Omit line numbers.'),
|
||||
|
||||
new InputOption('save', '', InputOption::VALUE_REQUIRED, 'Save history to a file.'),
|
||||
new InputOption('replay', '', InputOption::VALUE_NONE, 'Replay'),
|
||||
new InputOption('clear', '', InputOption::VALUE_NONE, 'Clear the history.'),
|
||||
))
|
||||
->setDescription('Show the Psy Shell history.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
Show, search, save or replay the Psy Shell history.
|
||||
|
||||
e.g.
|
||||
<return>>>> history --grep /[bB]acon/</return>
|
||||
<return>>>> history --show 0..10 --replay</return>
|
||||
<return>>>> history --clear</return>
|
||||
<return>>>> history --tail 1000 --save somefile.txt</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->validateOnlyOne($input, array('show', 'head', 'tail'));
|
||||
$this->validateOnlyOne($input, array('save', 'replay', 'clear'));
|
||||
|
||||
$history = $this->getHistorySlice(
|
||||
$input->getOption('show'),
|
||||
$input->getOption('head'),
|
||||
$input->getOption('tail')
|
||||
);
|
||||
$highlighted = false;
|
||||
|
||||
$invert = $input->getOption('invert');
|
||||
$insensitive = $input->getOption('insensitive');
|
||||
if ($pattern = $input->getOption('grep')) {
|
||||
if (substr($pattern, 0, 1) !== '/' || substr($pattern, -1) !== '/' || strlen($pattern) < 3) {
|
||||
$pattern = '/' . preg_quote($pattern, '/') . '/';
|
||||
}
|
||||
|
||||
if ($insensitive) {
|
||||
$pattern .= 'i';
|
||||
}
|
||||
|
||||
$this->validateRegex($pattern);
|
||||
|
||||
$matches = array();
|
||||
$highlighted = array();
|
||||
foreach ($history as $i => $line) {
|
||||
if (preg_match($pattern, $line, $matches) xor $invert) {
|
||||
if (!$invert) {
|
||||
$chunks = explode($matches[0], $history[$i]);
|
||||
$chunks = array_map(array(__CLASS__, 'escape'), $chunks);
|
||||
$glue = sprintf('<urgent>%s</urgent>', self::escape($matches[0]));
|
||||
|
||||
$highlighted[$i] = implode($glue, $chunks);
|
||||
}
|
||||
} else {
|
||||
unset($history[$i]);
|
||||
}
|
||||
}
|
||||
} elseif ($invert) {
|
||||
throw new \InvalidArgumentException('Cannot use -v without --grep.');
|
||||
} elseif ($insensitive) {
|
||||
throw new \InvalidArgumentException('Cannot use -i without --grep.');
|
||||
}
|
||||
|
||||
if ($save = $input->getOption('save')) {
|
||||
$output->writeln(sprintf('Saving history in %s...', $save));
|
||||
file_put_contents($save, implode(PHP_EOL, $history) . PHP_EOL);
|
||||
$output->writeln('<info>History saved.</info>');
|
||||
} elseif ($input->getOption('replay')) {
|
||||
if (!($input->getOption('show') || $input->getOption('head') || $input->getOption('tail'))) {
|
||||
throw new \InvalidArgumentException('You must limit history via --head, --tail or --show before replaying.');
|
||||
}
|
||||
|
||||
$count = count($history);
|
||||
$output->writeln(sprintf('Replaying %d line%s of history', $count, ($count !== 1) ? 's' : ''));
|
||||
$this->getApplication()->addInput($history);
|
||||
} elseif ($input->getOption('clear')) {
|
||||
$this->clearHistory();
|
||||
$output->writeln('<info>History cleared.</info>');
|
||||
} else {
|
||||
$type = $input->getOption('no-numbers') ? 0 : ShellOutput::NUMBER_LINES;
|
||||
if (!$highlighted) {
|
||||
$type = $type | ShellOutput::OUTPUT_RAW;
|
||||
}
|
||||
|
||||
$output->page($highlighted ?: $history, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a range from a string.
|
||||
*
|
||||
* @param string $range
|
||||
*
|
||||
* @return array [ start, end ]
|
||||
*/
|
||||
private function extractRange($range)
|
||||
{
|
||||
if (preg_match('/^\d+$/', $range)) {
|
||||
return array($range, $range + 1);
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
if ($range !== '..' && preg_match('/^(\d*)\.\.(\d*)$/', $range, $matches)) {
|
||||
$start = $matches[1] ? intval($matches[1]) : 0;
|
||||
$end = $matches[2] ? intval($matches[2]) + 1 : PHP_INT_MAX;
|
||||
|
||||
return array($start, $end);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Unexpected range: ' . $range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a slice of the readline history.
|
||||
*
|
||||
* @param string $show
|
||||
* @param string $head
|
||||
* @param string $tail
|
||||
*
|
||||
* @return array A slilce of history.
|
||||
*/
|
||||
private function getHistorySlice($show, $head, $tail)
|
||||
{
|
||||
$history = $this->readline->listHistory();
|
||||
|
||||
if ($show) {
|
||||
list($start, $end) = $this->extractRange($show);
|
||||
$length = $end - $start;
|
||||
} elseif ($head) {
|
||||
if (!preg_match('/^\d+$/', $head)) {
|
||||
throw new \InvalidArgumentException('Please specify an integer argument for --head.');
|
||||
}
|
||||
|
||||
$start = 0;
|
||||
$length = intval($head);
|
||||
} elseif ($tail) {
|
||||
if (!preg_match('/^\d+$/', $tail)) {
|
||||
throw new \InvalidArgumentException('Please specify an integer argument for --tail.');
|
||||
}
|
||||
|
||||
$start = count($history) - $tail;
|
||||
$length = intval($tail) + 1;
|
||||
} else {
|
||||
return $history;
|
||||
}
|
||||
|
||||
return array_slice($history, $start, $length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that $pattern is a valid regular expression.
|
||||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validateRegex($pattern)
|
||||
{
|
||||
set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
|
||||
try {
|
||||
preg_match($pattern, '');
|
||||
} catch (ErrorException $e) {
|
||||
throw new RuntimeException(str_replace('preg_match(): ', 'Invalid regular expression: ', $e->getRawMessage()));
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that only one of the given $options is set.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param array $options
|
||||
*/
|
||||
private function validateOnlyOne(InputInterface $input, array $options)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($options as $opt) {
|
||||
if ($input->getOption($opt)) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count > 1) {
|
||||
throw new \InvalidArgumentException('Please specify only one of --' . implode(', --', $options));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the readline history.
|
||||
*/
|
||||
private function clearHistory()
|
||||
{
|
||||
$this->readline->clearHistory();
|
||||
}
|
||||
|
||||
public static function escape($string)
|
||||
{
|
||||
return OutputFormatter::escape($string);
|
||||
}
|
||||
}
|
278
vendor/psy/psysh/src/Psy/Command/ListCommand.php
vendored
278
vendor/psy/psysh/src/Psy/Command/ListCommand.php
vendored
@@ -1,278 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Command\ListCommand\ClassConstantEnumerator;
|
||||
use Psy\Command\ListCommand\ClassEnumerator;
|
||||
use Psy\Command\ListCommand\ConstantEnumerator;
|
||||
use Psy\Command\ListCommand\FunctionEnumerator;
|
||||
use Psy\Command\ListCommand\GlobalVariableEnumerator;
|
||||
use Psy\Command\ListCommand\InterfaceEnumerator;
|
||||
use Psy\Command\ListCommand\MethodEnumerator;
|
||||
use Psy\Command\ListCommand\PropertyEnumerator;
|
||||
use Psy\Command\ListCommand\TraitEnumerator;
|
||||
use Psy\Command\ListCommand\VariableEnumerator;
|
||||
use Psy\Exception\RuntimeException;
|
||||
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;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* List available local variables, object properties, etc.
|
||||
*/
|
||||
class ListCommand extends ReflectingCommand implements PresenterAware
|
||||
{
|
||||
protected $presenter;
|
||||
protected $enumerators;
|
||||
|
||||
/**
|
||||
* PresenterAware interface.
|
||||
*
|
||||
* @param Presenter $manager
|
||||
*/
|
||||
public function setPresenter(Presenter $presenter)
|
||||
{
|
||||
$this->presenter = $presenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('ls')
|
||||
->setAliases(array('list', 'dir'))
|
||||
->setDefinition(array(
|
||||
new InputArgument('target', InputArgument::OPTIONAL, 'A target class or object to list.', null),
|
||||
|
||||
new InputOption('vars', '', InputOption::VALUE_NONE, 'Display variables.'),
|
||||
new InputOption('constants', 'c', InputOption::VALUE_NONE, 'Display defined constants.'),
|
||||
new InputOption('functions', 'f', InputOption::VALUE_NONE, 'Display defined functions.'),
|
||||
new InputOption('classes', 'k', InputOption::VALUE_NONE, 'Display declared classes.'),
|
||||
new InputOption('interfaces', 'I', InputOption::VALUE_NONE, 'Display declared interfaces.'),
|
||||
new InputOption('traits', 't', InputOption::VALUE_NONE, 'Display declared traits.'),
|
||||
|
||||
new InputOption('properties', 'p', InputOption::VALUE_NONE, 'Display class or object properties (public properties by default).'),
|
||||
new InputOption('methods', 'm', InputOption::VALUE_NONE, 'Display class or object methods (public methods by default).'),
|
||||
|
||||
new InputOption('grep', 'G', InputOption::VALUE_REQUIRED, 'Limit to items matching the given pattern (string or regex).'),
|
||||
new InputOption('insensitive', 'i', InputOption::VALUE_NONE, 'Case-insensitive search (requires --grep).'),
|
||||
new InputOption('invert', 'v', InputOption::VALUE_NONE, 'Inverted search (requires --grep).'),
|
||||
|
||||
new InputOption('globals', 'g', InputOption::VALUE_NONE, 'Include global variables.'),
|
||||
new InputOption('internal', 'n', InputOption::VALUE_NONE, 'Limit to internal functions and classes.'),
|
||||
new InputOption('user', 'u', InputOption::VALUE_NONE, 'Limit to user-defined constants, functions and classes.'),
|
||||
new InputOption('category', 'C', InputOption::VALUE_REQUIRED, 'Limit to constants in a specific category (e.g. "date").'),
|
||||
|
||||
new InputOption('all', 'a', InputOption::VALUE_NONE, 'Include private and protected methods and properties.'),
|
||||
new InputOption('long', 'l', InputOption::VALUE_NONE, 'List in long format: includes class names and method signatures.'),
|
||||
))
|
||||
->setDescription('List local, instance or class variables, methods and constants.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
List variables, constants, classes, interfaces, traits, functions, methods,
|
||||
and properties.
|
||||
|
||||
Called without options, this will return a list of variables currently in scope.
|
||||
|
||||
If a target object is provided, list properties, constants and methods of that
|
||||
target. If a class, interface or trait name is passed instead, list constants
|
||||
and methods on that class.
|
||||
|
||||
e.g.
|
||||
<return>>>> ls</return>
|
||||
<return>>>> ls $foo</return>
|
||||
<return>>>> ls -k --grep mongo -i</return>
|
||||
<return>>>> ls -al ReflectionClass</return>
|
||||
<return>>>> ls --constants --category date</return>
|
||||
<return>>>> ls -l --functions --grep /^array_.*/</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->validateInput($input);
|
||||
$this->initEnumerators();
|
||||
|
||||
$method = $input->getOption('long') ? 'writeLong' : 'write';
|
||||
|
||||
if ($target = $input->getArgument('target')) {
|
||||
list($target, $reflector) = $this->getTargetAndReflector($target, true);
|
||||
} else {
|
||||
$reflector = null;
|
||||
}
|
||||
|
||||
// TODO: something cleaner than this :-/
|
||||
if ($input->getOption('long')) {
|
||||
$output->startPaging();
|
||||
}
|
||||
|
||||
foreach ($this->enumerators as $enumerator) {
|
||||
$this->$method($output, $enumerator->enumerate($input, $reflector, $target));
|
||||
}
|
||||
|
||||
if ($input->getOption('long')) {
|
||||
$output->stopPaging();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Enumerators.
|
||||
*/
|
||||
protected function initEnumerators()
|
||||
{
|
||||
if (!isset($this->enumerators)) {
|
||||
$mgr = $this->presenter;
|
||||
|
||||
$this->enumerators = array(
|
||||
new ClassConstantEnumerator($mgr),
|
||||
new ClassEnumerator($mgr),
|
||||
new ConstantEnumerator($mgr),
|
||||
new FunctionEnumerator($mgr),
|
||||
new GlobalVariableEnumerator($mgr),
|
||||
new InterfaceEnumerator($mgr),
|
||||
new PropertyEnumerator($mgr),
|
||||
new MethodEnumerator($mgr),
|
||||
new TraitEnumerator($mgr),
|
||||
new VariableEnumerator($mgr, $this->context),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the list items to $output.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param null|array $result List of enumerated items.
|
||||
*/
|
||||
protected function write(OutputInterface $output, array $result = null)
|
||||
{
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($result as $label => $items) {
|
||||
$names = array_map(array($this, 'formatItemName'), $items);
|
||||
$output->writeln(sprintf('<strong>%s</strong>: %s', $label, implode(', ', $names)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the list items to $output.
|
||||
*
|
||||
* Items are listed one per line, and include the item signature.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param null|array $result List of enumerated items.
|
||||
*/
|
||||
protected function writeLong(OutputInterface $output, array $result = null)
|
||||
{
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = $this->getTable($output);
|
||||
|
||||
foreach ($result as $label => $items) {
|
||||
$output->writeln('');
|
||||
$output->writeln(sprintf('<strong>%s:</strong>', $label));
|
||||
|
||||
$table->setRows(array());
|
||||
foreach ($items as $item) {
|
||||
$table->addRow(array($this->formatItemName($item), $item['value']));
|
||||
}
|
||||
|
||||
if ($table instanceof TableHelper) {
|
||||
$table->render($output);
|
||||
} else {
|
||||
$table->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an item name given its visibility.
|
||||
*
|
||||
* @param array $item
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function formatItemName($item)
|
||||
{
|
||||
return sprintf('<%s>%s</%s>', $item['style'], OutputFormatter::escape($item['name']), $item['style']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that input options make sense, provide defaults when called without options.
|
||||
*
|
||||
* @throws RuntimeException if options are inconsistent.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
*/
|
||||
private function validateInput(InputInterface $input)
|
||||
{
|
||||
// grep, invert and insensitive
|
||||
if (!$input->getOption('grep')) {
|
||||
foreach (array('invert', 'insensitive') as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
throw new RuntimeException('--' . $option . ' does not make sense without --grep');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$input->getArgument('target')) {
|
||||
// if no target is passed, there can be no properties or methods
|
||||
foreach (array('properties', 'methods') as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
throw new RuntimeException('--' . $option . ' does not make sense without a specified target.');
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('globals', 'vars', 'constants', 'functions', 'classes', 'interfaces', 'traits') as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// default to --vars if no other options are passed
|
||||
$input->setOption('vars', true);
|
||||
} else {
|
||||
// if a target is passed, classes, functions, etc don't make sense
|
||||
foreach (array('vars', 'globals', 'functions', 'classes', 'interfaces', 'traits') as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
throw new RuntimeException('--' . $option . ' does not make sense with a specified target.');
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('constants', 'properties', 'methods') as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// default to --constants --properties --methods if no other options are passed
|
||||
$input->setOption('constants', true);
|
||||
$input->setOption('properties', true);
|
||||
$input->setOption('methods', true);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,118 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Psy\Reflection\ReflectionConstant;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Class Constant Enumerator class.
|
||||
*/
|
||||
class ClassConstantEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list constants when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can only list constants on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
// TODO: handle ReflectionExtension as well
|
||||
return;
|
||||
}
|
||||
|
||||
// only list constants if we are specifically asked
|
||||
if (!$input->getOption('constants')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$constants = $this->prepareConstants($this->getConstants($reflector));
|
||||
|
||||
if (empty($constants)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
$ret[$this->getKindLabel($reflector)] = $constants;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined constants for the given class or object Reflector.
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstants(\Reflector $reflector)
|
||||
{
|
||||
$constants = array();
|
||||
foreach ($reflector->getConstants() as $name => $constant) {
|
||||
$constants[$name] = new ReflectionConstant($reflector, $name);
|
||||
}
|
||||
|
||||
// TODO: this should be natcasesort
|
||||
ksort($constants);
|
||||
|
||||
return $constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted constant array.
|
||||
*
|
||||
* @param array $constants
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareConstants(array $constants)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($constants as $name => $constant) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_CONSTANT,
|
||||
'value' => $this->presentRef($constant->getValue()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a label for the particular kind of "class" represented.
|
||||
*
|
||||
* @param \ReflectionClass $reflector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Constants';
|
||||
} elseif (method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
return 'Trait Constants';
|
||||
} else {
|
||||
return 'Class Constants';
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Class Enumerator class.
|
||||
*/
|
||||
class ClassEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list classes when no Reflector is present.
|
||||
//
|
||||
// TODO: make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --classes Foo
|
||||
//
|
||||
// ... for listing classes in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list classes if we are specifically asked
|
||||
if (!$input->getOption('classes')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$classes = $this->prepareClasses(get_declared_classes());
|
||||
|
||||
if (empty($classes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'Classes' => $classes,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted class array.
|
||||
*
|
||||
* @param array $class
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareClasses(array $classes)
|
||||
{
|
||||
natcasesort($classes);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($classes as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_CLASS,
|
||||
'value' => $this->presentSignature($name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Constant Enumerator class.
|
||||
*/
|
||||
class ConstantEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list constants when no Reflector is present.
|
||||
//
|
||||
// TODO: make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --constants Foo
|
||||
//
|
||||
// ... for listing constants in the Foo namespace
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list constants if we are specifically asked
|
||||
if (!$input->getOption('constants')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$category = $input->getOption('user') ? 'user' : $input->getOption('category');
|
||||
$label = $category ? ucfirst($category) . ' Constants' : 'Constants';
|
||||
$constants = $this->prepareConstants($this->getConstants($category));
|
||||
|
||||
if (empty($constants)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
$ret[$label] = $constants;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined constants.
|
||||
*
|
||||
* Optionally restrict constants to a given category, e.g. "date".
|
||||
*
|
||||
* @param string $category
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getConstants($category = null)
|
||||
{
|
||||
if (!$category) {
|
||||
return get_defined_constants();
|
||||
}
|
||||
|
||||
$consts = get_defined_constants(true);
|
||||
|
||||
return isset($consts[$category]) ? $consts[$category] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted constant array.
|
||||
*
|
||||
* @param array $constants
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareConstants(array $constants)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
$names = array_keys($constants);
|
||||
natcasesort($names);
|
||||
|
||||
foreach ($names as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_CONSTANT,
|
||||
'value' => $this->presentRef($constants[$name]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Psy\Formatter\SignatureFormatter;
|
||||
use Psy\Util\Mirror;
|
||||
use Psy\VarDumper\Presenter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Abstract Enumerator class.
|
||||
*/
|
||||
abstract class Enumerator
|
||||
{
|
||||
// Output styles
|
||||
const IS_PUBLIC = 'public';
|
||||
const IS_PROTECTED = 'protected';
|
||||
const IS_PRIVATE = 'private';
|
||||
const IS_GLOBAL = 'global';
|
||||
const IS_CONSTANT = 'const';
|
||||
const IS_CLASS = 'class';
|
||||
const IS_FUNCTION = 'function';
|
||||
|
||||
private $presenter;
|
||||
|
||||
private $filter = false;
|
||||
private $invertFilter = false;
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* Enumerator constructor.
|
||||
*
|
||||
* @param Presenter $presenter
|
||||
*/
|
||||
public function __construct(Presenter $presenter)
|
||||
{
|
||||
$this->presenter = $presenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of categorized things with the given input options and target.
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param Reflector $reflector
|
||||
* @param mixed $target
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
$this->setFilter($input);
|
||||
|
||||
return $this->listItems($input, $reflector, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate specific items with the given input options and target.
|
||||
*
|
||||
* Implementing classes should return an array of arrays:
|
||||
*
|
||||
* [
|
||||
* 'Constants' => [
|
||||
* 'FOO' => [
|
||||
* 'name' => 'FOO',
|
||||
* 'style' => 'public',
|
||||
* 'value' => '123',
|
||||
* ],
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param Reflector $reflector
|
||||
* @param mixed $target
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null);
|
||||
|
||||
protected function presentRef($value)
|
||||
{
|
||||
return $this->presenter->presentRef($value);
|
||||
}
|
||||
|
||||
protected function showItem($name)
|
||||
{
|
||||
return $this->filter === false || (preg_match($this->pattern, $name) xor $this->invertFilter);
|
||||
}
|
||||
|
||||
private function setFilter(InputInterface $input)
|
||||
{
|
||||
if ($pattern = $input->getOption('grep')) {
|
||||
if (substr($pattern, 0, 1) !== '/' || substr($pattern, -1) !== '/' || strlen($pattern) < 3) {
|
||||
$pattern = '/' . preg_quote($pattern, '/') . '/';
|
||||
}
|
||||
|
||||
if ($input->getOption('insensitive')) {
|
||||
$pattern .= 'i';
|
||||
}
|
||||
|
||||
$this->validateRegex($pattern);
|
||||
|
||||
$this->filter = true;
|
||||
$this->pattern = $pattern;
|
||||
$this->invertFilter = $input->getOption('invert');
|
||||
} else {
|
||||
$this->filter = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that $pattern is a valid regular expression.
|
||||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validateRegex($pattern)
|
||||
{
|
||||
set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
|
||||
try {
|
||||
preg_match($pattern, '');
|
||||
} catch (ErrorException $e) {
|
||||
throw new RuntimeException(str_replace('preg_match(): ', 'Invalid regular expression: ', $e->getRawMessage()));
|
||||
}
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
protected function presentSignature($target)
|
||||
{
|
||||
// This might get weird if the signature is actually for a reflector. Hrm.
|
||||
if (!$target instanceof \Reflector) {
|
||||
$target = Mirror::get($target);
|
||||
}
|
||||
|
||||
return SignatureFormatter::format($target);
|
||||
}
|
||||
}
|
@@ -1,112 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Function Enumerator class.
|
||||
*/
|
||||
class FunctionEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list functions when no Reflector is present.
|
||||
//
|
||||
// TODO: make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --functions Foo
|
||||
//
|
||||
// ... for listing functions in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list functions if we are specifically asked
|
||||
if (!$input->getOption('functions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->getOption('user')) {
|
||||
$label = 'User Functions';
|
||||
$functions = $this->getFunctions('user');
|
||||
} elseif ($input->getOption('internal')) {
|
||||
$label = 'Internal Functions';
|
||||
$functions = $this->getFunctions('internal');
|
||||
} else {
|
||||
$label = 'Functions';
|
||||
$functions = $this->getFunctions();
|
||||
}
|
||||
|
||||
$functions = $this->prepareFunctions($functions);
|
||||
|
||||
if (empty($functions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
$ret[$label] = $functions;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined functions.
|
||||
*
|
||||
* Optionally limit functions to "user" or "internal" functions.
|
||||
*
|
||||
* @param null|string $type "user" or "internal" (default: both)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFunctions($type = null)
|
||||
{
|
||||
$funcs = get_defined_functions();
|
||||
|
||||
if ($type) {
|
||||
return $funcs[$type];
|
||||
} else {
|
||||
return array_merge($funcs['internal'], $funcs['user']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted function array.
|
||||
*
|
||||
* @param array $functions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareFunctions(array $functions)
|
||||
{
|
||||
natcasesort($functions);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($functions as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_FUNCTION,
|
||||
'value' => $this->presentSignature($name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,92 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Global Variable Enumerator class.
|
||||
*/
|
||||
class GlobalVariableEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list globals when no Reflector is present.
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list globals if we are specifically asked
|
||||
if (!$input->getOption('globals')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$globals = $this->prepareGlobals($this->getGlobals());
|
||||
|
||||
if (empty($globals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'Global Variables' => $globals,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined global variables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getGlobals()
|
||||
{
|
||||
global $GLOBALS;
|
||||
|
||||
$names = array_keys($GLOBALS);
|
||||
natcasesort($names);
|
||||
|
||||
$ret = array();
|
||||
foreach ($names as $name) {
|
||||
$ret[$name] = $GLOBALS[$name];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted global variable array.
|
||||
*
|
||||
* @param array $globals
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareGlobals($globals)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($globals as $name => $value) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$ret[$fname] = array(
|
||||
'name' => $fname,
|
||||
'style' => self::IS_GLOBAL,
|
||||
'value' => $this->presentRef($value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Interface Enumerator class.
|
||||
*/
|
||||
class InterfaceEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list interfaces when no Reflector is present.
|
||||
//
|
||||
// TODO: make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --interfaces Foo
|
||||
//
|
||||
// ... for listing interfaces in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list interfaces if we are specifically asked
|
||||
if (!$input->getOption('interfaces')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$interfaces = $this->prepareInterfaces(get_declared_interfaces());
|
||||
|
||||
if (empty($interfaces)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'Interfaces' => $interfaces,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted interface array.
|
||||
*
|
||||
* @param array $interfaces
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareInterfaces(array $interfaces)
|
||||
{
|
||||
natcasesort($interfaces);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($interfaces as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_CLASS,
|
||||
'value' => $this->presentSignature($name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,138 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Method Enumerator class.
|
||||
*/
|
||||
class MethodEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list methods when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can only list methods on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list methods if we are specifically asked
|
||||
if (!$input->getOption('methods')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$methods = $this->prepareMethods($this->getMethods($showAll, $reflector));
|
||||
|
||||
if (empty($methods)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
$ret[$this->getKindLabel($reflector)] = $methods;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined methods for the given class or object Reflector.
|
||||
*
|
||||
* @param bool $showAll Include private and protected methods.
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getMethods($showAll, \Reflector $reflector)
|
||||
{
|
||||
$methods = array();
|
||||
foreach ($reflector->getMethods() as $name => $method) {
|
||||
if ($showAll || $method->isPublic()) {
|
||||
$methods[$method->getName()] = $method;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be natcasesort
|
||||
ksort($methods);
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted method array.
|
||||
*
|
||||
* @param array $methods
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareMethods(array $methods)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($methods as $name => $method) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => $this->getVisibilityStyle($method),
|
||||
'value' => $this->presentSignature($method),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a label for the particular kind of "class" represented.
|
||||
*
|
||||
* @param \ReflectionClass $reflector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Methods';
|
||||
} elseif (method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
return 'Trait Methods';
|
||||
} else {
|
||||
return 'Class Methods';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output style for the given method's visibility.
|
||||
*
|
||||
* @param \ReflectionMethod $method
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVisibilityStyle(\ReflectionMethod $method)
|
||||
{
|
||||
if ($method->isPublic()) {
|
||||
return self::IS_PUBLIC;
|
||||
} elseif ($method->isProtected()) {
|
||||
return self::IS_PROTECTED;
|
||||
} else {
|
||||
return self::IS_PRIVATE;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,161 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Property Enumerator class.
|
||||
*/
|
||||
class PropertyEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list properties when a Reflector is present.
|
||||
|
||||
if ($reflector === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can only list properties on actual class (or object) reflectors.
|
||||
if (!$reflector instanceof \ReflectionClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list properties if we are specifically asked
|
||||
if (!$input->getOption('properties')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$properties = $this->prepareProperties($this->getProperties($showAll, $reflector), $target);
|
||||
|
||||
if (empty($properties)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
$ret[$this->getKindLabel($reflector)] = $properties;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined properties for the given class or object Reflector.
|
||||
*
|
||||
* @param bool $showAll Include private and protected properties.
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getProperties($showAll, \Reflector $reflector)
|
||||
{
|
||||
$properties = array();
|
||||
foreach ($reflector->getProperties() as $property) {
|
||||
if ($showAll || $property->isPublic()) {
|
||||
$properties[$property->getName()] = $property;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be natcasesort
|
||||
ksort($properties);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted property array.
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareProperties(array $properties, $target = null)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($properties as $name => $property) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$ret[$fname] = array(
|
||||
'name' => $fname,
|
||||
'style' => $this->getVisibilityStyle($property),
|
||||
'value' => $this->presentValue($property, $target),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a label for the particular kind of "class" represented.
|
||||
*
|
||||
* @param \ReflectionClass $reflector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getKindLabel(\ReflectionClass $reflector)
|
||||
{
|
||||
if ($reflector->isInterface()) {
|
||||
return 'Interface Properties';
|
||||
} elseif (method_exists($reflector, 'isTrait') && $reflector->isTrait()) {
|
||||
return 'Trait Properties';
|
||||
} else {
|
||||
return 'Class Properties';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output style for the given property's visibility.
|
||||
*
|
||||
* @param \ReflectionProperty $property
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVisibilityStyle(\ReflectionProperty $property)
|
||||
{
|
||||
if ($property->isPublic()) {
|
||||
return self::IS_PUBLIC;
|
||||
} elseif ($property->isProtected()) {
|
||||
return self::IS_PROTECTED;
|
||||
} else {
|
||||
return self::IS_PRIVATE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the $target's current value for a reflection property.
|
||||
*
|
||||
* @param \ReflectionProperty $property
|
||||
* @param mixed $target
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function presentValue(\ReflectionProperty $property, $target)
|
||||
{
|
||||
if (!is_object($target)) {
|
||||
// TODO: figure out if there's a way to return defaults when target
|
||||
// is a class/interface/trait rather than an object.
|
||||
return '';
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
$value = $property->getValue($target);
|
||||
|
||||
return $this->presentRef($value);
|
||||
}
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Trait Enumerator class.
|
||||
*/
|
||||
class TraitEnumerator extends Enumerator
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// bail early if current PHP doesn't know about traits.
|
||||
if (!function_exists('trait_exists')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list traits when no Reflector is present.
|
||||
//
|
||||
// TODO: make a NamespaceReflector and pass that in for commands like:
|
||||
//
|
||||
// ls --traits Foo
|
||||
//
|
||||
// ... for listing traits in the Foo namespace
|
||||
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list traits if we are specifically asked
|
||||
if (!$input->getOption('traits')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$traits = $this->prepareTraits(get_declared_traits());
|
||||
|
||||
if (empty($traits)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'Traits' => $traits,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted trait array.
|
||||
*
|
||||
* @param array $traits
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareTraits(array $traits)
|
||||
{
|
||||
natcasesort($traits);
|
||||
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
|
||||
foreach ($traits as $name) {
|
||||
if ($this->showItem($name)) {
|
||||
$ret[$name] = array(
|
||||
'name' => $name,
|
||||
'style' => self::IS_CLASS,
|
||||
'value' => $this->presentSignature($name),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
@@ -1,129 +0,0 @@
|
||||
<?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\Command\ListCommand;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\VarDumper\Presenter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
/**
|
||||
* Variable Enumerator class.
|
||||
*/
|
||||
class VariableEnumerator extends Enumerator
|
||||
{
|
||||
private static $specialVars = array('_', '_e');
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* Variable Enumerator constructor.
|
||||
*
|
||||
* Unlike most other enumerators, the Variable Enumerator needs access to
|
||||
* the current scope variables, so we need to pass it a Context instance.
|
||||
*
|
||||
* @param Presenter $presenter
|
||||
* @param Context $context
|
||||
*/
|
||||
public function __construct(Presenter $presenter, Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
parent::__construct($presenter);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null)
|
||||
{
|
||||
// only list variables when no Reflector is present.
|
||||
if ($reflector !== null || $target !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only list variables if we are specifically asked
|
||||
if (!$input->getOption('vars')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$showAll = $input->getOption('all');
|
||||
$variables = $this->prepareVariables($this->getVariables($showAll));
|
||||
|
||||
if (empty($variables)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'Variables' => $variables,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scope variables.
|
||||
*
|
||||
* @param bool $showAll Include special variables (e.g. $_).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getVariables($showAll)
|
||||
{
|
||||
$scopeVars = $this->context->getAll();
|
||||
uksort($scopeVars, function ($a, $b) {
|
||||
if ($a === '_e') {
|
||||
return 1;
|
||||
} elseif ($b === '_e') {
|
||||
return -1;
|
||||
} elseif ($a === '_') {
|
||||
return 1;
|
||||
} elseif ($b === '_') {
|
||||
return -1;
|
||||
} else {
|
||||
// TODO: this should be natcasesort
|
||||
return strcasecmp($a, $b);
|
||||
}
|
||||
});
|
||||
|
||||
$ret = array();
|
||||
foreach ($scopeVars as $name => $val) {
|
||||
if (!$showAll && in_array($name, self::$specialVars)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ret[$name] = $val;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare formatted variable array.
|
||||
*
|
||||
* @param array $variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareVariables(array $variables)
|
||||
{
|
||||
// My kingdom for a generator.
|
||||
$ret = array();
|
||||
foreach ($variables as $name => $val) {
|
||||
if ($this->showItem($name)) {
|
||||
$fname = '$' . $name;
|
||||
$ret[$fname] = array(
|
||||
'name' => $fname,
|
||||
'style' => in_array($name, self::$specialVars) ? self::IS_PRIVATE : self::IS_PUBLIC,
|
||||
'value' => $this->presentRef($val), // TODO: add types to variable signatures
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
159
vendor/psy/psysh/src/Psy/Command/ParseCommand.php
vendored
159
vendor/psy/psysh/src/Psy/Command/ParseCommand.php
vendored
@@ -1,159 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Parser;
|
||||
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 PresenterAware
|
||||
{
|
||||
private $presenter;
|
||||
private $parserFactory;
|
||||
private $parsers;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
$this->parserFactory = new ParserFactory();
|
||||
$this->parsers = array();
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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($definition)
|
||||
->setDescription('Parse PHP code and show the abstract syntax tree.')
|
||||
->setHelp(
|
||||
<<<'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,
|
||||
it pretty-prints the PHP Parser parse tree.
|
||||
|
||||
See https://github.com/nikic/PHP-Parser
|
||||
|
||||
It prolly won't be super useful for most of you, but it's here if you want to play.
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$code = $input->getArgument('code');
|
||||
if (strpos('<?', $code) === false) {
|
||||
$code = '<?php ' . $code;
|
||||
}
|
||||
|
||||
$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(Parser $parser, $code)
|
||||
{
|
||||
try {
|
||||
return $parser->parse($code);
|
||||
} catch (\PhpParser\Error $e) {
|
||||
if (strpos($e->getMessage(), 'unexpected EOF') === false) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// If we got an unexpected EOF, let's try it again with a semicolon.
|
||||
return $parser->parse($code . ';');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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($kind = null)
|
||||
{
|
||||
if (!array_key_exists($kind, $this->parsers)) {
|
||||
$this->parsers[$kind] = $this->parserFactory->createParser($kind);
|
||||
}
|
||||
|
||||
return $this->parsers[$kind];
|
||||
}
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* A dumb little command for printing out the current Psy Shell version.
|
||||
*/
|
||||
class PsyVersionCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('version')
|
||||
->setDefinition(array())
|
||||
->setDescription('Show Psy Shell version.')
|
||||
->setHelp('Show Psy Shell version.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln($this->getApplication()->getVersion());
|
||||
}
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Util\Mirror;
|
||||
|
||||
/**
|
||||
* An abstract command with helpers for inspecting the current context.
|
||||
*/
|
||||
abstract class ReflectingCommand extends Command implements ContextAware
|
||||
{
|
||||
const CLASS_OR_FUNC = '/^[\\\\\w]+$/';
|
||||
const INSTANCE = '/^\$(\w+)$/';
|
||||
const CLASS_MEMBER = '/^([\\\\\w]+)::(\w+)$/';
|
||||
const CLASS_STATIC = '/^([\\\\\w]+)::\$(\w+)$/';
|
||||
const INSTANCE_MEMBER = '/^\$(\w+)(::|->)(\w+)$/';
|
||||
const INSTANCE_STATIC = '/^\$(\w+)::\$(\w+)$/';
|
||||
|
||||
/**
|
||||
* Context instance (for ContextAware interface).
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target for a value.
|
||||
*
|
||||
* @throws \InvalidArgumentException when the value specified can't be resolved.
|
||||
*
|
||||
* @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)
|
||||
*/
|
||||
protected function getTarget($valueName, $classOnly = false)
|
||||
{
|
||||
$valueName = trim($valueName);
|
||||
$matches = array();
|
||||
switch (true) {
|
||||
case preg_match(self::CLASS_OR_FUNC, $valueName, $matches):
|
||||
return array($this->resolveName($matches[0], true), null, 0);
|
||||
|
||||
case preg_match(self::INSTANCE, $valueName, $matches):
|
||||
return array($this->resolveInstance($matches[1]), null, 0);
|
||||
|
||||
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):
|
||||
return array($this->resolveName($matches[1]), $matches[2], Mirror::STATIC_PROPERTY | Mirror::PROPERTY);
|
||||
|
||||
case !$classOnly && preg_match(self::INSTANCE_MEMBER, $valueName, $matches):
|
||||
if ($matches[2] === '->') {
|
||||
$kind = Mirror::METHOD | Mirror::PROPERTY;
|
||||
} else {
|
||||
$kind = Mirror::CONSTANT | Mirror::METHOD;
|
||||
}
|
||||
|
||||
return array($this->resolveInstance($matches[1]), $matches[3], $kind);
|
||||
|
||||
case !$classOnly && preg_match(self::INSTANCE_STATIC, $valueName, $matches):
|
||||
return array($this->resolveInstance($matches[1]), $matches[2], Mirror::STATIC_PROPERTY);
|
||||
|
||||
default:
|
||||
throw new RuntimeException('Unknown target: ' . $valueName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a class or function name (with the current shell namespace).
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $includeFunctions (default: false)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function resolveName($name, $includeFunctions = false)
|
||||
{
|
||||
if (substr($name, 0, 1) === '\\') {
|
||||
return $name;
|
||||
}
|
||||
|
||||
if ($namespace = $this->getApplication()->getNamespace()) {
|
||||
$fullName = $namespace . '\\' . $name;
|
||||
|
||||
if (class_exists($fullName) || interface_exists($fullName) || ($includeFunctions && function_exists($fullName))) {
|
||||
return $fullName;
|
||||
}
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 bool $classOnly True if the name should only refer to a class, function or instance
|
||||
*
|
||||
* @return array (value, Reflector)
|
||||
*/
|
||||
protected function getTargetAndReflector($valueName, $classOnly = false)
|
||||
{
|
||||
list($value, $member, $kind) = $this->getTarget($valueName, $classOnly);
|
||||
|
||||
return array($value, Mirror::get($value, $member, $kind));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a variable instance from the current scope.
|
||||
*
|
||||
* @throws \InvalidArgumentException when the requested variable does not exist in the current scope.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed Variable instance.
|
||||
*/
|
||||
protected function resolveInstance($name)
|
||||
{
|
||||
$value = $this->getScopeVariable($name);
|
||||
if (!is_object($value)) {
|
||||
throw new RuntimeException('Unable to inspect a non-object');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a variable from the current shell scope.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getScopeVariable($name)
|
||||
{
|
||||
return $this->context->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all scope variables from the current shell scope.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getScopeVariables()
|
||||
{
|
||||
return $this->context->getAll();
|
||||
}
|
||||
}
|
76
vendor/psy/psysh/src/Psy/Command/ShowCommand.php
vendored
76
vendor/psy/psysh/src/Psy/Command/ShowCommand.php
vendored
@@ -1,76 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Configuration;
|
||||
use Psy\Exception\RuntimeException;
|
||||
use Psy\Formatter\CodeFormatter;
|
||||
use Psy\Formatter\SignatureFormatter;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Show the code for an object, class, constant, method or property.
|
||||
*/
|
||||
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}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('show')
|
||||
->setDefinition(array(
|
||||
new InputArgument('value', InputArgument::REQUIRED, 'Function, class, instance, constant, method or property to show.'),
|
||||
))
|
||||
->setDescription('Show the code for an object, class, constant, method or property.')
|
||||
->setHelp(
|
||||
<<<HELP
|
||||
Show the code for an object, class, constant, method or property.
|
||||
|
||||
e.g.
|
||||
<return>>>> show \$myObject</return>
|
||||
<return>>>> show Psy\Shell::debug</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
list($value, $reflector) = $this->getTargetAndReflector($input->getArgument('value'));
|
||||
|
||||
try {
|
||||
$output->page(CodeFormatter::format($reflector, $this->colorMode), ShellOutput::OUTPUT_RAW);
|
||||
} catch (RuntimeException $e) {
|
||||
$output->writeln(SignatureFormatter::format($reflector));
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
use Psy\Exception\ThrowUpException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Throw an exception out of the Psy Shell.
|
||||
*/
|
||||
class ThrowUpCommand extends Command implements ContextAware
|
||||
{
|
||||
/**
|
||||
* Context instance (for ContextAware interface).
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('throw-up')
|
||||
->setDefinition(array(
|
||||
new InputArgument('exception', InputArgument::OPTIONAL, 'Exception to throw'),
|
||||
))
|
||||
->setDescription('Throw an exception out of the Psy Shell.')
|
||||
->setHelp(
|
||||
<<<'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>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws InvalidArgumentException if there is no exception to throw.
|
||||
* @throws ThrowUpException because what else do you expect it to do?
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($name = $input->getArgument('exception')) {
|
||||
$orig = $this->context->get(preg_replace('/^\$/', '', $name));
|
||||
} else {
|
||||
$orig = $this->context->getLastException();
|
||||
}
|
||||
|
||||
if (!$orig instanceof \Exception) {
|
||||
throw new \InvalidArgumentException('throw-up can only throw Exceptions');
|
||||
}
|
||||
|
||||
throw new ThrowUpException($orig);
|
||||
}
|
||||
}
|
137
vendor/psy/psysh/src/Psy/Command/TraceCommand.php
vendored
137
vendor/psy/psysh/src/Psy/Command/TraceCommand.php
vendored
@@ -1,137 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Show the current stack trace.
|
||||
*/
|
||||
class TraceCommand extends Command
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('trace')
|
||||
->setDefinition(array(
|
||||
new InputOption('include-psy', 'p', InputOption::VALUE_NONE, 'Include Psy in the call stack.'),
|
||||
new InputOption('num', 'n', InputOption::VALUE_REQUIRED, 'Only include NUM lines.'),
|
||||
))
|
||||
->setDescription('Show the current call stack.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
Show the current call stack.
|
||||
|
||||
Optionally, include PsySH in the call stack by passing the <info>--include-psy</info> option.
|
||||
|
||||
e.g.
|
||||
<return>> trace -n10</return>
|
||||
<return>> trace --include-psy</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a backtrace for an exception.
|
||||
*
|
||||
* Optionally limit the number of rows to include with $count, and exclude
|
||||
* Psy from the trace.
|
||||
*
|
||||
* @param \Exception $e The exception with a backtrace.
|
||||
* @param int $count (default: PHP_INT_MAX)
|
||||
* @param bool $includePsy (default: true)
|
||||
*
|
||||
* @return array Formatted stacktrace lines.
|
||||
*/
|
||||
protected function getBacktrace(\Exception $e, $count = null, $includePsy = true)
|
||||
{
|
||||
if ($cwd = getcwd()) {
|
||||
$cwd = rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
if ($count === null) {
|
||||
$count = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$lines = array();
|
||||
|
||||
$trace = $e->getTrace();
|
||||
array_unshift($trace, array(
|
||||
'function' => '',
|
||||
'file' => $e->getFile() !== null ? $e->getFile() : 'n/a',
|
||||
'line' => $e->getLine() !== null ? $e->getLine() : 'n/a',
|
||||
'args' => array(),
|
||||
));
|
||||
|
||||
if (!$includePsy) {
|
||||
for ($i = count($trace) - 1; $i >= 0; $i--) {
|
||||
$thing = isset($trace[$i]['class']) ? $trace[$i]['class'] : $trace[$i]['function'];
|
||||
if (preg_match('/\\\\?Psy\\\\/', $thing)) {
|
||||
$trace = array_slice($trace, $i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0, $count = min($count, count($trace)); $i < $count; $i++) {
|
||||
$class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
|
||||
$type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
|
||||
$function = $trace[$i]['function'];
|
||||
$file = isset($trace[$i]['file']) ? $this->replaceCwd($cwd, $trace[$i]['file']) : 'n/a';
|
||||
$line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
|
||||
|
||||
$lines[] = sprintf(
|
||||
' <class>%s</class>%s%s() at <info>%s:%s</info>',
|
||||
OutputFormatter::escape($class),
|
||||
OutputFormatter::escape($type),
|
||||
OutputFormatter::escape($function),
|
||||
OutputFormatter::escape($file),
|
||||
OutputFormatter::escape($line)
|
||||
);
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the given directory from the start of a filepath.
|
||||
*
|
||||
* @param string $cwd
|
||||
* @param string $file
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replaceCwd($cwd, $file)
|
||||
{
|
||||
if ($cwd === false) {
|
||||
return $file;
|
||||
} else {
|
||||
return preg_replace('/^' . preg_quote($cwd, '/') . '/', '', $file);
|
||||
}
|
||||
}
|
||||
}
|
123
vendor/psy/psysh/src/Psy/Command/WhereamiCommand.php
vendored
123
vendor/psy/psysh/src/Psy/Command/WhereamiCommand.php
vendored
@@ -1,123 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
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;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Show the context of where you opened the debugger.
|
||||
*/
|
||||
class WhereamiCommand extends Command
|
||||
{
|
||||
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 {
|
||||
$this->backtrace = debug_backtrace();
|
||||
}
|
||||
|
||||
return parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('whereami')
|
||||
->setDefinition(array(
|
||||
new InputOption('num', 'n', InputOption::VALUE_OPTIONAL, 'Number of lines before and after.', '5'),
|
||||
))
|
||||
->setDescription('Show where you are in the code.')
|
||||
->setHelp(
|
||||
<<<'HELP'
|
||||
Show where you are in the code.
|
||||
|
||||
Optionally, include how many lines before and after you want to display.
|
||||
|
||||
e.g.
|
||||
<return>> whereami </return>
|
||||
<return>> whereami -n10</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the correct trace in the full backtrace.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function trace()
|
||||
{
|
||||
foreach ($this->backtrace as $i => $backtrace) {
|
||||
if (!isset($backtrace['class'], $backtrace['function'])) {
|
||||
continue;
|
||||
}
|
||||
$correctClass = $backtrace['class'] === 'Psy\Shell';
|
||||
$correctFunction = $backtrace['function'] === 'debug';
|
||||
if ($correctClass && $correctFunction) {
|
||||
return $backtrace;
|
||||
}
|
||||
}
|
||||
|
||||
return end($this->backtrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the file and line based on the specific backtrace.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function fileInfo()
|
||||
{
|
||||
$backtrace = $this->trace();
|
||||
if (preg_match('/eval\(/', $backtrace['file'])) {
|
||||
preg_match_all('/([^\(]+)\((\d+)/', $backtrace['file'], $matches);
|
||||
$file = $matches[1][0];
|
||||
$line = (int) $matches[2][0];
|
||||
} else {
|
||||
$file = $backtrace['file'];
|
||||
$line = $backtrace['line'];
|
||||
}
|
||||
|
||||
return compact('file', 'line');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$info = $this->fileInfo();
|
||||
$num = $input->getOption('num');
|
||||
$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);
|
||||
}
|
||||
}
|
111
vendor/psy/psysh/src/Psy/Command/WtfCommand.php
vendored
111
vendor/psy/psysh/src/Psy/Command/WtfCommand.php
vendored
@@ -1,111 +0,0 @@
|
||||
<?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\Command;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
use Psy\Output\ShellOutput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Show the last uncaught exception.
|
||||
*/
|
||||
class WtfCommand extends TraceCommand implements ContextAware
|
||||
{
|
||||
/**
|
||||
* Context instance (for ContextAware interface).
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('wtf')
|
||||
->setAliases(array('last-exception', 'wtf?'))
|
||||
->setDefinition(array(
|
||||
new InputArgument('incredulity', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Number of lines to show'),
|
||||
new InputOption('verbose', 'v', InputOption::VALUE_NONE, 'Show entire backtrace.'),
|
||||
))
|
||||
->setDescription('Show the backtrace of the most recent exception.')
|
||||
->setHelp(
|
||||
<<<'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:
|
||||
|
||||
e.g.
|
||||
<return>>>> wtf ?</return>
|
||||
<return>>>> wtf ?!???!?!?</return>
|
||||
|
||||
To see the entire backtrace, pass the -v/--verbose flag:
|
||||
|
||||
e.g.
|
||||
<return>>>> wtf -v</return>
|
||||
HELP
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* --verbose is not hidden for this option :)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getHiddenOptions()
|
||||
{
|
||||
$options = parent::getHiddenOptions();
|
||||
unset($options[array_search('verbose', $options)]);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$incredulity = implode('', $input->getArgument('incredulity'));
|
||||
if (strlen(preg_replace('/[\\?!]/', '', $incredulity))) {
|
||||
throw new \InvalidArgumentException('Incredulity must include only "?" and "!".');
|
||||
}
|
||||
|
||||
$exception = $this->context->getLastException();
|
||||
$count = $input->getOption('verbose') ? PHP_INT_MAX : pow(2, max(0, (strlen($incredulity) - 1)));
|
||||
$trace = $this->getBacktrace($exception, $count);
|
||||
|
||||
$shell = $this->getApplication();
|
||||
$output->page(function ($output) use ($exception, $trace, $shell) {
|
||||
$shell->renderException($exception, $output);
|
||||
$output->writeln('--');
|
||||
$output->write($trace, true, ShellOutput::NUMBER_LINES);
|
||||
});
|
||||
}
|
||||
}
|
157
vendor/psy/psysh/src/Psy/Compiler.php
vendored
157
vendor/psy/psysh/src/Psy/Compiler.php
vendored
@@ -1,157 +0,0 @@
|
||||
<?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 Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* A Psy Shell Phar compiler.
|
||||
*/
|
||||
class Compiler
|
||||
{
|
||||
/**
|
||||
* Compiles psysh into a single phar file.
|
||||
*
|
||||
* @param string $pharFile The full path to the file to create
|
||||
*/
|
||||
public function compile($pharFile = 'psysh.phar')
|
||||
{
|
||||
if (file_exists($pharFile)) {
|
||||
unlink($pharFile);
|
||||
}
|
||||
|
||||
$this->version = Shell::VERSION;
|
||||
|
||||
$phar = new \Phar($pharFile, 0, 'psysh.phar');
|
||||
$phar->setSignatureAlgorithm(\Phar::SHA1);
|
||||
|
||||
$phar->startBuffering();
|
||||
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->ignoreVCS(true)
|
||||
->name('*.php')
|
||||
->notName('Compiler.php')
|
||||
->notName('Autoloader.php')
|
||||
->in(__DIR__ . '/..');
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$this->addFile($phar, $file);
|
||||
}
|
||||
|
||||
$finder = Finder::create()
|
||||
->files()
|
||||
->ignoreVCS(true)
|
||||
->name('*.php')
|
||||
->exclude('Tests')
|
||||
->in(__DIR__ . '/../../build-vendor');
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$this->addFile($phar, $file);
|
||||
}
|
||||
|
||||
// Stubs
|
||||
$phar->setStub($this->getStub());
|
||||
|
||||
$phar->stopBuffering();
|
||||
|
||||
unset($phar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file to the psysh Phar.
|
||||
*
|
||||
* @param Phar $phar
|
||||
* @param SplFileInfo $file
|
||||
* @param bool $strip (default: true)
|
||||
*/
|
||||
private function addFile($phar, $file, $strip = true)
|
||||
{
|
||||
$path = str_replace(dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR, '', $file->getRealPath());
|
||||
|
||||
$content = file_get_contents($file);
|
||||
if ($strip) {
|
||||
$content = $this->stripWhitespace($content);
|
||||
} elseif ('LICENSE' === basename($file)) {
|
||||
$content = "\n" . $content . "\n";
|
||||
}
|
||||
|
||||
$phar->addFromString($path, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes whitespace from a PHP source string while preserving line numbers.
|
||||
*
|
||||
* @param string $source A PHP string
|
||||
*
|
||||
* @return string The PHP string with the whitespace removed
|
||||
*/
|
||||
private function stripWhitespace($source)
|
||||
{
|
||||
if (!function_exists('token_get_all')) {
|
||||
return $source;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
foreach (token_get_all($source) as $token) {
|
||||
if (is_string($token)) {
|
||||
$output .= $token;
|
||||
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
|
||||
$output .= str_repeat("\n", substr_count($token[1], "\n"));
|
||||
} elseif (T_WHITESPACE === $token[0]) {
|
||||
// reduce wide spaces
|
||||
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
|
||||
// normalize newlines to \n
|
||||
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
|
||||
// trim leading spaces
|
||||
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
|
||||
$output .= $whitespace;
|
||||
} else {
|
||||
$output .= $token[1];
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* This is basically the psysh bin, with the autoload require statements swapped out.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getStub()
|
||||
{
|
||||
$content = file_get_contents(__DIR__ . '/../../bin/psysh');
|
||||
$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
183
vendor/psy/psysh/src/Psy/ConfigPaths.php
vendored
@@ -1,183 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
1074
vendor/psy/psysh/src/Psy/Configuration.php
vendored
1074
vendor/psy/psysh/src/Psy/Configuration.php
vendored
File diff suppressed because it is too large
Load Diff
79
vendor/psy/psysh/src/Psy/ConsoleColorFactory.php
vendored
79
vendor/psy/psysh/src/Psy/ConsoleColorFactory.php
vendored
@@ -1,79 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
136
vendor/psy/psysh/src/Psy/Context.php
vendored
136
vendor/psy/psysh/src/Psy/Context.php
vendored
@@ -1,136 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* The Shell execution context.
|
||||
*
|
||||
* This class encapsulates the current variables, most recent return value and
|
||||
* exception, and the current namespace.
|
||||
*/
|
||||
class Context
|
||||
{
|
||||
private static $specialVars = array('_', '_e', '__psysh__');
|
||||
private $scopeVariables = array();
|
||||
private $lastException;
|
||||
private $returnValue;
|
||||
|
||||
/**
|
||||
* Get a context variable.
|
||||
*
|
||||
* @throws InvalidArgumentException If the variable is not found in the current context.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
switch ($name) {
|
||||
case '_':
|
||||
return $this->returnValue;
|
||||
|
||||
case '_e':
|
||||
if (!isset($this->lastException)) {
|
||||
throw new \InvalidArgumentException('Unknown variable: $' . $name);
|
||||
}
|
||||
|
||||
return $this->lastException;
|
||||
|
||||
default:
|
||||
if (!array_key_exists($name, $this->scopeVariables)) {
|
||||
throw new \InvalidArgumentException('Unknown variable: $' . $name);
|
||||
}
|
||||
|
||||
return $this->scopeVariables[$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all defined variables.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
$vars = $this->scopeVariables;
|
||||
$vars['_'] = $this->returnValue;
|
||||
|
||||
if (isset($this->lastException)) {
|
||||
$vars['_e'] = $this->lastException;
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all scope variables.
|
||||
*
|
||||
* This method does *not* set the magic $_ and $_e variables.
|
||||
*
|
||||
* @param array $vars
|
||||
*/
|
||||
public function setAll(array $vars)
|
||||
{
|
||||
foreach (self::$specialVars as $key) {
|
||||
unset($vars[$key]);
|
||||
}
|
||||
|
||||
$this->scopeVariables = $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the most recent return value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setReturnValue($value)
|
||||
{
|
||||
$this->returnValue = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent return value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReturnValue()
|
||||
{
|
||||
return $this->returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the most recent Exception.
|
||||
*
|
||||
* @param \Exception $e
|
||||
*/
|
||||
public function setLastException(\Exception $e)
|
||||
{
|
||||
$this->lastException = $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the most recent Exception.
|
||||
*
|
||||
* @throws InvalidArgumentException If no Exception has been caught.
|
||||
*
|
||||
* @return null|Exception
|
||||
*/
|
||||
public function getLastException()
|
||||
{
|
||||
if (!isset($this->lastException)) {
|
||||
throw new \InvalidArgumentException('No most-recent exception');
|
||||
}
|
||||
|
||||
return $this->lastException;
|
||||
}
|
||||
}
|
28
vendor/psy/psysh/src/Psy/ContextAware.php
vendored
28
vendor/psy/psysh/src/Psy/ContextAware.php
vendored
@@ -1,28 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
*
|
||||
* This interface is used to pass the Shell's context into commands and such
|
||||
* which require access to the current scope variables.
|
||||
*/
|
||||
interface ContextAware
|
||||
{
|
||||
/**
|
||||
* Set the Context reference.
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context);
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
<?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 break exception, used for halting the Psy Shell.
|
||||
*/
|
||||
class BreakException extends \Exception implements Exception
|
||||
{
|
||||
private $rawMessage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, \Exception $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
parent::__construct(sprintf('Exit: %s', $message), $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a raw (unformatted) version of the error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?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.
|
||||
}
|
@@ -1,88 +0,0 @@
|
||||
<?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 custom error Exception for Psy with a formatted $message.
|
||||
*/
|
||||
class ErrorException extends \ErrorException implements Exception
|
||||
{
|
||||
private $rawMessage;
|
||||
|
||||
/**
|
||||
* Construct a Psy ErrorException.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 1)
|
||||
* @param string $filename (default: null)
|
||||
* @param int $lineno (default: null)
|
||||
* @param Exception $previous (default: 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 = '';
|
||||
}
|
||||
|
||||
switch ($severity) {
|
||||
case E_WARNING:
|
||||
case E_CORE_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_USER_WARNING:
|
||||
$type = 'warning';
|
||||
break;
|
||||
|
||||
case E_STRICT:
|
||||
$type = 'Strict error';
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = 'error';
|
||||
break;
|
||||
}
|
||||
|
||||
$message = sprintf('PHP %s: %s%s on line %d', $type, $message, $filename ? ' in ' . $filename : '', $lineno);
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw (unformatted) message for this error.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for throwing an ErrorException.
|
||||
*
|
||||
* This allows us to:
|
||||
*
|
||||
* set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
|
||||
*
|
||||
* @throws ErrorException
|
||||
*
|
||||
* @param int $errno Error type
|
||||
* @param string $errstr Message
|
||||
* @param string $errfile Filename
|
||||
* @param int $errline Line number
|
||||
*/
|
||||
public static function throwException($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
throw new self($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
}
|
27
vendor/psy/psysh/src/Psy/Exception/Exception.php
vendored
27
vendor/psy/psysh/src/Psy/Exception/Exception.php
vendored
@@ -1,27 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* An interface for Psy Exceptions.
|
||||
*/
|
||||
interface Exception
|
||||
{
|
||||
/**
|
||||
* This is the only thing, really...
|
||||
*
|
||||
* Return a raw (unformatted) version of the message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage();
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
<?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 "fatal error" Exception for Psy.
|
||||
*/
|
||||
class FatalErrorException extends \ErrorException implements Exception
|
||||
{
|
||||
private $rawMessage;
|
||||
|
||||
/**
|
||||
* Create a fatal error.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param int $severity (default: 9000)
|
||||
* @param string $filename (default: null)
|
||||
* @param int $lineno (default: null)
|
||||
* @param \Exception $previous (default: 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);
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a raw (unformatted) version of the error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
<?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 "parse error" Exception for Psy.
|
||||
*/
|
||||
class ParseErrorException extends \PhpParser\Error implements Exception
|
||||
{
|
||||
/**
|
||||
* Constructor!
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $line (default: -1)
|
||||
*/
|
||||
public function __construct($message = '', $line = -1)
|
||||
{
|
||||
$message = sprintf('PHP Parse error: %s', $message);
|
||||
parent::__construct($message, $line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ParseErrorException from a PhpParser Error.
|
||||
*
|
||||
* @param \PhpParser\Error $e
|
||||
*
|
||||
* @return ParseErrorException
|
||||
*/
|
||||
public static function fromParseError(\PhpParser\Error $e)
|
||||
{
|
||||
return new self($e->getRawMessage(), $e->getRawLine());
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
<?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 RuntimeException for Psy.
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements Exception
|
||||
{
|
||||
private $rawMessage;
|
||||
|
||||
/**
|
||||
* Make this bad boy.
|
||||
*
|
||||
* @param string $message (default: "")
|
||||
* @param int $code (default: 0)
|
||||
* @param \Exception $previous (default: null)
|
||||
*/
|
||||
public function __construct($message = '', $code = 0, \Exception $previous = null)
|
||||
{
|
||||
$this->rawMessage = $message;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a raw (unformatted) version of the error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->rawMessage;
|
||||
}
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
<?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 throw-up exception, used for throwing an exception out of the Psy Shell.
|
||||
*/
|
||||
class ThrowUpException extends \Exception implements Exception
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(\Exception $exception)
|
||||
{
|
||||
$message = sprintf("Throwing %s with message '%s'", get_class($exception), $exception->getMessage());
|
||||
parent::__construct($message, $exception->getCode(), $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a raw (unformatted) version of the error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage()
|
||||
{
|
||||
return $this->getPrevious()->getMessage();
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
@@ -1,174 +0,0 @@
|
||||
<?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\ExecutionLoop;
|
||||
|
||||
use Psy\Shell;
|
||||
|
||||
/**
|
||||
* A forking version of the Psy Shell execution loop.
|
||||
*
|
||||
* This version is preferred, as it won't die prematurely if user input includes
|
||||
* a fatal error, such as redeclaring a class or function.
|
||||
*/
|
||||
class ForkingLoop extends Loop
|
||||
{
|
||||
private $savegame;
|
||||
|
||||
/**
|
||||
* Run the execution loop.
|
||||
*
|
||||
* Forks into a master and a loop process. The loop process will handle the
|
||||
* evaluation of all instructions, then return its state via a socket upon
|
||||
* completion.
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
public function run(Shell $shell)
|
||||
{
|
||||
list($up, $down) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
|
||||
|
||||
if (!$up) {
|
||||
throw new \RuntimeException('Unable to create socket pair.');
|
||||
}
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
throw new \RuntimeException('Unable to start execution loop.');
|
||||
} elseif ($pid > 0) {
|
||||
// This is the main thread. We'll just wait for a while.
|
||||
|
||||
// We won't be needing this one.
|
||||
fclose($up);
|
||||
|
||||
// Wait for a return value from the loop process.
|
||||
$read = array($down);
|
||||
$write = null;
|
||||
$except = null;
|
||||
if (stream_select($read, $write, $except, null) === false) {
|
||||
throw new \RuntimeException('Error waiting for execution loop.');
|
||||
}
|
||||
|
||||
$content = stream_get_contents($down);
|
||||
fclose($down);
|
||||
|
||||
if ($content) {
|
||||
$shell->setScopeVariables(@unserialize($content));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the child process. It's going to do all the work.
|
||||
if (function_exists('setproctitle')) {
|
||||
setproctitle('psysh (loop)');
|
||||
}
|
||||
|
||||
// We won't be needing this one.
|
||||
fclose($down);
|
||||
|
||||
// Let's do some processing.
|
||||
parent::run($shell);
|
||||
|
||||
// Send the scope variables back up to the main thread
|
||||
fwrite($up, $this->serializeReturn($shell->getScopeVariables()));
|
||||
fclose($up);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a savegame at the start of each loop iteration.
|
||||
*/
|
||||
public function beforeLoop()
|
||||
{
|
||||
$this->createSavegame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old savegames at the end of each loop iteration.
|
||||
*/
|
||||
public function afterLoop()
|
||||
{
|
||||
// if there's an old savegame hanging around, let's kill it.
|
||||
if (isset($this->savegame)) {
|
||||
posix_kill($this->savegame, SIGKILL);
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a savegame fork.
|
||||
*
|
||||
* The savegame contains the current execution state, and can be resumed in
|
||||
* the event that the worker dies unexpectedly (for example, by encountering
|
||||
* a PHP fatal error).
|
||||
*/
|
||||
private function createSavegame()
|
||||
{
|
||||
// the current process will become the savegame
|
||||
$this->savegame = posix_getpid();
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
throw new \RuntimeException('Unable to create savegame fork.');
|
||||
} elseif ($pid > 0) {
|
||||
// we're the savegame now... let's wait and see what happens
|
||||
pcntl_waitpid($pid, $status);
|
||||
|
||||
// worker exited cleanly, let's bail
|
||||
if (!pcntl_wexitstatus($status)) {
|
||||
posix_kill(posix_getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
// worker didn't exit cleanly, we'll need to have another go
|
||||
$this->createSavegame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize all serializable return values.
|
||||
*
|
||||
* A naïve serialization will run into issues if there is a Closure or
|
||||
* SimpleXMLElement (among other things) in scope when exiting the execution
|
||||
* loop. We'll just ignore these unserializable classes, and serialize what
|
||||
* we can.
|
||||
*
|
||||
* @param array $return
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
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);
|
||||
$serializable[$key] = $value;
|
||||
} catch (\Exception $e) {
|
||||
// we'll just ignore this one...
|
||||
}
|
||||
}
|
||||
|
||||
return @serialize($serializable);
|
||||
}
|
||||
}
|
175
vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php
vendored
175
vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php
vendored
@@ -1,175 +0,0 @@
|
||||
<?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\ExecutionLoop;
|
||||
|
||||
use Psy\Configuration;
|
||||
use Psy\Exception\BreakException;
|
||||
use Psy\Exception\ThrowUpException;
|
||||
use Psy\Exception\TypeErrorException;
|
||||
use Psy\Shell;
|
||||
|
||||
/**
|
||||
* The Psy Shell execution loop.
|
||||
*/
|
||||
class Loop
|
||||
{
|
||||
const NOOP_INPUT = 'return null;';
|
||||
|
||||
/**
|
||||
* Loop constructor.
|
||||
*
|
||||
* The non-forking loop doesn't have much use for Configuration, so we'll
|
||||
* just ignore it.
|
||||
*
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function __construct(Configuration $config)
|
||||
{
|
||||
// don't need this
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the execution loop.
|
||||
*
|
||||
* @throws ThrowUpException if thrown by the `throw-up` command.
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
public function run(Shell $shell)
|
||||
{
|
||||
$loop = function ($__psysh__) {
|
||||
// Load user-defined includes
|
||||
set_error_handler(array($__psysh__, 'handleError'));
|
||||
try {
|
||||
foreach ($__psysh__->getIncludes() as $__psysh_include__) {
|
||||
include $__psysh_include__;
|
||||
}
|
||||
} catch (\Exception $_e) {
|
||||
$__psysh__->writeException($_e);
|
||||
}
|
||||
restore_error_handler();
|
||||
unset($__psysh_include__);
|
||||
|
||||
extract($__psysh__->getScopeVariables());
|
||||
|
||||
do {
|
||||
$__psysh__->beforeLoop();
|
||||
$__psysh__->setScopeVariables(get_defined_vars());
|
||||
|
||||
try {
|
||||
// read a line, see if we should eval
|
||||
$__psysh__->getInput();
|
||||
|
||||
// evaluate the current code buffer
|
||||
ob_start(
|
||||
array($__psysh__, 'writeStdout'),
|
||||
version_compare(PHP_VERSION, '5.4', '>=') ? 1 : 2
|
||||
);
|
||||
|
||||
set_error_handler(array($__psysh__, 'handleError'));
|
||||
$_ = eval($__psysh__->flushCode() ?: Loop::NOOP_INPUT);
|
||||
restore_error_handler();
|
||||
|
||||
ob_end_flush();
|
||||
|
||||
$__psysh__->writeReturnValue($_);
|
||||
} catch (BreakException $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException($_e);
|
||||
|
||||
return;
|
||||
} catch (ThrowUpException $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__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) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException($_e);
|
||||
}
|
||||
|
||||
$__psysh__->afterLoop();
|
||||
} while (true);
|
||||
};
|
||||
|
||||
// bind the closure to $this from the shell scope variables...
|
||||
if (self::bindLoop()) {
|
||||
$that = null;
|
||||
try {
|
||||
$that = $shell->getScopeVariable('this');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// well, it was worth a shot
|
||||
}
|
||||
|
||||
if (is_object($that)) {
|
||||
$loop = $loop->bindTo($that, get_class($that));
|
||||
} else {
|
||||
$loop = $loop->bindTo(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
$loop($shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* A beforeLoop callback.
|
||||
*
|
||||
* This is executed at the start of each loop iteration. In the default
|
||||
* (non-forking) loop implementation, this is a no-op.
|
||||
*/
|
||||
public function beforeLoop()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* A afterLoop callback.
|
||||
*
|
||||
* This is executed at the end of each loop iteration. In the default
|
||||
* (non-forking) loop implementation, this is a no-op.
|
||||
*/
|
||||
public function afterLoop()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether to bind the execution loop.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function bindLoop()
|
||||
{
|
||||
// skip binding on HHVM <= 3.5.0
|
||||
// see https://github.com/facebook/hhvm/issues/1203
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return version_compare(HHVM_VERSION, '3.5.0', '>=');
|
||||
}
|
||||
|
||||
return version_compare(PHP_VERSION, '5.4', '>=');
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
|
||||
use Psy\Configuration;
|
||||
use Psy\ConsoleColorFactory;
|
||||
use Psy\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* A pretty-printer for code.
|
||||
*/
|
||||
class CodeFormatter implements Formatter
|
||||
{
|
||||
/**
|
||||
* Format the code represented by $reflector.
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
* @param null|string $colorMode (default: null)
|
||||
*
|
||||
* @return string formatted code
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
|
||||
$file = file_get_contents($fileName);
|
||||
$start = $reflector->getStartLine();
|
||||
$end = $reflector->getEndLine() - $start;
|
||||
|
||||
$factory = new ConsoleColorFactory($colorMode);
|
||||
$colors = $factory->getConsoleColor();
|
||||
$highlighter = new Highlighter($colors);
|
||||
|
||||
return $highlighter->getCodeSnippet($file, $start, 0, $end);
|
||||
|
||||
// no need to escape this bad boy, since (for now) it's being output raw.
|
||||
// return OutputFormatter::escape(implode(PHP_EOL, $code));
|
||||
return implode(PHP_EOL, $code);
|
||||
} else {
|
||||
throw new RuntimeException('Source code unavailable.');
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,168 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
use Psy\Util\Docblock;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* A pretty-printer for docblocks.
|
||||
*/
|
||||
class DocblockFormatter implements Formatter
|
||||
{
|
||||
private static $vectorParamTemplates = array(
|
||||
'type' => 'info',
|
||||
'var' => 'strong',
|
||||
);
|
||||
|
||||
/**
|
||||
* Format a docblock.
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return string Formatted docblock
|
||||
*/
|
||||
public static function format(\Reflector $reflector)
|
||||
{
|
||||
$docblock = new Docblock($reflector);
|
||||
$chunks = array();
|
||||
|
||||
if (!empty($docblock->desc)) {
|
||||
$chunks[] = '<comment>Description:</comment>';
|
||||
$chunks[] = self::indent(OutputFormatter::escape($docblock->desc), ' ');
|
||||
$chunks[] = '';
|
||||
}
|
||||
|
||||
if (!empty($docblock->tags)) {
|
||||
foreach ($docblock::$vectors as $name => $vector) {
|
||||
if (isset($docblock->tags[$name])) {
|
||||
$chunks[] = sprintf('<comment>%s:</comment>', self::inflect($name));
|
||||
$chunks[] = self::formatVector($vector, $docblock->tags[$name]);
|
||||
$chunks[] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$tags = self::formatTags(array_keys($docblock::$vectors), $docblock->tags);
|
||||
if (!empty($tags)) {
|
||||
$chunks[] = $tags;
|
||||
$chunks[] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim(implode("\n", $chunks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a docblock vector, for example, `@throws`, `@param`, or `@return`.
|
||||
*
|
||||
* @see DocBlock::$vectors
|
||||
*
|
||||
* @param array $vector
|
||||
* @param array $lines
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function formatVector(array $vector, array $lines)
|
||||
{
|
||||
$template = array(' ');
|
||||
foreach ($vector as $type) {
|
||||
$max = 0;
|
||||
foreach ($lines as $line) {
|
||||
$chunk = $line[$type];
|
||||
$cur = empty($chunk) ? 0 : strlen($chunk) + 1;
|
||||
if ($cur > $max) {
|
||||
$max = $cur;
|
||||
}
|
||||
}
|
||||
|
||||
$template[] = self::getVectorParamTemplate($type, $max);
|
||||
}
|
||||
$template = implode(' ', $template);
|
||||
|
||||
return implode("\n", array_map(function ($line) use ($template) {
|
||||
$escaped = array_map(array('Symfony\Component\Console\Formatter\OutputFormatter', 'escape'), $line);
|
||||
|
||||
return rtrim(vsprintf($template, $escaped));
|
||||
}, $lines));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format docblock tags.
|
||||
*
|
||||
* @param array $skip Tags to exclude
|
||||
* @param array $tags Tags to format
|
||||
*
|
||||
* @return string formatted tags
|
||||
*/
|
||||
private static function formatTags(array $skip, array $tags)
|
||||
{
|
||||
$chunks = array();
|
||||
|
||||
foreach ($tags as $name => $values) {
|
||||
if (in_array($name, $skip)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($values as $value) {
|
||||
$chunks[] = sprintf('<comment>%s%s</comment> %s', self::inflect($name), empty($value) ? '' : ':', OutputFormatter::escape($value));
|
||||
}
|
||||
|
||||
$chunks[] = '';
|
||||
}
|
||||
|
||||
return implode("\n", $chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a docblock vector template.
|
||||
*
|
||||
* @param string $type Vector type
|
||||
* @param int $max Pad width
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getVectorParamTemplate($type, $max)
|
||||
{
|
||||
if (!isset(self::$vectorParamTemplates[$type])) {
|
||||
return sprintf('%%-%ds', $max);
|
||||
}
|
||||
|
||||
return sprintf('<%s>%%-%ds</%s>', self::$vectorParamTemplates[$type], $max, self::$vectorParamTemplates[$type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent a string.
|
||||
*
|
||||
* @param string $text String to indent
|
||||
* @param string $indent (default: ' ')
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function indent($text, $indent = ' ')
|
||||
{
|
||||
return $indent . str_replace("\n", "\n" . $indent, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert underscored or whitespace separated words into sentence case.
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function inflect($text)
|
||||
{
|
||||
$words = trim(preg_replace('/[\s_-]+/', ' ', preg_replace('/([a-z])([A-Z])/', '$1 $2', $text)));
|
||||
|
||||
return implode(' ', array_map('ucfirst', explode(' ', $words)));
|
||||
}
|
||||
}
|
25
vendor/psy/psysh/src/Psy/Formatter/Formatter.php
vendored
25
vendor/psy/psysh/src/Psy/Formatter/Formatter.php
vendored
@@ -1,25 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
/**
|
||||
* Formatter interface.
|
||||
*/
|
||||
interface Formatter
|
||||
{
|
||||
/**
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function format(\Reflector $reflector);
|
||||
}
|
@@ -1,271 +0,0 @@
|
||||
<?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\Formatter;
|
||||
|
||||
use Psy\Reflection\ReflectionConstant;
|
||||
use Psy\Util\Json;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* An abstract representation of a function, class or property signature.
|
||||
*/
|
||||
class SignatureFormatter implements Formatter
|
||||
{
|
||||
/**
|
||||
* Format a signature for the given reflector.
|
||||
*
|
||||
* Defers to subclasses to do the actual formatting.
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
public static function format(\Reflector $reflector)
|
||||
{
|
||||
switch (true) {
|
||||
case $reflector instanceof \ReflectionFunction:
|
||||
return self::formatFunction($reflector);
|
||||
|
||||
// this case also covers \ReflectionObject:
|
||||
case $reflector instanceof \ReflectionClass:
|
||||
return self::formatClass($reflector);
|
||||
|
||||
case $reflector instanceof ReflectionConstant:
|
||||
return self::formatConstant($reflector);
|
||||
|
||||
case $reflector instanceof \ReflectionMethod:
|
||||
return self::formatMethod($reflector);
|
||||
|
||||
case $reflector instanceof \ReflectionProperty:
|
||||
return self::formatProperty($reflector);
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException('Unexpected Reflector class: ' . get_class($reflector));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the signature name.
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return string Formatted name.
|
||||
*/
|
||||
public static function formatName(\Reflector $reflector)
|
||||
{
|
||||
return $reflector->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the method, property or class modifiers.
|
||||
*
|
||||
* Technically this should be a trait. Can't wait for 5.4 :)
|
||||
*
|
||||
* @param \Reflector $reflector
|
||||
*
|
||||
* @return string Formatted modifiers.
|
||||
*/
|
||||
private static function formatModifiers(\Reflector $reflector)
|
||||
{
|
||||
return implode(' ', array_map(function ($modifier) {
|
||||
return sprintf('<keyword>%s</keyword>', $modifier);
|
||||
}, \Reflection::getModifierNames($reflector->getModifiers())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a class signature.
|
||||
*
|
||||
* @param \ReflectionClass $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
private static function formatClass(\ReflectionClass $reflector)
|
||||
{
|
||||
$chunks = array();
|
||||
|
||||
if ($modifiers = self::formatModifiers($reflector)) {
|
||||
$chunks[] = $modifiers;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4', '>=') && $reflector->isTrait()) {
|
||||
$chunks[] = 'trait';
|
||||
} else {
|
||||
$chunks[] = $reflector->isInterface() ? 'interface' : 'class';
|
||||
}
|
||||
|
||||
$chunks[] = sprintf('<class>%s</class>', self::formatName($reflector));
|
||||
|
||||
if ($parent = $reflector->getParentClass()) {
|
||||
$chunks[] = 'extends';
|
||||
$chunks[] = sprintf('<class>%s</class>', $parent->getName());
|
||||
}
|
||||
|
||||
$interfaces = $reflector->getInterfaceNames();
|
||||
if (!empty($interfaces)) {
|
||||
sort($interfaces);
|
||||
|
||||
$chunks[] = 'implements';
|
||||
$chunks[] = implode(', ', array_map(function ($name) {
|
||||
return sprintf('<class>%s</class>', $name);
|
||||
}, $interfaces));
|
||||
}
|
||||
|
||||
return implode(' ', $chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a constant signature.
|
||||
*
|
||||
* @param ReflectionConstant $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
private static function formatConstant(ReflectionConstant $reflector)
|
||||
{
|
||||
$value = $reflector->getValue();
|
||||
$style = self::getTypeStyle($value);
|
||||
|
||||
return sprintf(
|
||||
'<keyword>const</keyword> <const>%s</const> = <%s>%s</%s>',
|
||||
self::formatName($reflector),
|
||||
$style,
|
||||
OutputFormatter::escape(Json::encode($value)),
|
||||
$style
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for getting output style for a given value's type.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static 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';
|
||||
} else {
|
||||
return 'strong';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a property signature.
|
||||
*
|
||||
* @param \ReflectionProperty $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
private static function formatProperty(\ReflectionProperty $reflector)
|
||||
{
|
||||
return sprintf(
|
||||
'%s <strong>$%s</strong>',
|
||||
self::formatModifiers($reflector),
|
||||
$reflector->getName()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a function signature.
|
||||
*
|
||||
* @param \ReflectionFunction $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
private static function formatFunction(\ReflectionFunctionAbstract $reflector)
|
||||
{
|
||||
return sprintf(
|
||||
'<keyword>function</keyword> %s<function>%s</function>(%s)',
|
||||
$reflector->returnsReference() ? '&' : '',
|
||||
self::formatName($reflector),
|
||||
implode(', ', self::formatFunctionParams($reflector))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a method signature.
|
||||
*
|
||||
* @param \ReflectionMethod $reflector
|
||||
*
|
||||
* @return string Formatted signature.
|
||||
*/
|
||||
private static function formatMethod(\ReflectionMethod $reflector)
|
||||
{
|
||||
return sprintf(
|
||||
'%s %s',
|
||||
self::formatModifiers($reflector),
|
||||
self::formatFunction($reflector)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the function params.
|
||||
*
|
||||
* @param \ReflectionFunctionAbstract $reflector
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function formatFunctionParams(\ReflectionFunctionAbstract $reflector)
|
||||
{
|
||||
$params = array();
|
||||
foreach ($reflector->getParameters() as $param) {
|
||||
$hint = '';
|
||||
try {
|
||||
if ($param->isArray()) {
|
||||
$hint = '<keyword>array</keyword> ';
|
||||
} elseif ($class = $param->getClass()) {
|
||||
$hint = sprintf('<class>%s</class> ', $class->getName());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// sometimes we just don't know...
|
||||
// bad class names, or autoloaded classes that haven't been loaded yet, or whathaveyou.
|
||||
// come to think of it, the only time I've seen this is with the intl extension.
|
||||
|
||||
// Hax: we'll try to extract it :P
|
||||
$chunks = explode('$' . $param->getName(), (string) $param);
|
||||
$chunks = explode(' ', trim($chunks[0]));
|
||||
$guess = end($chunks);
|
||||
|
||||
$hint = sprintf('<urgent>%s</urgent> ', $guess);
|
||||
}
|
||||
|
||||
if ($param->isOptional()) {
|
||||
if (!$param->isDefaultValueAvailable()) {
|
||||
$value = 'unknown';
|
||||
$typeStyle = 'urgent';
|
||||
} else {
|
||||
$value = $param->getDefaultValue();
|
||||
$typeStyle = self::getTypeStyle($value);
|
||||
$value = is_array($value) ? 'array()' : is_null($value) ? 'null' : var_export($value, true);
|
||||
}
|
||||
$default = sprintf(' = <%s>%s</%s>', $typeStyle, OutputFormatter::escape($value), $typeStyle);
|
||||
} else {
|
||||
$default = '';
|
||||
}
|
||||
|
||||
$params[] = sprintf(
|
||||
'%s%s<strong>$%s</strong>%s',
|
||||
$param->isPassedByReference() ? '&' : '',
|
||||
$hint,
|
||||
$param->getName(),
|
||||
$default
|
||||
);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
26
vendor/psy/psysh/src/Psy/Output/OutputPager.php
vendored
26
vendor/psy/psysh/src/Psy/Output/OutputPager.php
vendored
@@ -1,26 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* An output pager is much the same as a regular OutputInterface, but allows
|
||||
* the stream to be flushed to a pager periodically.
|
||||
*/
|
||||
interface OutputPager extends OutputInterface
|
||||
{
|
||||
/**
|
||||
* Close the current pager process.
|
||||
*/
|
||||
public function close();
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
/**
|
||||
* A passthrough pager is a no-op. It simply wraps a StreamOutput's stream and
|
||||
* does nothing when the pager is closed.
|
||||
*/
|
||||
class PassthruPager extends StreamOutput implements OutputPager
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param StreamOutput $output
|
||||
*/
|
||||
public function __construct(StreamOutput $output)
|
||||
{
|
||||
parent::__construct($output->getStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current pager process.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
}
|
103
vendor/psy/psysh/src/Psy/Output/ProcOutputPager.php
vendored
103
vendor/psy/psysh/src/Psy/Output/ProcOutputPager.php
vendored
@@ -1,103 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Output\StreamOutput;
|
||||
|
||||
/**
|
||||
* ProcOutputPager class.
|
||||
*
|
||||
* A ProcOutputPager instance wraps a regular StreamOutput's stream. Rather
|
||||
* than writing directly to the stream, it shells out to a pager process and
|
||||
* gives that process the stream as stdout. This means regular *nix commands
|
||||
* like `less` and `more` can be used to page large amounts of output.
|
||||
*/
|
||||
class ProcOutputPager extends StreamOutput implements OutputPager
|
||||
{
|
||||
private $proc;
|
||||
private $pipe;
|
||||
private $stream;
|
||||
private $cmd;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param StreamOutput $output
|
||||
* @param string $cmd Pager process command (default: 'less -R -S -F -X')
|
||||
*/
|
||||
public function __construct(StreamOutput $output, $cmd = 'less -R -S -F -X')
|
||||
{
|
||||
$this->stream = $output->getStream();
|
||||
$this->cmd = $cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* @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)
|
||||
*/
|
||||
public function doWrite($message, $newline)
|
||||
{
|
||||
$pipe = $this->getPipe();
|
||||
if (false === @fwrite($pipe, $message . ($newline ? PHP_EOL : ''))) {
|
||||
// @codeCoverageIgnoreStart
|
||||
// should never happen
|
||||
throw new \RuntimeException('Unable to write output.');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
fflush($pipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current pager process.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->pipe)) {
|
||||
fclose($this->pipe);
|
||||
}
|
||||
|
||||
if (isset($this->proc)) {
|
||||
$exit = proc_close($this->proc);
|
||||
if ($exit !== 0) {
|
||||
throw new \RuntimeException('Error closing output stream');
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->pipe, $this->proc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pipe for paging output.
|
||||
*
|
||||
* If no active pager process exists, fork one and return its input pipe.
|
||||
*/
|
||||
private function getPipe()
|
||||
{
|
||||
if (!isset($this->pipe) || !isset($this->proc)) {
|
||||
$desc = array(array('pipe', 'r'), $this->stream, fopen('php://stderr', 'w'));
|
||||
$this->proc = proc_open($this->cmd, $desc, $pipes);
|
||||
|
||||
if (!is_resource($this->proc)) {
|
||||
throw new \RuntimeException('Error opening output stream');
|
||||
}
|
||||
|
||||
$this->pipe = $pipes[0];
|
||||
}
|
||||
|
||||
return $this->pipe;
|
||||
}
|
||||
}
|
203
vendor/psy/psysh/src/Psy/Output/ShellOutput.php
vendored
203
vendor/psy/psysh/src/Psy/Output/ShellOutput.php
vendored
@@ -1,203 +0,0 @@
|
||||
<?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\Output;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
/**
|
||||
* A ConsoleOutput subclass specifically for Psy Shell output.
|
||||
*/
|
||||
class ShellOutput extends ConsoleOutput
|
||||
{
|
||||
const NUMBER_LINES = 128;
|
||||
|
||||
private $paging = 0;
|
||||
private $pager;
|
||||
|
||||
/**
|
||||
* Construct a ShellOutput instance.
|
||||
*
|
||||
* @param mixed $verbosity (default: self::VERBOSITY_NORMAL)
|
||||
* @param bool $decorated (default: null)
|
||||
* @param OutputFormatterInterface $formatter (default: null)
|
||||
* @param null|string|OutputPager $pager (default: null)
|
||||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null, $pager = null)
|
||||
{
|
||||
parent::__construct($verbosity, $decorated, $formatter);
|
||||
|
||||
$this->initFormatters();
|
||||
|
||||
if ($pager === null) {
|
||||
$this->pager = new PassthruPager($this);
|
||||
} elseif (is_string($pager)) {
|
||||
$this->pager = new ProcOutputPager($this, $pager);
|
||||
} elseif ($pager instanceof OutputPager) {
|
||||
$this->pager = $pager;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Unexpected pager parameter: ' . $pager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page multiple lines of output.
|
||||
*
|
||||
* The output pager is started
|
||||
*
|
||||
* If $messages is callable, it will be called, passing this output instance
|
||||
* for rendering. Otherwise, all passed $messages are paged to output.
|
||||
*
|
||||
* Upon completion, the output pager is flushed.
|
||||
*
|
||||
* @param string|array|Closure $messages A string, array of strings or a callback.
|
||||
* @param int $type (default: 0)
|
||||
*/
|
||||
public function page($messages, $type = 0)
|
||||
{
|
||||
if (is_string($messages)) {
|
||||
$messages = (array) $messages;
|
||||
}
|
||||
|
||||
if (!is_array($messages) && !is_callable($messages)) {
|
||||
throw new \InvalidArgumentException('Paged output requires a string, array or callback.');
|
||||
}
|
||||
|
||||
$this->startPaging();
|
||||
|
||||
if (is_callable($messages)) {
|
||||
$messages($this);
|
||||
} else {
|
||||
$this->write($messages, true, $type);
|
||||
}
|
||||
|
||||
$this->stopPaging();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start sending output to the output pager.
|
||||
*/
|
||||
public function startPaging()
|
||||
{
|
||||
$this->paging++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop paging output and flush the output pager.
|
||||
*/
|
||||
public function stopPaging()
|
||||
{
|
||||
$this->paging--;
|
||||
$this->closePager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* Optionally, pass `$type | self::NUMBER_LINES` as the $type parameter to
|
||||
* number the lines of output.
|
||||
*
|
||||
* @throws \InvalidArgumentException When unknown output type is given
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines or a single string
|
||||
* @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)
|
||||
{
|
||||
if ($this->getVerbosity() === self::VERBOSITY_QUIET) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = (array) $messages;
|
||||
|
||||
if ($type & self::NUMBER_LINES) {
|
||||
$pad = strlen((string) count($messages));
|
||||
$template = $this->isDecorated() ? "<aside>%{$pad}s</aside>: %s" : "%{$pad}s: %s";
|
||||
|
||||
if ($type & self::OUTPUT_RAW) {
|
||||
$messages = array_map(array('Symfony\Component\Console\Formatter\OutputFormatter', 'escape'), $messages);
|
||||
}
|
||||
|
||||
foreach ($messages as $i => $line) {
|
||||
$messages[$i] = sprintf($template, $i, $line);
|
||||
}
|
||||
|
||||
// clean this up for super.
|
||||
$type = $type & ~self::NUMBER_LINES & ~self::OUTPUT_RAW;
|
||||
}
|
||||
|
||||
parent::write($messages, $newline, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to the output.
|
||||
*
|
||||
* Handles paged output, or writes directly to the output stream.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
if ($this->paging > 0) {
|
||||
$this->pager->doWrite($message, $newline);
|
||||
} else {
|
||||
parent::doWrite($message, $newline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush and close the output pager.
|
||||
*/
|
||||
private function closePager()
|
||||
{
|
||||
if ($this->paging <= 0) {
|
||||
$this->pager->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize output formatter styles.
|
||||
*/
|
||||
private function initFormatters()
|
||||
{
|
||||
$formatter = $this->getFormatter();
|
||||
|
||||
$formatter->setStyle('warning', new OutputFormatterStyle('black', 'yellow'));
|
||||
$formatter->setStyle('aside', new OutputFormatterStyle('blue'));
|
||||
$formatter->setStyle('strong', new OutputFormatterStyle(null, null, array('bold')));
|
||||
$formatter->setStyle('return', new OutputFormatterStyle('cyan'));
|
||||
$formatter->setStyle('urgent', new OutputFormatterStyle('red'));
|
||||
$formatter->setStyle('hidden', new OutputFormatterStyle('black'));
|
||||
|
||||
// Visibility
|
||||
$formatter->setStyle('public', new OutputFormatterStyle(null, null, array('bold')));
|
||||
$formatter->setStyle('protected', new OutputFormatterStyle('yellow'));
|
||||
$formatter->setStyle('private', new OutputFormatterStyle('red'));
|
||||
$formatter->setStyle('global', new OutputFormatterStyle('cyan', null, array('bold')));
|
||||
$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'));
|
||||
$formatter->setStyle('string', new OutputFormatterStyle('green'));
|
||||
$formatter->setStyle('bool', new OutputFormatterStyle('cyan'));
|
||||
$formatter->setStyle('keyword', new OutputFormatterStyle('yellow'));
|
||||
$formatter->setStyle('comment', new OutputFormatterStyle('blue'));
|
||||
$formatter->setStyle('object', new OutputFormatterStyle('blue'));
|
||||
$formatter->setStyle('resource', new OutputFormatterStyle('yellow'));
|
||||
}
|
||||
}
|
91
vendor/psy/psysh/src/Psy/ParserFactory.php
vendored
91
vendor/psy/psysh/src/Psy/ParserFactory.php
vendored
@@ -1,91 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
155
vendor/psy/psysh/src/Psy/Readline/GNUReadline.php
vendored
155
vendor/psy/psysh/src/Psy/Readline/GNUReadline.php
vendored
@@ -1,155 +0,0 @@
|
||||
<?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\Readline;
|
||||
|
||||
/**
|
||||
* A Readline interface implementation for GNU Readline.
|
||||
*
|
||||
* This is by far the coolest way to do it, but it doesn't work with new PHP.
|
||||
*
|
||||
* Oh well.
|
||||
*/
|
||||
class GNUReadline implements Readline
|
||||
{
|
||||
protected $historyFile;
|
||||
protected $historySize;
|
||||
protected $eraseDups;
|
||||
|
||||
/**
|
||||
* GNU Readline is supported iff `readline_list_history` is defined. PHP
|
||||
* decided it would be awesome to swap out GNU Readline for Libedit, but
|
||||
* they ended up shipping an incomplete implementation. So we've got this.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return function_exists('readline_list_history');
|
||||
}
|
||||
|
||||
/**
|
||||
* GNU Readline constructor.
|
||||
*/
|
||||
public function __construct($historyFile = null, $historySize = 0, $eraseDups = false)
|
||||
{
|
||||
$this->historyFile = $historyFile;
|
||||
$this->historySize = $historySize;
|
||||
$this->eraseDups = $eraseDups;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addHistory($line)
|
||||
{
|
||||
if ($res = readline_add_history($line)) {
|
||||
$this->writeHistory();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearHistory()
|
||||
{
|
||||
if ($res = readline_clear_history()) {
|
||||
$this->writeHistory();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function listHistory()
|
||||
{
|
||||
return readline_list_history();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readHistory()
|
||||
{
|
||||
// Workaround PHP bug #69054
|
||||
//
|
||||
// If open_basedir is set, readline_read_history() segfaults. This will be fixed in 5.6.7:
|
||||
//
|
||||
// https://github.com/php/php-src/blob/423a057023ef3c00d2ffc16a6b43ba01d0f71796/NEWS#L19-L21
|
||||
//
|
||||
// TODO: add a PHP version check after next point release
|
||||
if (!ini_get('open_basedir')) {
|
||||
readline_read_history();
|
||||
}
|
||||
readline_clear_history();
|
||||
|
||||
return readline_read_history($this->historyFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readline($prompt = null)
|
||||
{
|
||||
return readline($prompt);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function redisplay()
|
||||
{
|
||||
readline_redisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function writeHistory()
|
||||
{
|
||||
// We have to write history first, since it is used
|
||||
// by Libedit to list history
|
||||
$res = readline_write_history($this->historyFile);
|
||||
if (!$res || !$this->eraseDups && !$this->historySize > 0) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
$hist = $this->listHistory();
|
||||
if (!$hist) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->eraseDups) {
|
||||
// flip-flip technique: removes duplicates, latest entries win.
|
||||
$hist = array_flip(array_flip($hist));
|
||||
// sort on keys to get the order back
|
||||
ksort($hist);
|
||||
}
|
||||
|
||||
if ($this->historySize > 0) {
|
||||
$histsize = count($hist);
|
||||
if ($histsize > $this->historySize) {
|
||||
$hist = array_slice($hist, $histsize - $this->historySize);
|
||||
}
|
||||
}
|
||||
|
||||
readline_clear_history();
|
||||
foreach ($hist as $line) {
|
||||
readline_add_history($line);
|
||||
}
|
||||
|
||||
return readline_write_history($this->historyFile);
|
||||
}
|
||||
}
|
83
vendor/psy/psysh/src/Psy/Readline/Libedit.php
vendored
83
vendor/psy/psysh/src/Psy/Readline/Libedit.php
vendored
@@ -1,83 +0,0 @@
|
||||
<?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\Readline;
|
||||
|
||||
use Psy\Util\Str;
|
||||
|
||||
/**
|
||||
* A Libedit-based Readline implementation.
|
||||
*
|
||||
* This is largely the same as the Readline implementation, but it emulates
|
||||
* support for `readline_list_history` since PHP decided it was a good idea to
|
||||
* ship a fake Readline implementation that is missing history support.
|
||||
*/
|
||||
class Libedit extends GNUReadline
|
||||
{
|
||||
/**
|
||||
* Let's emulate GNU Readline by manually reading and parsing the history file!
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return function_exists('readline') && !function_exists('readline_list_history');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function listHistory()
|
||||
{
|
||||
$history = file_get_contents($this->historyFile);
|
||||
if (!$history) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// libedit doesn't seem to support non-unix line separators.
|
||||
$history = explode("\n", $history);
|
||||
|
||||
// shift the history signature, ensure it's valid
|
||||
if (array_shift($history) !== '_HiStOrY_V2_') {
|
||||
return array();
|
||||
}
|
||||
|
||||
// decode the line
|
||||
$history = array_map(array($this, 'parseHistoryLine'), $history);
|
||||
// filter empty lines & comments
|
||||
return array_values(array_filter($history));
|
||||
}
|
||||
|
||||
/**
|
||||
* From GNUReadline (readline/histfile.c & readline/histexpand.c):
|
||||
* lines starting with "\0" are comments or timestamps;
|
||||
* if "\0" is found in an entry,
|
||||
* everything from it until the next line is a comment.
|
||||
*
|
||||
* @param string $line The history line to parse.
|
||||
*
|
||||
* @return string | null
|
||||
*/
|
||||
protected function parseHistoryLine($line)
|
||||
{
|
||||
// empty line, comment or timestamp
|
||||
if (!$line || $line[0] === "\0") {
|
||||
return;
|
||||
}
|
||||
// if "\0" is found in an entry, then
|
||||
// everything from it until the end of line is a comment.
|
||||
if (($pos = strpos($line, "\0")) !== false) {
|
||||
$line = substr($line, 0, $pos);
|
||||
}
|
||||
|
||||
return ($line !== '') ? Str::unvis($line) : null;
|
||||
}
|
||||
}
|
76
vendor/psy/psysh/src/Psy/Readline/Readline.php
vendored
76
vendor/psy/psysh/src/Psy/Readline/Readline.php
vendored
@@ -1,76 +0,0 @@
|
||||
<?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\Readline;
|
||||
|
||||
/**
|
||||
* An interface abstracting the various readline_* functions.
|
||||
*/
|
||||
interface Readline
|
||||
{
|
||||
/**
|
||||
* Check whether this Readline class is supported by the current system.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported();
|
||||
|
||||
/**
|
||||
* Add a line to the command history.
|
||||
*
|
||||
* @param string $line
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function addHistory($line);
|
||||
|
||||
/**
|
||||
* Clear the command history.
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function clearHistory();
|
||||
|
||||
/**
|
||||
* List the command history.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listHistory();
|
||||
|
||||
/**
|
||||
* Read the command history.
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function readHistory();
|
||||
|
||||
/**
|
||||
* Read a single line of input from the user.
|
||||
*
|
||||
* @param null|string $prompt
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function readline($prompt = null);
|
||||
|
||||
/**
|
||||
* Redraw readline to redraw the display.
|
||||
*/
|
||||
public function redisplay();
|
||||
|
||||
/**
|
||||
* Write the command history to a file.
|
||||
*
|
||||
* @return bool Success
|
||||
*/
|
||||
public function writeHistory();
|
||||
}
|
146
vendor/psy/psysh/src/Psy/Readline/Transient.php
vendored
146
vendor/psy/psysh/src/Psy/Readline/Transient.php
vendored
@@ -1,146 +0,0 @@
|
||||
<?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\Readline;
|
||||
|
||||
use Psy\Exception\BreakException;
|
||||
|
||||
/**
|
||||
* An array-based Readline emulation implementation.
|
||||
*/
|
||||
class Transient implements Readline
|
||||
{
|
||||
private $history;
|
||||
private $historySize;
|
||||
private $eraseDups;
|
||||
|
||||
/**
|
||||
* Transient Readline is always supported.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transient Readline constructor.
|
||||
*/
|
||||
public function __construct($historyFile = null, $historySize = 0, $eraseDups = false)
|
||||
{
|
||||
// don't do anything with the history file...
|
||||
$this->history = array();
|
||||
$this->historySize = $historySize;
|
||||
$this->eraseDups = $eraseDups;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addHistory($line)
|
||||
{
|
||||
if ($this->eraseDups) {
|
||||
if (($key = array_search($line, $this->history)) !== false) {
|
||||
unset($this->history[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->history[] = $line;
|
||||
|
||||
if ($this->historySize > 0) {
|
||||
$histsize = count($this->history);
|
||||
if ($histsize > $this->historySize) {
|
||||
$this->history = array_slice($this->history, $histsize - $this->historySize);
|
||||
}
|
||||
}
|
||||
|
||||
$this->history = array_values($this->history);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearHistory()
|
||||
{
|
||||
$this->history = array();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function listHistory()
|
||||
{
|
||||
return $this->history;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readHistory()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws BreakException if user hits Ctrl+D
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function readline($prompt = null)
|
||||
{
|
||||
echo $prompt;
|
||||
|
||||
return rtrim(fgets($this->getStdin(), 1024));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function redisplay()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function writeHistory()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a STDIN file handle.
|
||||
*
|
||||
* @throws BreakException if user hits Ctrl+D
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
private function getStdin()
|
||||
{
|
||||
if (!isset($this->stdin)) {
|
||||
$this->stdin = fopen('php://stdin', 'r');
|
||||
}
|
||||
|
||||
if (feof($this->stdin)) {
|
||||
throw new BreakException('Ctrl+D');
|
||||
}
|
||||
|
||||
return $this->stdin;
|
||||
}
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
<?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\Reflection;
|
||||
|
||||
/**
|
||||
* Somehow the standard reflection library doesn't include constants.
|
||||
*
|
||||
* ReflectionConstant corrects that omission.
|
||||
*/
|
||||
class ReflectionConstant implements \Reflector
|
||||
{
|
||||
private $class;
|
||||
private $name;
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Construct a ReflectionConstant object.
|
||||
*
|
||||
* @param mixed $class
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct($class, $name)
|
||||
{
|
||||
if (!$class instanceof \ReflectionClass) {
|
||||
$class = new \ReflectionClass($class);
|
||||
}
|
||||
|
||||
$this->class = $class;
|
||||
$this->name = $name;
|
||||
|
||||
$constants = $class->getConstants();
|
||||
if (!array_key_exists($name, $constants)) {
|
||||
throw new \InvalidArgumentException('Unknown constant: ' . $name);
|
||||
}
|
||||
|
||||
$this->value = $constants[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the declaring class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDeclaringClass()
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constant name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the constant.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constant's file name.
|
||||
*
|
||||
* Currently returns null, because if it returns a file name the signature
|
||||
* formatter will barf.
|
||||
*/
|
||||
public function getFileName()
|
||||
{
|
||||
return;
|
||||
// return $this->class->getFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code start line.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getStartLine()
|
||||
{
|
||||
throw new \RuntimeException('Not yet implemented because it\'s unclear what I should do here :)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code end line.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getEndLine()
|
||||
{
|
||||
return $this->getStartLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constant's docblock.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function getDocComment()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export the constant? I don't think this is possible.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function export()
|
||||
{
|
||||
throw new \RuntimeException('Not yet implemented because it\'s unclear what I should do here :)');
|
||||
}
|
||||
|
||||
/**
|
||||
* To string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
}
|
887
vendor/psy/psysh/src/Psy/Shell.php
vendored
887
vendor/psy/psysh/src/Psy/Shell.php
vendored
@@ -1,887 +0,0 @@
|
||||
<?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 Psy\Exception\BreakException;
|
||||
use Psy\Exception\ErrorException;
|
||||
use Psy\Exception\Exception as PsyException;
|
||||
use Psy\Exception\ThrowUpException;
|
||||
use Psy\Output\ShellOutput;
|
||||
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;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* The Psy Shell application.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $shell = new Shell;
|
||||
* $shell->run();
|
||||
*
|
||||
* @author Justin Hileman <justin@justinhileman.info>
|
||||
*/
|
||||
class Shell extends Application
|
||||
{
|
||||
const VERSION = 'v0.7.2';
|
||||
|
||||
const PROMPT = '>>> ';
|
||||
const BUFF_PROMPT = '... ';
|
||||
const REPLAY = '--> ';
|
||||
const RETVAL = '=> ';
|
||||
|
||||
private $config;
|
||||
private $cleaner;
|
||||
private $output;
|
||||
private $readline;
|
||||
private $inputBuffer;
|
||||
private $code;
|
||||
private $codeBuffer;
|
||||
private $codeBufferOpen;
|
||||
private $context;
|
||||
private $includes;
|
||||
private $loop;
|
||||
private $outputWantsNewline = false;
|
||||
private $completion;
|
||||
private $tabCompletionMatchers = array();
|
||||
|
||||
/**
|
||||
* Create a new Psy Shell.
|
||||
*
|
||||
* @param Configuration $config (default: null)
|
||||
*/
|
||||
public function __construct(Configuration $config = null)
|
||||
{
|
||||
$this->config = $config ?: new Configuration();
|
||||
$this->cleaner = $this->config->getCodeCleaner();
|
||||
$this->loop = $this->config->getLoop();
|
||||
$this->context = new Context();
|
||||
$this->includes = array();
|
||||
$this->readline = $this->config->getReadline();
|
||||
|
||||
parent::__construct('Psy Shell', self::VERSION);
|
||||
|
||||
$this->config->setShell($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the first thing in a backtrace is an include call.
|
||||
*
|
||||
* This is used by the psysh bin to decide whether to start a shell on boot,
|
||||
* or to simply autoload the library.
|
||||
*/
|
||||
public static function isIncluded(array $trace)
|
||||
{
|
||||
return isset($trace[0]['function']) &&
|
||||
in_array($trace[0]['function'], array('require', 'include', 'require_once', 'include_once'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a Psy Shell from the current context.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* foreach ($items as $item) {
|
||||
* \Psy\Shell::debug(get_defined_vars());
|
||||
* }
|
||||
*
|
||||
* If you would like your shell interaction to affect the state of the
|
||||
* current context, you can extract() the values returned from this call:
|
||||
*
|
||||
* foreach ($items as $item) {
|
||||
* extract(\Psy\Shell::debug(get_defined_vars()));
|
||||
* var_dump($item); // will be whatever you set $item to in Psy Shell
|
||||
* }
|
||||
*
|
||||
* Optionally, supply an object as the `$bind` parameter. This determines
|
||||
* the value `$this` will have in the shell, and sets up class scope so that
|
||||
* private and protected members are accessible:
|
||||
*
|
||||
* class Foo {
|
||||
* function bar() {
|
||||
* \Psy\Shell::debug(get_defined_vars(), $this);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This only really works in PHP 5.4+ and HHVM 3.5+, so upgrade already.
|
||||
*
|
||||
* @param array $vars Scope variables from the calling context (default: array())
|
||||
* @param object $bind Bound object ($this) value for the shell
|
||||
*
|
||||
* @return array Scope variables from the debugger session.
|
||||
*/
|
||||
public static function debug(array $vars = array(), $bind = null)
|
||||
{
|
||||
echo PHP_EOL;
|
||||
|
||||
if ($bind !== null) {
|
||||
$vars['this'] = $bind;
|
||||
}
|
||||
|
||||
$sh = new \Psy\Shell();
|
||||
$sh->setScopeVariables($vars);
|
||||
$sh->run();
|
||||
|
||||
return $sh->getScopeVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a command object.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param BaseCommand $command A Symfony Console Command object
|
||||
*
|
||||
* @return BaseCommand The registered command
|
||||
*/
|
||||
public function add(BaseCommand $command)
|
||||
{
|
||||
if ($ret = parent::add($command)) {
|
||||
if ($ret instanceof ContextAware) {
|
||||
$ret->setContext($this->context);
|
||||
}
|
||||
|
||||
if ($ret instanceof PresenterAware) {
|
||||
$ret->setPresenter($this->config->getPresenter());
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default input definition.
|
||||
*
|
||||
* @return InputDefinition An InputDefinition instance
|
||||
*/
|
||||
protected function getDefaultInputDefinition()
|
||||
{
|
||||
return new InputDefinition(array(
|
||||
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
|
||||
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message.'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default commands that should always be available.
|
||||
*
|
||||
* @return array An array of default Command instances
|
||||
*/
|
||||
protected function getDefaultCommands()
|
||||
{
|
||||
$hist = new Command\HistoryCommand();
|
||||
$hist->setReadline($this->readline);
|
||||
|
||||
return array(
|
||||
new Command\HelpCommand(),
|
||||
new Command\ListCommand(),
|
||||
new Command\DumpCommand(),
|
||||
new Command\DocCommand(),
|
||||
new Command\ShowCommand($this->config->colorMode()),
|
||||
new Command\WtfCommand(),
|
||||
new Command\WhereamiCommand($this->config->colorMode()),
|
||||
new Command\ThrowUpCommand(),
|
||||
new Command\TraceCommand(),
|
||||
new Command\BufferCommand(),
|
||||
new Command\ClearCommand(),
|
||||
// new Command\PsyVersionCommand(),
|
||||
$hist,
|
||||
new Command\ExitCommand(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getTabCompletionMatchers()
|
||||
{
|
||||
if (empty($this->tabCompletionMatchers)) {
|
||||
$this->tabCompletionMatchers = array(
|
||||
new Matcher\CommandsMatcher($this->all()),
|
||||
new Matcher\KeywordsMatcher(),
|
||||
new Matcher\VariablesMatcher(),
|
||||
new Matcher\ConstantsMatcher(),
|
||||
new Matcher\FunctionsMatcher(),
|
||||
new Matcher\ClassNamesMatcher(),
|
||||
new Matcher\ClassMethodsMatcher(),
|
||||
new Matcher\ClassAttributesMatcher(),
|
||||
new Matcher\ObjectMethodsMatcher(),
|
||||
new Matcher\ObjectAttributesMatcher(),
|
||||
);
|
||||
}
|
||||
|
||||
return $this->tabCompletionMatchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $matchers
|
||||
*/
|
||||
public function addTabCompletionMatchers(array $matchers)
|
||||
{
|
||||
$this->tabCompletionMatchers = array_merge($matchers, $this->getTabCompletionMatchers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Shell output.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the current application.
|
||||
*
|
||||
* @param InputInterface $input An Input instance
|
||||
* @param OutputInterface $output An Output instance
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
|
||||
if ($output === null) {
|
||||
$output = $this->config->getOutput();
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::run($input, $output);
|
||||
} catch (\Exception $e) {
|
||||
$this->writeException($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the current application.
|
||||
*
|
||||
* @throws Exception if thrown via the `throw-up` command.
|
||||
*
|
||||
* @param InputInterface $input An Input instance
|
||||
* @param OutputInterface $output An Output instance
|
||||
*
|
||||
* @return int 0 if everything went fine, or an error code
|
||||
*/
|
||||
public function doRun(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->setOutput($output);
|
||||
|
||||
$this->resetCodeBuffer();
|
||||
|
||||
$this->setAutoExit(false);
|
||||
$this->setCatchExceptions(false);
|
||||
|
||||
$this->readline->readHistory();
|
||||
|
||||
// if ($this->config->useReadline()) {
|
||||
// readline_completion_function(array($this, 'autocomplete'));
|
||||
// }
|
||||
|
||||
$this->output->writeln($this->getHeader());
|
||||
|
||||
try {
|
||||
$this->loop->run($this);
|
||||
} catch (ThrowUpException $e) {
|
||||
throw $e->getPrevious();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read user input.
|
||||
*
|
||||
* This will continue fetching user input until the code buffer contains
|
||||
* valid code.
|
||||
*
|
||||
* @throws BreakException if user hits Ctrl+D
|
||||
*/
|
||||
public function getInput()
|
||||
{
|
||||
$this->codeBufferOpen = false;
|
||||
|
||||
do {
|
||||
// reset output verbosity (in case it was altered by a subcommand)
|
||||
$this->output->setVerbosity(ShellOutput::VERBOSITY_VERBOSE);
|
||||
|
||||
$input = $this->readline();
|
||||
|
||||
/*
|
||||
* Handle Ctrl+D. It behaves differently in different cases:
|
||||
*
|
||||
* 1) In an expression, like a function or "if" block, clear the input buffer
|
||||
* 2) At top-level session, behave like the exit command
|
||||
*/
|
||||
if ($input === false) {
|
||||
$this->output->writeln('');
|
||||
|
||||
if ($this->hasCode()) {
|
||||
$this->resetCodeBuffer();
|
||||
} else {
|
||||
throw new BreakException('Ctrl+D');
|
||||
}
|
||||
}
|
||||
|
||||
// handle empty input
|
||||
if (trim($input) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->hasCommand($input)) {
|
||||
$this->readline->addHistory($input);
|
||||
$this->runCommand($input);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addCode($input);
|
||||
} while (!$this->hasValidCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the beforeLoop callback through to the Loop instance.
|
||||
*
|
||||
* @see Loop::beforeLoop
|
||||
*/
|
||||
public function beforeLoop()
|
||||
{
|
||||
$this->loop->beforeLoop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the afterLoop callback through to the Loop instance.
|
||||
*
|
||||
* @see Loop::afterLoop
|
||||
*/
|
||||
public function afterLoop()
|
||||
{
|
||||
$this->loop->afterLoop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the variables currently in scope.
|
||||
*
|
||||
* @param array $vars
|
||||
*/
|
||||
public function setScopeVariables(array $vars)
|
||||
{
|
||||
$this->context->setAll($vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of variables currently in scope.
|
||||
*
|
||||
* @return array Associative array of scope variables.
|
||||
*/
|
||||
public function getScopeVariables()
|
||||
{
|
||||
return $this->context->getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of variable names currently in scope.
|
||||
*
|
||||
* @return array Array of variable names.
|
||||
*/
|
||||
public function getScopeVariableNames()
|
||||
{
|
||||
return array_keys($this->context->getAll());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scope variable value by name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getScopeVariable($name)
|
||||
{
|
||||
return $this->context->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add includes, to be parsed and executed before running the interactive shell.
|
||||
*
|
||||
* @param array $includes
|
||||
*/
|
||||
public function setIncludes(array $includes = array())
|
||||
{
|
||||
$this->includes = $includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP files to be parsed and executed before running the interactive shell.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getIncludes()
|
||||
{
|
||||
return array_merge($this->config->getDefaultIncludes(), $this->includes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this shell's code buffer contains code.
|
||||
*
|
||||
* @return bool True if the code buffer contains code.
|
||||
*/
|
||||
public function hasCode()
|
||||
{
|
||||
return !empty($this->codeBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the code in this shell's code buffer is valid.
|
||||
*
|
||||
* If the code is valid, the code buffer should be flushed and evaluated.
|
||||
*
|
||||
* @return bool True if the code buffer content is valid.
|
||||
*/
|
||||
protected function hasValidCode()
|
||||
{
|
||||
return !$this->codeBufferOpen && $this->code !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add code to the code buffer.
|
||||
*
|
||||
* @param string $code
|
||||
*/
|
||||
public function addCode($code)
|
||||
{
|
||||
try {
|
||||
// Code lines ending in \ keep the buffer open
|
||||
if (substr(rtrim($code), -1) === '\\') {
|
||||
$this->codeBufferOpen = true;
|
||||
$code = substr(rtrim($code), 0, -1);
|
||||
} else {
|
||||
$this->codeBufferOpen = false;
|
||||
}
|
||||
|
||||
$this->codeBuffer[] = $code;
|
||||
$this->code = $this->cleaner->clean($this->codeBuffer, $this->config->requireSemicolons());
|
||||
} catch (\Exception $e) {
|
||||
// Add failed code blocks to the readline history.
|
||||
$this->readline->addHistory(implode("\n", $this->codeBuffer));
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current code buffer.
|
||||
*
|
||||
* This is useful for commands which manipulate the buffer.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCodeBuffer()
|
||||
{
|
||||
return $this->codeBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a Psy Shell command given the user input.
|
||||
*
|
||||
* @throws InvalidArgumentException if the input is not a valid command.
|
||||
*
|
||||
* @param string $input User input string
|
||||
*
|
||||
* @return mixed Who knows?
|
||||
*/
|
||||
protected function runCommand($input)
|
||||
{
|
||||
$command = $this->getCommand($input);
|
||||
|
||||
if (empty($command)) {
|
||||
throw new \InvalidArgumentException('Command not found: ' . $input);
|
||||
}
|
||||
|
||||
$input = new StringInput(str_replace('\\', '\\\\', rtrim($input, " \t\n\r\0\x0B;")));
|
||||
|
||||
if ($input->hasParameterOption(array('--help', '-h'))) {
|
||||
$helpCommand = $this->get('help');
|
||||
$helpCommand->setCommand($command);
|
||||
|
||||
return $helpCommand->run($input, $this->output);
|
||||
}
|
||||
|
||||
return $command->run($input, $this->output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current code buffer.
|
||||
*
|
||||
* This should be run after evaluating user input, catching exceptions, or
|
||||
* on demand by commands such as BufferCommand.
|
||||
*/
|
||||
public function resetCodeBuffer()
|
||||
{
|
||||
$this->codeBuffer = array();
|
||||
$this->code = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject input into the input buffer.
|
||||
*
|
||||
* This is useful for commands which want to replay history.
|
||||
*
|
||||
* @param string|array $input
|
||||
*/
|
||||
public function addInput($input)
|
||||
{
|
||||
foreach ((array) $input as $line) {
|
||||
$this->inputBuffer[] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the current (valid) code buffer.
|
||||
*
|
||||
* If the code buffer is valid, resets the code buffer and returns the
|
||||
* current code.
|
||||
*
|
||||
* @return string PHP code buffer contents.
|
||||
*/
|
||||
public function flushCode()
|
||||
{
|
||||
if ($this->hasValidCode()) {
|
||||
$this->readline->addHistory(implode("\n", $this->codeBuffer));
|
||||
$code = $this->code;
|
||||
$this->resetCodeBuffer();
|
||||
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current evaluation scope namespace.
|
||||
*
|
||||
* @see CodeCleaner::getNamespace
|
||||
*
|
||||
* @return string Current code namespace.
|
||||
*/
|
||||
public function getNamespace()
|
||||
{
|
||||
if ($namespace = $this->cleaner->getNamespace()) {
|
||||
return implode('\\', $namespace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string to stdout.
|
||||
*
|
||||
* This is used by the shell loop for rendering output from evaluated code.
|
||||
*
|
||||
* @param string $out
|
||||
* @param int $phase Output buffering phase
|
||||
*/
|
||||
public function writeStdout($out, $phase = PHP_OUTPUT_HANDLER_END)
|
||||
{
|
||||
$isCleaning = false;
|
||||
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||
$isCleaning = $phase & PHP_OUTPUT_HANDLER_CLEAN;
|
||||
}
|
||||
|
||||
// Incremental flush
|
||||
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(sprintf('<aside>%s</aside>', $this->config->useUnicode() ? '⏎' : '\\n'));
|
||||
$this->outputWantsNewline = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a return value to stdout.
|
||||
*
|
||||
* The return value is formatted or pretty-printed, and rendered in a
|
||||
* visibly distinct manner (in this case, as cyan).
|
||||
*
|
||||
* @see self::presentValue
|
||||
*
|
||||
* @param mixed $ret
|
||||
*/
|
||||
public function writeReturnValue($ret)
|
||||
{
|
||||
$this->context->setReturnValue($ret);
|
||||
$ret = $this->presentValue($ret);
|
||||
$indent = str_repeat(' ', strlen(self::RETVAL));
|
||||
|
||||
$this->output->writeln(self::RETVAL . str_replace(PHP_EOL, PHP_EOL . $indent, $ret));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a caught Exception.
|
||||
*
|
||||
* Exceptions are formatted according to severity. ErrorExceptions which were
|
||||
* warnings or Strict errors aren't rendered as harshly as real errors.
|
||||
*
|
||||
* Stores $e as the last Exception in the Shell Context.
|
||||
*
|
||||
* @param \Exception $e An exception instance
|
||||
* @param OutputInterface $output An OutputInterface instance
|
||||
*/
|
||||
public function writeException(\Exception $e)
|
||||
{
|
||||
$this->context->setLastException($e);
|
||||
|
||||
$message = $e->getMessage();
|
||||
if (!$e instanceof PsyException) {
|
||||
$message = sprintf('%s with message \'%s\'', get_class($e), $message);
|
||||
}
|
||||
|
||||
$severity = ($e instanceof \ErrorException) ? $this->getSeverity($e) : 'error';
|
||||
$this->output->writeln(sprintf('<%s>%s</%s>', $severity, OutputFormatter::escape($message), $severity));
|
||||
|
||||
$this->resetCodeBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for getting an output style for the given ErrorException's level.
|
||||
*
|
||||
* @param \ErrorException $e
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSeverity(\ErrorException $e)
|
||||
{
|
||||
$severity = $e->getSeverity();
|
||||
if ($severity & error_reporting()) {
|
||||
switch ($severity) {
|
||||
case E_WARNING:
|
||||
case E_NOTICE:
|
||||
case E_CORE_WARNING:
|
||||
case E_COMPILE_WARNING:
|
||||
case E_USER_WARNING:
|
||||
case E_USER_NOTICE:
|
||||
case E_STRICT:
|
||||
return 'warning';
|
||||
|
||||
default:
|
||||
return 'error';
|
||||
}
|
||||
} else {
|
||||
// Since this is below the user's reporting threshold, it's always going to be a warning.
|
||||
return 'warning';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for throwing an ErrorException.
|
||||
*
|
||||
* This allows us to:
|
||||
*
|
||||
* set_error_handler(array($psysh, 'handleError'));
|
||||
*
|
||||
* Unlike ErrorException::throwException, this error handler respects the
|
||||
* current error_reporting level; i.e. it logs warnings and notices, but
|
||||
* doesn't throw an exception unless it's above the current error_reporting
|
||||
* 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
|
||||
* @param int $errline Line number
|
||||
*/
|
||||
public function handleError($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
if ($errno & error_reporting()) {
|
||||
ErrorException::throwException($errno, $errstr, $errfile, $errline);
|
||||
} elseif ($errno & $this->config->errorLoggingLevel()) {
|
||||
// log it and continue...
|
||||
$this->writeException(new ErrorException($errstr, 0, $errno, $errfile, $errline));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a value for display.
|
||||
*
|
||||
* @see Presenter::present
|
||||
*
|
||||
* @param mixed $val
|
||||
*
|
||||
* @return string Formatted value
|
||||
*/
|
||||
protected function presentValue($val)
|
||||
{
|
||||
return $this->config->getPresenter()->present($val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a command (if one exists) for the current input string.
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return null|Command
|
||||
*/
|
||||
protected function getCommand($input)
|
||||
{
|
||||
$input = new StringInput($input);
|
||||
if ($name = $input->getFirstArgument()) {
|
||||
return $this->get($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a command is set for the current input string.
|
||||
*
|
||||
* @param string $input
|
||||
*
|
||||
* @return bool True if the shell has a command for the given input.
|
||||
*/
|
||||
protected function hasCommand($input)
|
||||
{
|
||||
$input = new StringInput($input);
|
||||
if ($name = $input->getFirstArgument()) {
|
||||
return $this->has($name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current input prompt.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getPrompt()
|
||||
{
|
||||
return $this->hasCode() ? self::BUFF_PROMPT : self::PROMPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line of user input.
|
||||
*
|
||||
* This will return a line from the input buffer (if any exist). Otherwise,
|
||||
* it will ask the user for input.
|
||||
*
|
||||
* If readline is enabled, this delegates to readline. Otherwise, it's an
|
||||
* ugly `fgets` call.
|
||||
*
|
||||
* @return string One line of user input.
|
||||
*/
|
||||
protected function readline()
|
||||
{
|
||||
if (!empty($this->inputBuffer)) {
|
||||
$line = array_shift($this->inputBuffer);
|
||||
$this->output->writeln(sprintf('<aside>%s %s</aside>', self::REPLAY, OutputFormatter::escape($line)));
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
return $this->readline->readline($this->getPrompt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shell output header.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getHeader()
|
||||
{
|
||||
return sprintf('<aside>%s by Justin Hileman</aside>', $this->getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current version of Psy Shell.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$separator = $this->config->useUnicode() ? '—' : '-';
|
||||
|
||||
return sprintf('Psy Shell %s (PHP %s %s %s)', self::VERSION, phpversion(), $separator, php_sapi_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PHP manual database instance.
|
||||
*
|
||||
* @return PDO|null
|
||||
*/
|
||||
public function getManualDb()
|
||||
{
|
||||
return $this->config->getManualDb();
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocomplete variable names.
|
||||
*
|
||||
* This is used by `readline` for tab completion.
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return mixed Array possible completions for the given input, if any.
|
||||
*/
|
||||
protected function autocomplete($text)
|
||||
{
|
||||
$info = readline_info();
|
||||
// $line = substr($info['line_buffer'], 0, $info['end']);
|
||||
|
||||
// Check whether there's a command for this
|
||||
// $words = explode(' ', $line);
|
||||
// $firstWord = reset($words);
|
||||
|
||||
// check whether this is a variable...
|
||||
$firstChar = substr($info['line_buffer'], max(0, $info['end'] - strlen($text) - 1), 1);
|
||||
if ($firstChar === '$') {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,102 +0,0 @@
|
||||
<?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\TabCompletion;
|
||||
|
||||
use Psy\TabCompletion\Matcher\AbstractMatcher;
|
||||
|
||||
/**
|
||||
* A readline tab completion service.
|
||||
*
|
||||
* @author Marc Garcia <markcial@gmail.com>
|
||||
*/
|
||||
class AutoCompleter
|
||||
{
|
||||
/** @var Matcher\AbstractMatcher[] */
|
||||
protected $matchers;
|
||||
|
||||
/**
|
||||
* Register a tab completion Matcher.
|
||||
*
|
||||
* @param AbstractMatcher $matcher
|
||||
*/
|
||||
public function addMatcher(AbstractMatcher $matcher)
|
||||
{
|
||||
$this->matchers[] = $matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate readline tab completion.
|
||||
*/
|
||||
public function activate()
|
||||
{
|
||||
readline_completion_function(array(&$this, 'callback'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle readline completion.
|
||||
*
|
||||
* @param string $input Readline current word
|
||||
* @param int $index Current word index
|
||||
* @param array $info readline_info() data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function processCallback($input, $index, $info = array())
|
||||
{
|
||||
$line = substr($info['line_buffer'], 0, $info['end']);
|
||||
$tokens = token_get_all('<?php ' . $line);
|
||||
// remove whitespaces
|
||||
$tokens = array_filter($tokens, function ($token) {
|
||||
return !AbstractMatcher::tokenIs($token, AbstractMatcher::T_WHITESPACE);
|
||||
});
|
||||
|
||||
$matches = array();
|
||||
foreach ($this->matchers as $matcher) {
|
||||
if ($matcher->hasMatched($tokens)) {
|
||||
$matches = array_merge($matcher->getMatches($tokens), $matches);
|
||||
}
|
||||
}
|
||||
|
||||
$matches = array_unique($matches);
|
||||
|
||||
return !empty($matches) ? $matches : array('');
|
||||
}
|
||||
|
||||
/**
|
||||
* The readline_completion_function callback handler.
|
||||
*
|
||||
* @see processCallback
|
||||
*
|
||||
* @param $input
|
||||
* @param $index
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function callback($input, $index)
|
||||
{
|
||||
return $this->processCallback($input, $index, readline_info());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove readline callback handler on destruct.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// PHP didn't implement the whole readline API when they first switched
|
||||
// to libedit. And they still haven't.
|
||||
//
|
||||
// So this is a thing to make PsySH work on 5.3.x:
|
||||
if (function_exists('readline_callback_handler_remove')) {
|
||||
readline_callback_handler_remove();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
<?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\TabCompletion\Matcher;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\ContextAware;
|
||||
|
||||
/**
|
||||
* An abstract tab completion Matcher which implements ContextAware.
|
||||
*
|
||||
* The AutoCompleter service will inject a Context instance into all
|
||||
* ContextAware Matchers.
|
||||
*
|
||||
* @author Marc Garcia <markcial@gmail.com>
|
||||
*/
|
||||
abstract class AbstractContextAwareMatcher extends AbstractMatcher implements ContextAware
|
||||
{
|
||||
/**
|
||||
* Context instance (for ContextAware interface).
|
||||
*
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* ContextAware interface.
|
||||
*
|
||||
* @param Context $context
|
||||
*/
|
||||
public function setContext(Context $context)
|
||||
{
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Context variable by name.
|
||||
*
|
||||
* @param $var Variable name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getVariable($var)
|
||||
{
|
||||
return $this->context->get($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all variables in the current Context.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getVariables()
|
||||
{
|
||||
return $this->context->getAll();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user