View source
<?php
namespace Drupal\Sniffs\WhiteSpace;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Util\Tokens;
class ScopeIndentSniff implements Sniff {
public $supportedTokenizers = array(
'PHP',
);
public $indent = 2;
public $exact = true;
public $tabIndent = false;
private $_tabWidth = null;
public $ignoreIndentationTokens = array();
private $_ignoreIndentationTokens = array();
protected $nonIndentingScopes = array();
private $_debug = false;
public function register() {
if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
$this->_debug = false;
}
return array(
T_OPEN_TAG,
);
}
public function process(File $phpcsFile, $stackPtr) {
$debug = Config::getConfigData('scope_indent_debug');
if ($debug !== null) {
$this->_debug = (bool) $debug;
}
if ($this->_tabWidth === null) {
$config = $phpcsFile->config;
if (isset($config->tabWidth) === false || $config->tabWidth === 0) {
$this->_tabWidth = 4;
}
else {
$this->_tabWidth = $config->tabWidth;
}
}
$currentIndent = 0;
$lastOpenTag = $stackPtr;
$lastCloseTag = null;
$openScopes = array();
$adjustments = array();
$setIndents = array();
$tokens = $phpcsFile
->getTokens();
$first = $phpcsFile
->findFirstOnLine(T_INLINE_HTML, $stackPtr);
$trimmed = ltrim($tokens[$first]['content']);
if ($trimmed === '') {
$currentIndent = $tokens[$stackPtr]['column'] - 1;
}
else {
$currentIndent = strlen($tokens[$first]['content']) - strlen($trimmed);
}
if ($this->_debug === true) {
$line = $tokens[$stackPtr]['line'];
echo "Start with token {$stackPtr} on line {$line} with indent {$currentIndent}" . PHP_EOL;
}
if (empty($this->_ignoreIndentationTokens) === true) {
$this->_ignoreIndentationTokens = array(
T_INLINE_HTML => true,
);
foreach ($this->ignoreIndentationTokens as $token) {
if (is_int($token) === false) {
if (defined($token) === false) {
continue;
}
$token = constant($token);
}
$this->_ignoreIndentationTokens[$token] = true;
}
}
$this->exact = (bool) $this->exact;
$this->tabIndent = (bool) $this->tabIndent;
for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) {
if ($i === false) {
break;
}
$checkToken = null;
$checkIndent = null;
$exact = (bool) $this->exact;
if ($exact === true && isset($tokens[$i]['nested_parenthesis']) === true) {
$exact = false;
}
if ($tokens[$i]['column'] === 1) {
$trimmed = ltrim($tokens[$i]['content']);
if ($trimmed === '') {
if (isset($tokens[$i + 1]) === true && $tokens[$i]['line'] === $tokens[$i + 1]['line']) {
$checkToken = $i + 1;
$tokenIndent = $tokens[$i + 1]['column'] - 1;
}
}
else {
$checkToken = $i;
$tokenIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
}
}
if ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$checkToken]['parenthesis_opener']) === true || $tokens[$i]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$i]['parenthesis_opener']) === true) {
if ($checkToken !== null) {
$parenCloser = $checkToken;
}
else {
$parenCloser = $i;
}
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Closing parenthesis found on line {$line}" . PHP_EOL;
}
$parenOpener = $tokens[$parenCloser]['parenthesis_opener'];
if ($tokens[$parenCloser]['line'] !== $tokens[$parenOpener]['line']) {
$parens = 0;
if (isset($tokens[$parenCloser]['nested_parenthesis']) === true && empty($tokens[$parenCloser]['nested_parenthesis']) === false) {
end($tokens[$parenCloser]['nested_parenthesis']);
$parens = key($tokens[$parenCloser]['nested_parenthesis']);
if ($this->_debug === true) {
$line = $tokens[$parens]['line'];
echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
}
}
$condition = 0;
if (isset($tokens[$parenCloser]['conditions']) === true && empty($tokens[$parenCloser]['conditions']) === false) {
end($tokens[$parenCloser]['conditions']);
$condition = key($tokens[$parenCloser]['conditions']);
if ($this->_debug === true) {
$line = $tokens[$condition]['line'];
$type = $tokens[$condition]['type'];
echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
}
}
if ($parens > $condition) {
if ($this->_debug === true) {
echo "\t* using parenthesis *" . PHP_EOL;
}
$parenOpener = $parens;
$condition = 0;
}
else {
if ($condition > 0) {
if ($this->_debug === true) {
echo "\t* using condition *" . PHP_EOL;
}
$parenOpener = $condition;
$parens = 0;
}
}
$exact = false;
$lastOpenTagConditions = array_keys($tokens[$lastOpenTag]['conditions']);
$lastOpenTagCondition = array_pop($lastOpenTagConditions);
if ($condition > 0 && $lastOpenTagCondition === $condition) {
if ($this->_debug === true) {
echo "\t* open tag is inside condition; using open tag *" . PHP_EOL;
}
$checkIndent = $tokens[$lastOpenTag]['column'] - 1;
if (isset($adjustments[$condition]) === true) {
$checkIndent += $adjustments[$condition];
}
$currentIndent = $checkIndent;
if ($this->_debug === true) {
$type = $tokens[$lastOpenTag]['type'];
echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$lastOpenTag} ({$type})" . PHP_EOL;
}
}
else {
if ($condition > 0 && isset($tokens[$condition]['scope_opener']) === true && isset($setIndents[$tokens[$condition]['scope_opener']]) === true) {
$checkIndent = $setIndents[$tokens[$condition]['scope_opener']];
if (isset($adjustments[$condition]) === true) {
$checkIndent += $adjustments[$condition];
}
$currentIndent = $checkIndent;
if ($this->_debug === true) {
$type = $tokens[$condition]['type'];
echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$condition} ({$type})" . PHP_EOL;
}
}
else {
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $parenOpener, true);
$checkIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$checkIndent += $adjustments[$first];
}
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
}
if ($first === $tokens[$parenCloser]['parenthesis_opener']) {
$first--;
}
$prev = $phpcsFile
->findStartOfStatement($first, T_COMMA);
if ($prev !== $first) {
if ($this->_debug === true) {
$line = $tokens[$prev]['line'];
$type = $tokens[$prev]['type'];
echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
$prev = $phpcsFile
->findStartOfStatement($first, T_COMMA);
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
}
}
if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
if ($this->_debug === true) {
echo "\t* first token is a scope closer *" . PHP_EOL;
}
if (isset($tokens[$first]['scope_condition']) === true) {
$scopeCloser = $first;
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
$currentIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
}
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
}
}
else {
$currentIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
}
}
}
}
else {
if ($this->_debug === true) {
echo "\t * ignoring single-line definition *" . PHP_EOL;
}
}
}
if ($tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY || $checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) {
if ($checkToken !== null) {
$arrayCloser = $checkToken;
}
else {
$arrayCloser = $i;
}
if ($this->_debug === true) {
$line = $tokens[$arrayCloser]['line'];
echo "Closing short array bracket found on line {$line}" . PHP_EOL;
}
$arrayOpener = $tokens[$arrayCloser]['bracket_opener'];
if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) {
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
$checkIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$checkIndent += $adjustments[$first];
}
$exact = false;
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
}
if ($first === $tokens[$arrayCloser]['bracket_opener']) {
$first--;
}
$prev = $phpcsFile
->findStartOfStatement($first, T_COMMA);
if ($prev !== $first) {
if ($this->_debug === true) {
$line = $tokens[$prev]['line'];
$type = $tokens[$prev]['type'];
echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
$prev = $phpcsFile
->findStartOfStatement($first, T_COMMA);
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
}
}
if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
if ($this->_debug === true) {
echo "\t* first token is a scope closer; ignoring closing short array bracket *" . PHP_EOL;
}
if (isset($setIndents[$first]) === true) {
$currentIndent = $setIndents[$first];
if ($this->_debug === true) {
echo "\t=> indent reset to {$currentIndent}" . PHP_EOL;
}
}
}
else {
$currentIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
}
}
else {
if ($this->_debug === true) {
echo "\t * ignoring single-line definition *" . PHP_EOL;
}
}
}
if ($checkToken !== null && $exact === false && (empty($tokens[$checkToken]['conditions']) === false || isset($tokens[$checkToken]['scope_opener']) === true && $tokens[$checkToken]['scope_opener'] === $checkToken)) {
if (empty($tokens[$checkToken]['conditions']) === false) {
end($tokens[$checkToken]['conditions']);
$condition = key($tokens[$checkToken]['conditions']);
}
else {
$condition = $tokens[$checkToken]['scope_condition'];
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $condition, true);
if (isset($adjustments[$first]) === true && ($adjustments[$first] < 0 && $tokenIndent > $currentIndent || $adjustments[$first] > 0 && $tokenIndent < $currentIndent)) {
$padding = $tokenIndent + $adjustments[$first];
if ($padding > 0) {
if ($this->tabIndent === true) {
$numTabs = floor($padding / $this->_tabWidth);
$numSpaces = $padding - $numTabs * $this->_tabWidth;
$padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
}
else {
$padding = str_repeat(' ', $padding);
}
}
else {
$padding = '';
}
if ($checkToken === $i) {
$phpcsFile->fixer
->replaceToken($checkToken, $padding . $trimmed);
}
else {
$phpcsFile->fixer
->replaceToken($checkToken - 1, $padding);
}
if ($this->_debug === true) {
$length = strlen($padding);
$line = $tokens[$checkToken]['line'];
$type = $tokens[$checkToken]['type'];
echo "Indent adjusted to {$length} for {$type} on line {$line}" . PHP_EOL;
}
$adjustments[$checkToken] = $adjustments[$first];
if ($this->_debug === true) {
$line = $tokens[$checkToken]['line'];
$type = $tokens[$checkToken]['type'];
echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
}
}
}
if ($checkToken !== null && isset($openScopes[$checkToken]) === true || isset($tokens[$checkToken]['scope_condition']) === true && isset($tokens[$checkToken]['scope_closer']) === true && $tokens[$checkToken]['scope_closer'] === $checkToken && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'] || ($checkToken === null && isset($openScopes[$i]) === true || isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_closer']) === true && $tokens[$i]['scope_closer'] === $i && $tokens[$i]['line'] !== $tokens[$tokens[$i]['scope_opener']]['line'])) {
if ($this->_debug === true) {
if ($checkToken === null) {
$type = $tokens[$tokens[$i]['scope_condition']]['type'];
$line = $tokens[$i]['line'];
}
else {
$type = $tokens[$tokens[$checkToken]['scope_condition']]['type'];
$line = $tokens[$checkToken]['line'];
}
echo "Close scope ({$type}) on line {$line}" . PHP_EOL;
}
$scopeCloser = $checkToken;
if ($scopeCloser === null) {
$scopeCloser = $i;
}
else {
array_pop($openScopes);
}
if (isset($tokens[$scopeCloser]['scope_condition']) === true) {
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
$currentIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
}
$setIndents[$scopeCloser] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$scopeCloser]['type'];
echo "\t=> indent set to {$currentIndent} by token {$scopeCloser} ({$type})" . PHP_EOL;
}
if ($tokens[$scopeCloser]['code'] === T_CLOSE_CURLY_BRACKET) {
$exact = true;
}
else {
$checkToken = null;
}
}
}
if ($phpcsFile->tokenizerType === 'JS' && ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_OBJECT && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['bracket_opener']]['line'] || $checkToken === null && $tokens[$i]['code'] === T_CLOSE_OBJECT && $tokens[$i]['line'] !== $tokens[$tokens[$i]['bracket_opener']]['line'])) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Close JS object on line {$line}" . PHP_EOL;
}
$scopeCloser = $checkToken;
if ($scopeCloser === null) {
$scopeCloser = $i;
}
else {
array_pop($openScopes);
}
$parens = 0;
if (isset($tokens[$scopeCloser]['nested_parenthesis']) === true && empty($tokens[$scopeCloser]['nested_parenthesis']) === false) {
end($tokens[$scopeCloser]['nested_parenthesis']);
$parens = key($tokens[$scopeCloser]['nested_parenthesis']);
if ($this->_debug === true) {
$line = $tokens[$parens]['line'];
echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
}
}
$condition = 0;
if (isset($tokens[$scopeCloser]['conditions']) === true && empty($tokens[$scopeCloser]['conditions']) === false) {
end($tokens[$scopeCloser]['conditions']);
$condition = key($tokens[$scopeCloser]['conditions']);
if ($this->_debug === true) {
$line = $tokens[$condition]['line'];
$type = $tokens[$condition]['type'];
echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
}
}
if ($parens > $condition) {
if ($this->_debug === true) {
echo "\t* using parenthesis *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $parens, true);
$condition = 0;
}
else {
if ($condition > 0) {
if ($this->_debug === true) {
echo "\t* using condition *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $condition, true);
$parens = 0;
}
else {
if ($this->_debug === true) {
$line = $tokens[$tokens[$scopeCloser]['bracket_opener']]['line'];
echo "\t* token is not in parenthesis or condition; using opener on line {$line} *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['bracket_opener'], true);
}
}
$currentIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
if ($parens > 0 || $condition > 0) {
$checkIndent = $tokens[$first]['column'] - 1;
if (isset($adjustments[$first]) === true) {
$checkIndent += $adjustments[$first];
}
if ($condition > 0) {
$checkIndent += $this->indent;
$currentIndent += $this->indent;
$exact = true;
}
}
else {
$checkIndent = $currentIndent;
}
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
$checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
}
if ($checkToken !== null && isset(Tokens::$scopeOpeners[$tokens[$checkToken]['code']]) === true && in_array($tokens[$checkToken]['code'], $this->nonIndentingScopes) === false && isset($tokens[$checkToken]['scope_opener']) === true) {
$exact = true;
$lastOpener = null;
if (empty($openScopes) === false) {
end($openScopes);
$lastOpener = current($openScopes);
}
if ($lastOpener !== null && isset($tokens[$lastOpener]['scope_closer']) === true && $tokens[$lastOpener]['level'] === $tokens[$checkToken]['level'] && $tokens[$lastOpener]['scope_closer'] === $tokens[$checkToken]['scope_closer']) {
$currentIndent -= $this->indent;
$setIndents[$lastOpener] = $currentIndent;
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$lastOpener]['type'];
echo "Shared closer found on line {$line}" . PHP_EOL;
echo "\t=> indent set to {$currentIndent} by token {$lastOpener} ({$type})" . PHP_EOL;
}
}
if ($tokens[$checkToken]['code'] === T_CLOSURE && $tokenIndent > $currentIndent) {
$checkIndent = (int) (ceil($tokenIndent / $this->indent) * $this->indent);
$exact = false;
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Closure found on line {$line}" . PHP_EOL;
echo "\t=> checking indent of {$checkIndent}; main indent remains at {$currentIndent}" . PHP_EOL;
}
}
}
if ($checkToken !== null && isset(Tokens::$methodPrefixes[$tokens[$checkToken]['code']]) === true && $tokens[$checkToken + 1]['code'] !== T_DOUBLE_COLON) {
$exact = true;
}
if ($checkToken !== null && $tokens[$checkToken]['code'] === T_PROPERTY) {
$exact = true;
}
if ($checkToken !== null && ($tokens[$checkToken]['code'] === T_OPEN_TAG || $tokens[$checkToken]['code'] === T_OPEN_TAG_WITH_ECHO || $tokens[$checkToken]['code'] === T_CLOSE_TAG)) {
$exact = true;
$checkIndent = $tokens[$checkToken]['column'] - 1;
$checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
}
if ($checkIndent === null) {
$checkIndent = $currentIndent;
}
if ($checkToken !== null && $tokens[$checkToken]['code'] === T_OBJECT_OPERATOR) {
$checkIndent += $this->indent;
}
if ($checkToken !== null && $tokens[$checkToken]['code'] === T_COMMENT) {
$content = trim($tokens[$checkToken]['content']);
if ($content[0] === '*') {
$checkIndent += 1;
}
}
$adjusted = false;
if ($checkToken !== null && isset($this->_ignoreIndentationTokens[$tokens[$checkToken]['code']]) === false && ($tokenIndent !== $checkIndent && $exact === true || $tokenIndent < $checkIndent && $exact === false)) {
if ($tokenIndent > $checkIndent) {
$before = $phpcsFile
->findPrevious(Tokens::$emptyTokens, $checkToken - 1, null, true);
if ($before !== false && in_array($tokens[$before]['code'], array(
T_SEMICOLON,
T_CLOSE_CURLY_BRACKET,
T_OPEN_CURLY_BRACKET,
T_COLON,
)) === false) {
continue;
}
}
if ($tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$checkToken]['parenthesis_owner']) === true && $tokens[$tokens[$checkToken]['parenthesis_owner']]['code'] === T_ARRAY || $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) {
continue;
}
$type = 'IncorrectExact';
$error = 'Line indented incorrectly; expected ';
if ($exact === false) {
$error .= 'at least ';
$type = 'Incorrect';
}
if ($this->tabIndent === true) {
$error .= '%s tabs, found %s';
$data = array(
floor($checkIndent / $this->_tabWidth),
floor($tokenIndent / $this->_tabWidth),
);
}
else {
$error .= '%s spaces, found %s';
$data = array(
$checkIndent,
$tokenIndent,
);
}
if ($this->_debug === true) {
$line = $tokens[$checkToken]['line'];
$message = vsprintf($error, $data);
echo "[Line {$line}] {$message}" . PHP_EOL;
}
$fix = $phpcsFile
->addFixableError($error, $checkToken, $type, $data);
if ($fix === true || $this->_debug === true) {
$padding = '';
if ($this->tabIndent === true) {
$numTabs = floor($checkIndent / $this->_tabWidth);
if ($numTabs > 0) {
$numSpaces = $checkIndent - $numTabs * $this->_tabWidth;
$padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
}
}
else {
if ($checkIndent > 0) {
$padding = str_repeat(' ', $checkIndent);
}
}
if ($checkToken === $i) {
$accepted = $phpcsFile->fixer
->replaceToken($checkToken, $padding . $trimmed);
}
else {
$accepted = $phpcsFile->fixer
->replaceToken($checkToken - 1, $padding);
}
if ($accepted === true) {
$adjustments[$checkToken] = $checkIndent - $tokenIndent;
if ($this->_debug === true) {
$line = $tokens[$checkToken]['line'];
$type = $tokens[$checkToken]['type'];
echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
}
}
}
else {
$adjustments[$checkToken] = $checkIndent - $tokenIndent;
}
}
if ($checkToken !== null) {
$i = $checkToken;
}
if ($tokens[$i]['code'] === T_START_HEREDOC || $tokens[$i]['code'] === T_START_NOWDOC) {
$i = $phpcsFile
->findNext(array(
T_END_HEREDOC,
T_END_NOWDOC,
), $i + 1);
continue;
}
if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING || $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING) {
$i = $phpcsFile
->findNext($tokens[$i]['code'], $i + 1, null, true);
$i--;
continue;
}
if ($tokens[$i]['code'] === T_DOC_COMMENT_OPEN_TAG) {
$i = $tokens[$i]['comment_closer'];
continue;
}
if ($tokens[$i]['code'] === T_OPEN_TAG || $tokens[$i]['code'] === T_OPEN_TAG_WITH_ECHO) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Open PHP tag found on line {$line}" . PHP_EOL;
}
if ($checkToken === null) {
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $i, true);
$currentIndent = strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']));
}
else {
$currentIndent = $tokens[$i]['column'] - 1;
}
$lastOpenTag = $i;
if (isset($adjustments[$i]) === true) {
$currentIndent += $adjustments[$i];
}
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
$setIndents[$i] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$i]['type'];
echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
}
continue;
}
if ($tokens[$i]['code'] === T_CLOSE_TAG) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Close PHP tag found on line {$line}" . PHP_EOL;
}
if ($tokens[$lastOpenTag]['line'] !== $tokens[$i]['line']) {
$currentIndent = $tokens[$i]['column'] - 1;
$lastCloseTag = $i;
}
else {
if ($lastCloseTag === null) {
$currentIndent = 0;
}
else {
$currentIndent = $tokens[$lastCloseTag]['column'] - 1;
}
}
if (isset($adjustments[$i]) === true) {
$currentIndent += $adjustments[$i];
}
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
$setIndents[$i] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$i]['type'];
echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
}
continue;
}
if ($tokens[$i]['code'] === T_CLOSURE || $tokens[$i]['code'] === T_ANON_CLASS) {
$closer = $tokens[$i]['scope_closer'];
if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
if ($this->_debug === true) {
$type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
$line = $tokens[$i]['line'];
echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
}
$i = $closer;
continue;
}
if ($this->_debug === true) {
$type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
$line = $tokens[$i]['line'];
echo "Open {$type} on line {$line}" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $i, true);
$currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
$currentIndent = (int) (floor($currentIndent / $this->indent) * $this->indent);
$i = $tokens[$i]['scope_opener'];
$setIndents[$i] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$i]['type'];
echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
}
continue;
}
if (isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_opener']) === true && $tokens[$i]['scope_opener'] === $i) {
$closer = $tokens[$i]['scope_closer'];
if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$i]['type'];
echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
}
$i = $closer;
continue;
}
$condition = $tokens[$tokens[$i]['scope_condition']]['code'];
if (isset(Tokens::$scopeOpeners[$condition]) === true && in_array($condition, $this->nonIndentingScopes) === false) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$tokens[$i]['scope_condition']]['type'];
echo "Open scope ({$type}) on line {$line}" . PHP_EOL;
}
$currentIndent += $this->indent;
$setIndents[$i] = $currentIndent;
$openScopes[$tokens[$i]['scope_closer']] = $tokens[$i]['scope_condition'];
if ($this->_debug === true) {
$type = $tokens[$i]['type'];
echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
}
continue;
}
}
if ($phpcsFile->tokenizerType === 'JS' && $tokens[$i]['code'] === T_OBJECT) {
$closer = $tokens[$i]['bracket_closer'];
if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "* ignoring single-line JS object on line {$line}" . PHP_EOL;
}
$i = $closer;
continue;
}
if ($this->_debug === true) {
$line = $tokens[$i]['line'];
echo "Open JS object on line {$line}" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $i, true);
$currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
if (isset($adjustments[$first]) === true) {
$currentIndent += $adjustments[$first];
}
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
continue;
}
if (isset($tokens[$i]['scope_condition']) === true && $tokens[$i]['scope_closer'] === $i && ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE || $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS)) {
if ($this->_debug === true) {
$type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2)));
$line = $tokens[$i]['line'];
echo "Close {$type} on line {$line}" . PHP_EOL;
}
$prev = false;
$object = 0;
if ($phpcsFile->tokenizerType === 'JS') {
$conditions = $tokens[$i]['conditions'];
krsort($conditions, SORT_NUMERIC);
foreach ($conditions as $token => $condition) {
if ($condition === T_OBJECT) {
$object = $token;
break;
}
}
if ($this->_debug === true && $object !== 0) {
$line = $tokens[$object]['line'];
echo "\t* token is inside JS object {$object} on line {$line} *" . PHP_EOL;
}
}
$parens = 0;
if (isset($tokens[$i]['nested_parenthesis']) === true && empty($tokens[$i]['nested_parenthesis']) === false) {
end($tokens[$i]['nested_parenthesis']);
$parens = key($tokens[$i]['nested_parenthesis']);
if ($this->_debug === true) {
$line = $tokens[$parens]['line'];
echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
}
}
$condition = 0;
if (isset($tokens[$i]['conditions']) === true && empty($tokens[$i]['conditions']) === false) {
end($tokens[$i]['conditions']);
$condition = key($tokens[$i]['conditions']);
if ($this->_debug === true) {
$line = $tokens[$condition]['line'];
$type = $tokens[$condition]['type'];
echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
}
}
if ($parens > $object && $parens > $condition) {
if ($this->_debug === true) {
echo "\t* using parenthesis *" . PHP_EOL;
}
$prev = $phpcsFile
->findPrevious(Tokens::$emptyTokens, $parens - 1, null, true);
$object = 0;
$condition = 0;
}
else {
if ($object > 0 && $object >= $condition) {
if ($this->_debug === true) {
echo "\t* using object *" . PHP_EOL;
}
$prev = $object;
$parens = 0;
$condition = 0;
}
else {
if ($condition > 0) {
if ($this->_debug === true) {
echo "\t* using condition *" . PHP_EOL;
}
$prev = $condition;
$object = 0;
$parens = 0;
}
}
}
if ($prev === false) {
$prev = $phpcsFile
->findPrevious(array(
T_EQUAL,
T_RETURN,
), $tokens[$i]['scope_condition'] - 1, null, false, null, true);
if ($prev === false) {
$prev = $i;
if ($this->_debug === true) {
echo "\t* could not find a previous T_EQUAL or T_RETURN token; will use current token *" . PHP_EOL;
}
}
}
if ($this->_debug === true) {
$line = $tokens[$prev]['line'];
$type = $tokens[$prev]['type'];
echo "\t* previous token is {$type} on line {$line} *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
}
$prev = $phpcsFile
->findStartOfStatement($first);
if ($prev !== $first) {
if ($this->_debug === true) {
$line = $tokens[$prev]['line'];
$type = $tokens[$prev]['type'];
echo "\t* amended previous is {$type} on line {$line} *" . PHP_EOL;
}
$first = $phpcsFile
->findFirstOnLine(T_WHITESPACE, $prev, true);
if ($this->_debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
}
}
$currentIndent = $tokens[$first]['column'] - 1;
if ($object > 0 || $condition > 0) {
$currentIndent += $this->indent;
}
if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
if ($this->_debug === true) {
echo "\t* first token is a scope closer *" . PHP_EOL;
}
if ($condition === 0 || $tokens[$condition]['scope_opener'] < $first) {
$currentIndent = $setIndents[$first];
}
else {
if ($this->_debug === true) {
echo "\t* ignoring scope closer *" . PHP_EOL;
}
}
}
$currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
$setIndents[$first] = $currentIndent;
if ($this->_debug === true) {
$type = $tokens[$first]['type'];
echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
}
}
}
return $phpcsFile->numTokens;
}
}