Няма описание

WhereamiCommand.php 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <?php
  2. /*
  3. * This file is part of Psy Shell.
  4. *
  5. * (c) 2012-2018 Justin Hileman
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Psy\Command;
  11. use JakubOnderka\PhpConsoleHighlighter\Highlighter;
  12. use Psy\Configuration;
  13. use Psy\ConsoleColorFactory;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. use Symfony\Component\Console\Input\InputOption;
  16. use Symfony\Component\Console\Output\OutputInterface;
  17. /**
  18. * Show the context of where you opened the debugger.
  19. */
  20. class WhereamiCommand extends Command
  21. {
  22. private $colorMode;
  23. private $backtrace;
  24. /**
  25. * @param null|string $colorMode (default: null)
  26. */
  27. public function __construct($colorMode = null)
  28. {
  29. $this->colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO;
  30. $this->backtrace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  31. parent::__construct();
  32. }
  33. /**
  34. * {@inheritdoc}
  35. */
  36. protected function configure()
  37. {
  38. $this
  39. ->setName('whereami')
  40. ->setDefinition([
  41. new InputOption('num', 'n', InputOption::VALUE_OPTIONAL, 'Number of lines before and after.', '5'),
  42. ])
  43. ->setDescription('Show where you are in the code.')
  44. ->setHelp(
  45. <<<'HELP'
  46. Show where you are in the code.
  47. Optionally, include how many lines before and after you want to display.
  48. e.g.
  49. <return>> whereami </return>
  50. <return>> whereami -n10</return>
  51. HELP
  52. );
  53. }
  54. /**
  55. * Obtains the correct stack frame in the full backtrace.
  56. *
  57. * @return array
  58. */
  59. protected function trace()
  60. {
  61. foreach (\array_reverse($this->backtrace) as $stackFrame) {
  62. if ($this->isDebugCall($stackFrame)) {
  63. return $stackFrame;
  64. }
  65. }
  66. return \end($this->backtrace);
  67. }
  68. private static function isDebugCall(array $stackFrame)
  69. {
  70. $class = isset($stackFrame['class']) ? $stackFrame['class'] : null;
  71. $function = isset($stackFrame['function']) ? $stackFrame['function'] : null;
  72. return ($class === null && $function === 'Psy\debug') ||
  73. ($class === 'Psy\Shell' && \in_array($function, ['__construct', 'debug']));
  74. }
  75. /**
  76. * Determine the file and line based on the specific backtrace.
  77. *
  78. * @return array
  79. */
  80. protected function fileInfo()
  81. {
  82. $stackFrame = $this->trace();
  83. if (\preg_match('/eval\(/', $stackFrame['file'])) {
  84. \preg_match_all('/([^\(]+)\((\d+)/', $stackFrame['file'], $matches);
  85. $file = $matches[1][0];
  86. $line = (int) $matches[2][0];
  87. } else {
  88. $file = $stackFrame['file'];
  89. $line = $stackFrame['line'];
  90. }
  91. return \compact('file', 'line');
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. protected function execute(InputInterface $input, OutputInterface $output)
  97. {
  98. $info = $this->fileInfo();
  99. $num = $input->getOption('num');
  100. $factory = new ConsoleColorFactory($this->colorMode);
  101. $colors = $factory->getConsoleColor();
  102. $highlighter = new Highlighter($colors);
  103. $contents = \file_get_contents($info['file']);
  104. $output->startPaging();
  105. $output->writeln('');
  106. $output->writeln(\sprintf('From <info>%s:%s</info>:', $this->replaceCwd($info['file']), $info['line']));
  107. $output->writeln('');
  108. $output->write($highlighter->getCodeSnippet($contents, $info['line'], $num, $num), false, OutputInterface::OUTPUT_RAW);
  109. $output->stopPaging();
  110. return 0;
  111. }
  112. /**
  113. * Replace the given directory from the start of a filepath.
  114. *
  115. * @param string $file
  116. *
  117. * @return string
  118. */
  119. private function replaceCwd($file)
  120. {
  121. $cwd = \getcwd();
  122. if ($cwd === false) {
  123. return $file;
  124. }
  125. $cwd = \rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
  126. return \preg_replace('/^' . \preg_quote($cwd, '/') . '/', '', $file);
  127. }
  128. }