function Code::generateFileReport
Generate a partial report for a single processed file.
Function should return TRUE if it printed or stored data about the file and FALSE if it ignored the file. Returning TRUE indicates that the file and its data should be counted in the grand totals.
Parameters
array<string, string|int|array> $report Prepared report data.: See the {@see Report} interface for a detailed specification.
\PHP_CodeSniffer\Files\File $phpcsFile The file being reported on.:
bool $showSources Show sources?:
int $width Maximum allowed line width.:
Return value
bool
Overrides Report::generateFileReport
File
-
vendor/
squizlabs/ php_codesniffer/ src/ Reports/ Code.php, line 36
Class
Namespace
PHP_CodeSniffer\ReportsCode
public function generateFileReport($report, File $phpcsFile, $showSources = false, $width = 80) {
if ($report['errors'] === 0 && $report['warnings'] === 0) {
// Nothing to print.
return false;
}
// How many lines to show above and below the error line.
$surroundingLines = 2;
$file = $report['filename'];
$tokens = $phpcsFile->getTokens();
if (empty($tokens) === true) {
if (PHP_CODESNIFFER_VERBOSITY === 1) {
$startTime = microtime(true);
echo 'CODE report is parsing ' . basename($file) . ' ';
}
else {
if (PHP_CODESNIFFER_VERBOSITY > 1) {
echo "CODE report is forcing parse of {$file}" . PHP_EOL;
}
}
try {
$phpcsFile->parse();
} catch (Exception $e) {
// This is a second parse, so ignore exceptions.
// They would have been added to the file's error list already.
}
if (PHP_CODESNIFFER_VERBOSITY === 1) {
$timeTaken = (microtime(true) - $startTime) * 1000;
if ($timeTaken < 1000) {
$timeTaken = round($timeTaken);
echo "DONE in {$timeTaken}ms";
}
else {
$timeTaken = round($timeTaken / 1000, 2);
echo "DONE in {$timeTaken} secs";
}
echo PHP_EOL;
}
$tokens = $phpcsFile->getTokens();
}
//end if
// Create an array that maps lines to the first token on the line.
$lineTokens = [];
$lastLine = 0;
$stackPtr = 0;
foreach ($tokens as $stackPtr => $token) {
if ($token['line'] !== $lastLine) {
if ($lastLine > 0) {
$lineTokens[$lastLine]['end'] = $stackPtr - 1;
}
$lastLine++;
$lineTokens[$lastLine] = [
'start' => $stackPtr,
'end' => null,
];
}
}
// Make sure the last token in the file sits on an imaginary
// last line so it is easier to generate code snippets at the
// end of the file.
$lineTokens[$lastLine]['end'] = $stackPtr;
// Determine the longest code line we will be showing.
$maxSnippetLength = 0;
$eolLen = strlen($phpcsFile->eolChar);
foreach ($report['messages'] as $line => $lineErrors) {
$startLine = max($line - $surroundingLines, 1);
$endLine = min($line + $surroundingLines, $lastLine);
$maxLineNumLength = strlen($endLine);
for ($i = $startLine; $i <= $endLine; $i++) {
if ($i === 1) {
continue;
}
$lineLength = $tokens[$lineTokens[$i]['start'] - 1]['column'] + $tokens[$lineTokens[$i]['start'] - 1]['length'] - $eolLen;
$maxSnippetLength = max($lineLength, $maxSnippetLength);
}
}
$maxSnippetLength += $maxLineNumLength + 8;
// Determine the longest error message we will be showing.
$maxErrorLength = 0;
foreach ($report['messages'] as $lineErrors) {
foreach ($lineErrors as $colErrors) {
foreach ($colErrors as $error) {
$length = strlen($error['message']);
if ($showSources === true) {
$length += strlen($error['source']) + 3;
}
$maxErrorLength = max($maxErrorLength, $length + 1);
}
}
}
// The padding that all lines will require that are printing an error message overflow.
if ($report['warnings'] > 0) {
$typeLength = 7;
}
else {
$typeLength = 5;
}
$errorPadding = str_repeat(' ', $maxLineNumLength + 7);
$errorPadding .= str_repeat(' ', $typeLength);
$errorPadding .= ' ';
if ($report['fixable'] > 0) {
$errorPadding .= ' ';
}
$errorPaddingLength = strlen($errorPadding);
// The maximum amount of space an error message can use.
$maxErrorSpace = $width - $errorPaddingLength;
if ($showSources === true) {
// Account for the chars used to print colors.
$maxErrorSpace += 8;
}
// Figure out the max report width we need and can use.
$fileLength = strlen($file);
$maxWidth = max($fileLength + 6, $maxErrorLength + $errorPaddingLength);
$width = max(min($width, $maxWidth), $maxSnippetLength);
if ($width < 70) {
$width = 70;
}
// Print the file header.
echo PHP_EOL . "\x1b[1mFILE: ";
if ($fileLength <= $width - 6) {
echo $file;
}
else {
echo '...' . substr($file, $fileLength - ($width - 6));
}
echo "\x1b[0m" . PHP_EOL;
echo str_repeat('-', $width) . PHP_EOL;
echo "\x1b[1m" . 'FOUND ' . $report['errors'] . ' ERROR';
if ($report['errors'] !== 1) {
echo 'S';
}
if ($report['warnings'] > 0) {
echo ' AND ' . $report['warnings'] . ' WARNING';
if ($report['warnings'] !== 1) {
echo 'S';
}
}
echo ' AFFECTING ' . count($report['messages']) . ' LINE';
if (count($report['messages']) !== 1) {
echo 'S';
}
echo "\x1b[0m" . PHP_EOL;
foreach ($report['messages'] as $line => $lineErrors) {
$startLine = max($line - $surroundingLines, 1);
$endLine = min($line + $surroundingLines, $lastLine);
$snippet = '';
if (isset($lineTokens[$startLine]) === true) {
for ($i = $lineTokens[$startLine]['start']; $i <= $lineTokens[$endLine]['end']; $i++) {
$snippetLine = $tokens[$i]['line'];
if ($lineTokens[$snippetLine]['start'] === $i) {
// Starting a new line.
if ($snippetLine === $line) {
$snippet .= "\x1b[1m" . '>> ';
}
else {
$snippet .= ' ';
}
$snippet .= str_repeat(' ', $maxLineNumLength - strlen($snippetLine));
$snippet .= $snippetLine . ': ';
if ($snippetLine === $line) {
$snippet .= "\x1b[0m";
}
}
if (isset($tokens[$i]['orig_content']) === true) {
$tokenContent = $tokens[$i]['orig_content'];
}
else {
$tokenContent = $tokens[$i]['content'];
}
if (strpos($tokenContent, "\t") !== false) {
$token = $tokens[$i];
$token['content'] = $tokenContent;
if (stripos(PHP_OS, 'WIN') === 0) {
$tab = "\x00";
}
else {
$tab = "\x1b[30;1m»\x1b[0m";
}
$phpcsFile->tokenizer
->replaceTabsInToken($token, $tab, "\x00");
$tokenContent = $token['content'];
}
$tokenContent = Common::prepareForOutput($tokenContent, [
"\r",
"\n",
"\t",
]);
$tokenContent = str_replace("\x00", ' ', $tokenContent);
$underline = false;
if ($snippetLine === $line && isset($lineErrors[$tokens[$i]['column']]) === true) {
$underline = true;
}
// Underline invisible characters as well.
if ($underline === true && trim($tokenContent) === '') {
$snippet .= "\x1b[4m" . ' ' . "\x1b[0m" . $tokenContent;
}
else {
if ($underline === true) {
$snippet .= "\x1b[4m";
}
$snippet .= $tokenContent;
if ($underline === true) {
$snippet .= "\x1b[0m";
}
}
}
//end for
}
//end if
echo str_repeat('-', $width) . PHP_EOL;
foreach ($lineErrors as $colErrors) {
foreach ($colErrors as $error) {
$padding = $maxLineNumLength - strlen($line);
echo 'LINE ' . str_repeat(' ', $padding) . $line . ': ';
if ($error['type'] === 'ERROR') {
echo "\x1b[31mERROR\x1b[0m";
if ($report['warnings'] > 0) {
echo ' ';
}
}
else {
echo "\x1b[33mWARNING\x1b[0m";
}
echo ' ';
if ($report['fixable'] > 0) {
echo '[';
if ($error['fixable'] === true) {
echo 'x';
}
else {
echo ' ';
}
echo '] ';
}
$message = $error['message'];
$message = str_replace("\n", "\n" . $errorPadding, $message);
if ($showSources === true) {
$message = "\x1b[1m" . $message . "\x1b[0m" . ' (' . $error['source'] . ')';
}
$errorMsg = wordwrap($message, $maxErrorSpace, PHP_EOL . $errorPadding);
echo $errorMsg . PHP_EOL;
}
//end foreach
}
//end foreach
echo str_repeat('-', $width) . PHP_EOL;
echo rtrim($snippet) . PHP_EOL;
}
//end foreach
echo str_repeat('-', $width) . PHP_EOL;
if ($report['fixable'] > 0) {
echo "\x1b[1m" . 'PHPCBF CAN FIX THE ' . $report['fixable'] . ' MARKED SNIFF VIOLATIONS AUTOMATICALLY' . "\x1b[0m" . PHP_EOL;
echo str_repeat('-', $width) . PHP_EOL;
}
return true;
}