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