Chris@0: colorMode = $colorMode ?: Configuration::COLOR_MODE_AUTO; Chris@0: Chris@0: if (version_compare(PHP_VERSION, '5.3.6', '>=')) { Chris@0: $this->backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); Chris@0: } else { Chris@0: $this->backtrace = debug_backtrace(); Chris@0: } Chris@0: Chris@0: return parent::__construct(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: protected function configure() Chris@0: { Chris@0: $this Chris@0: ->setName('whereami') Chris@0: ->setDefinition(array( Chris@0: new InputOption('num', 'n', InputOption::VALUE_OPTIONAL, 'Number of lines before and after.', '5'), Chris@0: )) Chris@0: ->setDescription('Show where you are in the code.') Chris@0: ->setHelp( Chris@0: <<<'HELP' Chris@0: Show where you are in the code. Chris@0: Chris@0: Optionally, include how many lines before and after you want to display. Chris@0: Chris@0: e.g. Chris@0: > whereami Chris@0: > whereami -n10 Chris@0: HELP Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Obtains the correct stack frame in the full backtrace. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: protected function trace() Chris@0: { Chris@0: foreach (array_reverse($this->backtrace) as $stackFrame) { Chris@0: if ($this->isDebugCall($stackFrame)) { Chris@0: return $stackFrame; Chris@0: } Chris@0: } Chris@0: Chris@0: return end($this->backtrace); Chris@0: } Chris@0: Chris@0: private static function isDebugCall(array $stackFrame) Chris@0: { Chris@0: $class = isset($stackFrame['class']) ? $stackFrame['class'] : null; Chris@0: $function = isset($stackFrame['function']) ? $stackFrame['function'] : null; Chris@0: Chris@0: return ($class === null && $function === 'Psy\debug') || Chris@0: ($class === 'Psy\Shell' && in_array($function, array('__construct', 'debug'))); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determine the file and line based on the specific backtrace. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: protected function fileInfo() Chris@0: { Chris@0: $stackFrame = $this->trace(); Chris@0: if (preg_match('/eval\(/', $stackFrame['file'])) { Chris@0: preg_match_all('/([^\(]+)\((\d+)/', $stackFrame['file'], $matches); Chris@0: $file = $matches[1][0]; Chris@0: $line = (int) $matches[2][0]; Chris@0: } else { Chris@0: $file = $stackFrame['file']; Chris@0: $line = $stackFrame['line']; Chris@0: } Chris@0: Chris@0: return compact('file', 'line'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: protected function execute(InputInterface $input, OutputInterface $output) Chris@0: { Chris@0: $info = $this->fileInfo(); Chris@0: $num = $input->getOption('num'); Chris@0: $factory = new ConsoleColorFactory($this->colorMode); Chris@0: $colors = $factory->getConsoleColor(); Chris@0: $highlighter = new Highlighter($colors); Chris@0: $contents = file_get_contents($info['file']); Chris@0: Chris@0: $output->startPaging(); Chris@0: $output->writeln(''); Chris@0: $output->writeln(sprintf('From %s:%s:', $this->replaceCwd($info['file']), $info['line'])); Chris@0: $output->writeln(''); Chris@0: $output->write($highlighter->getCodeSnippet($contents, $info['line'], $num, $num), ShellOutput::OUTPUT_RAW); Chris@0: $output->stopPaging(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Replace the given directory from the start of a filepath. Chris@0: * Chris@0: * @param string $file Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: private function replaceCwd($file) Chris@0: { Chris@0: $cwd = getcwd(); Chris@0: if ($cwd === false) { Chris@0: return $file; Chris@0: } Chris@0: Chris@0: $cwd = rtrim($cwd, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; Chris@0: Chris@0: return preg_replace('/^' . preg_quote($cwd, '/') . '/', '', $file); Chris@0: } Chris@0: }