AbstractAlignFixerHelper.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer;
  12. use PhpCsFixer\Tokenizer\Tokens;
  13. /**
  14. * @author Carlos Cirello <carlos.cirello.nl@gmail.com>
  15. *
  16. * @internal
  17. *
  18. * @deprecated
  19. */
  20. abstract class AbstractAlignFixerHelper
  21. {
  22. /**
  23. * @const Placeholder used as anchor for right alignment.
  24. */
  25. const ALIGNABLE_PLACEHOLDER = "\x2 ALIGNABLE%d \x3";
  26. /**
  27. * Keep track of the deepest level ever achieved while
  28. * parsing the code. Used later to replace alignment
  29. * placeholders with spaces.
  30. *
  31. * @var int
  32. */
  33. protected $deepestLevel = 0;
  34. public function fix(Tokens $tokens)
  35. {
  36. // This fixer works partially on Tokens and partially on string representation of code.
  37. // During the process of fixing internal state of single Token may be affected by injecting ALIGNABLE_PLACEHOLDER to its content.
  38. // The placeholder will be resolved by `replacePlaceholder` method by removing placeholder or changing it into spaces.
  39. // That way of fixing the code causes disturbances in marking Token as changed - if code is perfectly valid then placeholder
  40. // still be injected and removed, which will cause the `changed` flag to be set.
  41. // To handle that unwanted behavior we work on clone of Tokens collection and then override original collection with fixed collection.
  42. $tokensClone = clone $tokens;
  43. $this->injectAlignmentPlaceholders($tokensClone, 0, \count($tokens));
  44. $content = $this->replacePlaceholder($tokensClone);
  45. $tokens->setCode($content);
  46. }
  47. /**
  48. * Inject into the text placeholders of candidates of vertical alignment.
  49. *
  50. * @param int $startAt
  51. * @param int $endAt
  52. */
  53. abstract protected function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt);
  54. /**
  55. * Look for group of placeholders, and provide vertical alignment.
  56. *
  57. * @return string
  58. */
  59. protected function replacePlaceholder(Tokens $tokens)
  60. {
  61. $tmpCode = $tokens->generateCode();
  62. for ($j = 0; $j <= $this->deepestLevel; ++$j) {
  63. $placeholder = sprintf(self::ALIGNABLE_PLACEHOLDER, $j);
  64. if (false === strpos($tmpCode, $placeholder)) {
  65. continue;
  66. }
  67. $lines = explode("\n", $tmpCode);
  68. $linesWithPlaceholder = [];
  69. $blockSize = 0;
  70. $linesWithPlaceholder[$blockSize] = [];
  71. foreach ($lines as $index => $line) {
  72. if (substr_count($line, $placeholder) > 0) {
  73. $linesWithPlaceholder[$blockSize][] = $index;
  74. } else {
  75. ++$blockSize;
  76. $linesWithPlaceholder[$blockSize] = [];
  77. }
  78. }
  79. foreach ($linesWithPlaceholder as $group) {
  80. if (\count($group) < 1) {
  81. continue;
  82. }
  83. $rightmostSymbol = 0;
  84. foreach ($group as $index) {
  85. $rightmostSymbol = max($rightmostSymbol, strpos(utf8_decode($lines[$index]), $placeholder));
  86. }
  87. foreach ($group as $index) {
  88. $line = $lines[$index];
  89. $currentSymbol = strpos(utf8_decode($line), $placeholder);
  90. $delta = abs($rightmostSymbol - $currentSymbol);
  91. if ($delta > 0) {
  92. $line = str_replace($placeholder, str_repeat(' ', $delta).$placeholder, $line);
  93. $lines[$index] = $line;
  94. }
  95. }
  96. }
  97. $tmpCode = str_replace($placeholder, '', implode("\n", $lines));
  98. }
  99. return $tmpCode;
  100. }
  101. }