Skip to content

Commit 0ed9203

Browse files
authored
Merge pull request #12 from tweakphp/fix-dd
fix dd & add stacked output
2 parents e37398e + 947f40f commit 0ed9203

File tree

9 files changed

+163
-85
lines changed

9 files changed

+163
-85
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
"require": {
1616
"php": ">=7.4",
1717
"ext-json": "*",
18-
"psy/psysh": "*"
18+
"psy/psysh": "*",
19+
"nikic/php-parser": "*",
20+
"symfony/var-dumper": "*",
21+
"symfony/console": "*"
1922
},
2023
"minimum-stability": "stable",
2124
"prefer-stable": true

composer.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.php

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@
1111
exit(1);
1212
}
1313

14-
function dd(...$args)
15-
{
16-
if (count($args) === 1) {
17-
return $args[0];
18-
}
19-
20-
return $args;
21-
}
22-
2314
$loader = Loader::load($arguments[1]);
2415

2516
if ($loader === null) {
@@ -53,6 +44,7 @@ function dd(...$args)
5344
echo 'Invalid arguments'.PHP_EOL;
5445
exit(1);
5546
}
56-
echo $loader->execute(base64_decode($arguments[3])).PHP_EOL;
47+
$output = json_encode($loader->execute(base64_decode($arguments[3])));
48+
echo 'TWEAKPHP_RESULT:'.$output.PHP_EOL;
5749
break;
5850
}

src/Casters/LaravelCaster.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace TweakPHP\Client\Casters;
4+
5+
class LaravelCaster
6+
{
7+
public static function casters(): array
8+
{
9+
$casters = [
10+
'Illuminate\Support\Collection' => 'Laravel\Tinker\TinkerCaster::castCollection',
11+
'Illuminate\Support\HtmlString' => 'Laravel\Tinker\TinkerCaster::castHtmlString',
12+
'Illuminate\Support\Stringable' => 'Laravel\Tinker\TinkerCaster::castStringable',
13+
];
14+
15+
if (class_exists('Illuminate\Database\Eloquent\Model')) {
16+
$casters['Illuminate\Database\Eloquent\Model'] = 'Laravel\Tinker\TinkerCaster::castModel';
17+
}
18+
19+
if (class_exists('Illuminate\Process\ProcessResult')) {
20+
$casters['Illuminate\Process\ProcessResult'] = 'Laravel\Tinker\TinkerCaster::castProcessResult';
21+
}
22+
23+
if (class_exists('Illuminate\Foundation\Application')) {
24+
$casters['Illuminate\Foundation\Application'] = 'Laravel\Tinker\TinkerCaster::castApplication';
25+
}
26+
27+
return $casters;
28+
}
29+
}

src/Loaders/BaseLoader.php

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace TweakPHP\Client\Loaders;
44

5-
use Psy\Configuration;
5+
use Psy\Configuration as ConfigurationAlias;
66
use Psy\VersionUpdater\Checker;
7+
use TweakPHP\Client\Casters\LaravelCaster;
78
use TweakPHP\Client\OutputModifiers\CustomOutputModifier;
9+
use TweakPHP\Client\Psy\Configuration;
810
use TweakPHP\Client\Tinker;
911

1012
abstract class BaseLoader implements LoaderInterface
@@ -17,42 +19,22 @@ public function init(): void
1719
'configFile' => null,
1820
]);
1921
$config->setUpdateCheck(Checker::NEVER);
20-
$config->setRawOutput(true);
21-
$config->setInteractiveMode(Configuration::INTERACTIVE_MODE_DISABLED);
22-
$config->setColorMode(Configuration::COLOR_MODE_DISABLED);
22+
$config->setInteractiveMode(ConfigurationAlias::INTERACTIVE_MODE_DISABLED);
23+
$config->setColorMode(ConfigurationAlias::COLOR_MODE_DISABLED);
24+
$config->setRawOutput(false);
2325
$config->setTheme([
2426
'prompt' => '',
2527
]);
26-
$config->setVerbosity(Configuration::VERBOSITY_QUIET);
2728
$config->setHistoryFile(defined('PHP_WINDOWS_VERSION_BUILD') ? 'null' : '/dev/null');
28-
$config->setRawOutput(false);
29-
if (getenv('KUBERNETES_SERVICE_HOST') || defined('PHP_WINDOWS_VERSION_BUILD')) {
30-
$config->setUsePcntl(false);
31-
}
29+
$config->setUsePcntl(false);
3230

33-
if (class_exists('Illuminate\Support\Collection') && class_exists('Laravel\Tinker\TinkerCaster')) {
34-
$config->getPresenter()->addCasters([
35-
\Illuminate\Support\Collection::class => 'Laravel\Tinker\TinkerCaster::castCollection',
36-
]);
37-
}
38-
if (class_exists('Illuminate\Database\Eloquent\Model') && class_exists('Laravel\Tinker\TinkerCaster')) {
39-
$config->getPresenter()->addCasters([
40-
\Illuminate\Database\Eloquent\Model::class => 'Laravel\Tinker\TinkerCaster::castModel',
41-
]);
42-
}
43-
if (class_exists('Illuminate\Foundation\Application') && class_exists('Laravel\Tinker\TinkerCaster')) {
44-
$config->getPresenter()->addCasters([
45-
\Illuminate\Foundation\Application::class => 'Laravel\Tinker\TinkerCaster::castApplication',
46-
]);
47-
}
31+
$config->getPresenter()->addCasters(LaravelCaster::casters());
4832

4933
$this->tinker = new Tinker(new CustomOutputModifier, $config);
5034
}
5135

52-
public function execute(string $code): string
36+
public function execute(string $code): array
5337
{
54-
$output = $this->tinker->execute($code);
55-
56-
return trim($output);
38+
return $this->tinker->execute($code);
5739
}
5840
}

src/Loaders/LoaderInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ public function version(): string;
1212

1313
public function init(): void;
1414

15-
public function execute(string $code): string;
15+
public function execute(string $code): array;
1616
}

src/Psy/Configuration.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace TweakPHP\Client\Psy;
4+
5+
class Configuration extends \Psy\Configuration
6+
{
7+
public function getPresenter(): Presenter
8+
{
9+
if (! isset($this->presenter)) {
10+
$this->presenter = new Presenter($this->getOutput()->getFormatter(), $this->forceArrayIndexes());
11+
}
12+
13+
return $this->presenter;
14+
}
15+
}

src/Psy/Presenter.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace TweakPHP\Client\Psy;
4+
5+
use Psy\VarDumper\Cloner;
6+
use Symfony\Component\Console\Formatter\OutputFormatter;
7+
use Symfony\Component\VarDumper\Caster\Caster;
8+
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
9+
use TweakPHP\Client\Tinker;
10+
11+
class Presenter extends \Psy\VarDumper\Presenter
12+
{
13+
private Cloner $cloner;
14+
15+
public function __construct(OutputFormatter $formatter, $forceArrayIndexes = false)
16+
{
17+
parent::__construct($formatter, $forceArrayIndexes);
18+
19+
$this->cloner = new Cloner;
20+
}
21+
22+
public function addCasters(array $casters)
23+
{
24+
parent::addCasters($casters);
25+
26+
$this->cloner->addCasters($casters);
27+
}
28+
29+
public function present($value, ?int $depth = null, int $options = 0): string
30+
{
31+
$dumper = new HtmlDumper;
32+
$dumper->setDumpHeader('');
33+
$data = $this->cloner->cloneVar($value, ! ($options & self::VERBOSE) ? Caster::EXCLUDE_VERBOSE : 0);
34+
if ($depth !== null) {
35+
$data = $data->withMaxDepth($depth);
36+
}
37+
38+
$output = '';
39+
$dumper->dump($data, function ($line, $depth) use (&$output) {
40+
if ($depth >= 0) {
41+
if ($output !== '') {
42+
$output .= \PHP_EOL;
43+
}
44+
$output .= \str_repeat(' ', $depth).$line;
45+
}
46+
});
47+
48+
if (isset(Tinker::$statements[Tinker::$current])) {
49+
Tinker::$statements[Tinker::$current]['html'] = $output;
50+
}
51+
52+
return parent::present($value, $depth, $options);
53+
}
54+
}

src/Tinker.php

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace TweakPHP\Client;
44

5+
use PhpParser\ParserFactory;
6+
use PhpParser\PrettyPrinter\Standard;
57
use Psy\Configuration;
68
use Psy\ExecutionLoopClosure;
79
use Psy\Shell;
@@ -16,6 +18,10 @@ class Tinker
1618

1719
protected OutputModifier $outputModifier;
1820

21+
public static array $statements = [];
22+
23+
public static int $current = 0;
24+
1925
public function __construct(OutputModifier $outputModifier, Configuration $config)
2026
{
2127
$this->output = new BufferedOutput;
@@ -25,23 +31,41 @@ public function __construct(OutputModifier $outputModifier, Configuration $confi
2531
$this->outputModifier = $outputModifier;
2632
}
2733

28-
public function execute(string $phpCode): string
34+
public function execute(string $rawPHPCode): array
2935
{
30-
$phpCode = $this->removeComments($phpCode);
31-
32-
$this->shell->addInput($phpCode);
36+
if (strpos($rawPHPCode, '<?php') === false) {
37+
$rawPHPCode = "<?php\n".$rawPHPCode;
38+
}
3339

34-
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
35-
$this->shell->addInput("\necho('TWEAKPHP_END'); exit();");
40+
$parser = (new ParserFactory)->createForHostVersion();
41+
$prettyPrinter = new Standard;
42+
foreach ($parser->parse($rawPHPCode) as $key => $stmt) {
43+
$code = $prettyPrinter->prettyPrint([$stmt]);
44+
self::$current = $key;
45+
self::$statements[] = [
46+
'line' => $stmt->getStartLine(),
47+
'code' => $code,
48+
];
49+
$output = $this->doExecute($code);
50+
self::$statements[$key]['output'] = $output;
3651
}
3752

38-
$closure = new ExecutionLoopClosure($this->shell);
53+
return [
54+
'output' => self::$statements,
55+
];
56+
}
3957

58+
protected function doExecute(string $code): string
59+
{
60+
$this->shell->addInput($code);
61+
$this->shell->addInput("\necho('TWEAKPHP_END'); exit();");
62+
$this->output = new BufferedOutput;
63+
$this->shell->setOutput($this->output);
64+
$closure = new ExecutionLoopClosure($this->shell);
4065
$closure->execute();
66+
$result = $this->outputModifier->modify($this->cleanOutput($this->output->fetch()));
4167

42-
$output = $this->cleanOutput($this->output->fetch());
43-
44-
return $this->outputModifier->modify($output);
68+
return trim($result);
4569
}
4670

4771
protected function createShell(BufferedOutput $output, Configuration $config): Shell
@@ -53,27 +77,6 @@ protected function createShell(BufferedOutput $output, Configuration $config): S
5377
return $shell;
5478
}
5579

56-
public function removeComments(string $code): string
57-
{
58-
$tokens = token_get_all("<?php\n".$code.'?>');
59-
$result = '';
60-
61-
foreach ($tokens as $token) {
62-
if (is_array($token)) {
63-
[$id, $text] = $token;
64-
65-
if (in_array($id, [T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG, T_CLOSE_TAG])) {
66-
continue;
67-
}
68-
$result .= $text;
69-
} else {
70-
$result .= $token;
71-
}
72-
}
73-
74-
return $result;
75-
}
76-
7780
protected function cleanOutput(string $output): string
7881
{
7982
$output = preg_replace('/(?s)(<aside.*?<\/aside>)|Exit: Ctrl\+D/ms', '$2', $output);

0 commit comments

Comments
 (0)