-
-
Notifications
You must be signed in to change notification settings - Fork 11
Adds the source file and line number to dd()
output
#134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
43b14ed
improvement to the dd() output of hypervel showing the source where i…
anabeto93 302e310
a little linting here.
anabeto93 1369e06
linting issue fixed.
anabeto93 526fb22
additional docblock linting.
anabeto93 56b6880
linting as recommended
anabeto93 530e595
Merge branch 'main' into feature/dd-source
albertcht c3be831
fix: fix php-cs
albertcht a546f50
fix: fix php-cs
albertcht 6c27269
fix: fix php-cs
albertcht f455e52
fix: adjust exclude path in php-cs config
albertcht File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Hypervel\Foundation\Concerns; | ||
|
||
use Throwable; | ||
|
||
trait ResolvesDumpSource | ||
{ | ||
/** | ||
* All of the href formats for common editors. | ||
* | ||
* @var array<string, string> | ||
*/ | ||
protected array $editorHrefs = [ | ||
'atom' => 'atom://core/open/file?filename={file}&line={line}', | ||
'cursor' => 'cursor://file/{file}:{line}', | ||
'emacs' => 'emacs://open?url=file://{file}&line={line}', | ||
'idea' => 'idea://open?file={file}&line={line}', | ||
'macvim' => 'mvim://open/?url=file://{file}&line={line}', | ||
'netbeans' => 'netbeans://open/?f={file}:{line}', | ||
'nova' => 'nova://core/open/file?filename={file}&line={line}', | ||
'phpstorm' => 'phpstorm://open?file={file}&line={line}', | ||
'sublime' => 'subl://open?url=file://{file}&line={line}', | ||
'textmate' => 'txmt://open?url=file://{file}&line={line}', | ||
'vscode' => 'vscode://file/{file}:{line}', | ||
'vscode-insiders' => 'vscode-insiders://file/{file}:{line}', | ||
'vscode-insiders-remote' => 'vscode-insiders://vscode-remote/{file}:{line}', | ||
'vscode-remote' => 'vscode://vscode-remote/{file}:{line}', | ||
'vscodium' => 'vscodium://file/{file}:{line}', | ||
'xdebug' => 'xdebug://{file}@{line}', | ||
]; | ||
|
||
/** | ||
* Files that require special trace handling and their levels. | ||
* | ||
* @var array<string, int> | ||
*/ | ||
protected static array $adjustableTraces = [ | ||
'symfony/var-dumper/Resources/functions/dump.php' => 1, | ||
]; | ||
|
||
/** | ||
* The source resolver. | ||
* | ||
* @var null|(callable(): (null|array{0: string, 1: string, 2: null|int}))|false | ||
*/ | ||
protected static $dumpSourceResolver; | ||
|
||
/** | ||
* Resolve the source of the dump call. | ||
* | ||
* @return null|array{0: string, 1: string, 2: null|int} | ||
*/ | ||
public function resolveDumpSource(): ?array | ||
{ | ||
if (static::$dumpSourceResolver === false) { | ||
return null; | ||
} | ||
|
||
if (static::$dumpSourceResolver) { | ||
return call_user_func(static::$dumpSourceResolver); | ||
} | ||
|
||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 20); | ||
|
||
$sourceKey = null; | ||
|
||
foreach ($trace as $traceKey => $traceFile) { | ||
if (! isset($traceFile['file'])) { | ||
continue; | ||
} | ||
|
||
foreach (self::$adjustableTraces as $name => $key) { | ||
if (str_ends_with( | ||
$traceFile['file'], | ||
str_replace('/', DIRECTORY_SEPARATOR, $name) | ||
)) { | ||
$sourceKey = $traceKey + $key; | ||
break; | ||
} | ||
} | ||
|
||
if (! is_null($sourceKey)) { | ||
break; | ||
} | ||
} | ||
|
||
if (is_null($sourceKey)) { | ||
return null; | ||
} | ||
|
||
$file = $trace[$sourceKey]['file'] ?? null; | ||
$line = $trace[$sourceKey]['line'] ?? null; | ||
|
||
if (is_null($file) || is_null($line)) { | ||
return null; | ||
} | ||
|
||
$relativeFile = $file; | ||
|
||
if ($this->isCompiledViewFile($file)) { | ||
$file = $this->getOriginalFileForCompiledView($file); | ||
$line = null; | ||
} | ||
|
||
if (str_starts_with($file, $this->basePath)) { | ||
$relativeFile = substr($file, strlen($this->basePath) + 1); | ||
} | ||
|
||
return [$file, $relativeFile, $line]; | ||
} | ||
|
||
/** | ||
* Determine if the given file is a view compiled. | ||
*/ | ||
protected function isCompiledViewFile(string $file): bool | ||
{ | ||
return str_starts_with($file, $this->compiledViewPath) && str_ends_with($file, '.php'); | ||
} | ||
|
||
/** | ||
* Get the original view compiled file by the given compiled file. | ||
*/ | ||
protected function getOriginalFileForCompiledView(string $file): string | ||
{ | ||
preg_match('/\/\*\*PATH\s(.*)\sENDPATH/', file_get_contents($file), $matches); | ||
|
||
if (isset($matches[1])) { | ||
$file = $matches[1]; | ||
} | ||
|
||
return $file; | ||
} | ||
|
||
/** | ||
* Resolve the source href, if possible. | ||
* | ||
* @return null|string|void | ||
*/ | ||
protected function resolveSourceHref(string $file, ?int $line) | ||
{ | ||
try { | ||
$editor = config('app.editor'); | ||
} catch (Throwable) { | ||
// .. | ||
} | ||
|
||
if (! isset($editor)) { | ||
return; | ||
} | ||
|
||
$href = is_array($editor) && isset($editor['href']) | ||
? $editor['href'] | ||
: ($this->editorHrefs[$editor['name'] ?? $editor] ?? sprintf('%s://open?file={file}&line={line}', $editor['name'] ?? $editor)); | ||
|
||
if ($basePath = $editor['base_path'] ?? false) { | ||
$file = str_replace($this->basePath, $basePath, $file); | ||
} | ||
|
||
return str_replace( | ||
['{file}', '{line}'], | ||
[$file, is_null($line) ? 1 : $line], | ||
$href, | ||
); | ||
} | ||
|
||
/** | ||
* Set the resolver that resolves the source of the dump call. | ||
* | ||
* @param null|(callable(): (null|array{0: string, 1: string, 2: null|int})) $callable | ||
*/ | ||
public static function resolveDumpSourceUsing(?callable $callable): void | ||
{ | ||
static::$dumpSourceResolver = $callable; | ||
} | ||
|
||
/** | ||
* Don't include the location / file of the dump in dumps. | ||
*/ | ||
public static function dontIncludeSource(): void | ||
{ | ||
static::$dumpSourceResolver = false; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Hypervel\Foundation\Console; | ||
|
||
use Hypervel\Foundation\Concerns\ResolvesDumpSource; | ||
use Symfony\Component\Console\Output\ConsoleOutput; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\VarDumper\Caster\ReflectionCaster; | ||
use Symfony\Component\VarDumper\Cloner\Data; | ||
use Symfony\Component\VarDumper\Cloner\VarCloner; | ||
use Symfony\Component\VarDumper\Dumper\CliDumper as BaseCliDumper; | ||
use Symfony\Component\VarDumper\VarDumper; | ||
|
||
class CliDumper extends BaseCliDumper | ||
{ | ||
use ResolvesDumpSource; | ||
|
||
/** | ||
* If the dumper is currently dumping. | ||
*/ | ||
protected bool $dumping = false; | ||
|
||
/** | ||
* Create a new CLI dumper instance. | ||
* | ||
* @param OutputInterface $output | ||
*/ | ||
public function __construct( | ||
protected mixed $output, | ||
protected string $basePath, | ||
protected ?string $compiledViewPath, | ||
) { | ||
parent::__construct(); | ||
|
||
$this->setColors($this->supportsColors()); | ||
} | ||
|
||
/** | ||
* Create a new CLI dumper instance and register it as the default dumper. | ||
* | ||
* @param string $basePath | ||
* @param string $compiledViewPath | ||
*/ | ||
public static function register($basePath, $compiledViewPath): void | ||
{ | ||
$cloner = tap(new VarCloner())->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); | ||
|
||
$dumper = new static(new ConsoleOutput(), $basePath, $compiledViewPath); | ||
|
||
VarDumper::setHandler(fn ($value) => $dumper->dumpWithSource($cloner->cloneVar($value))); | ||
} | ||
|
||
/** | ||
* Dump a variable with its source file / line. | ||
*/ | ||
public function dumpWithSource(Data $data): void | ||
{ | ||
if ($this->dumping) { | ||
$this->dump($data); | ||
|
||
return; | ||
} | ||
|
||
$this->dumping = true; | ||
|
||
$output = (string) $this->dump($data, true); | ||
$lines = explode("\n", $output); | ||
|
||
$lines[array_key_last($lines) - 1] .= $this->getDumpSourceContent(); | ||
|
||
$this->output->write(implode("\n", $lines)); | ||
|
||
$this->dumping = false; | ||
} | ||
|
||
/** | ||
* Get the dump's source console content. | ||
*/ | ||
protected function getDumpSourceContent(): string | ||
{ | ||
if (is_null($dumpSource = $this->resolveDumpSource())) { | ||
return ''; | ||
} | ||
|
||
[$file, $relativeFile, $line] = $dumpSource; | ||
|
||
$href = $this->resolveSourceHref($file, $line); | ||
|
||
return sprintf( | ||
' <fg=gray>// <fg=gray%s>%s%s</></>', | ||
is_null($href) ? '' : ";href={$href}", | ||
$relativeFile, | ||
is_null($line) ? '' : ":{$line}" | ||
); | ||
} | ||
|
||
protected function supportsColors(): bool | ||
{ | ||
return $this->output->isDecorated(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add type declaration and default value