DiffFormatter.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace Drupal\Core\Diff;
  3. use Drupal\Component\Diff\DiffFormatter as DiffFormatterBase;
  4. use Drupal\Component\Diff\WordLevelDiff;
  5. use Drupal\Component\Utility\Html;
  6. use Drupal\Core\Config\ConfigFactoryInterface;
  7. /**
  8. * Diff formatter which uses returns output that can be rendered to a table.
  9. */
  10. class DiffFormatter extends DiffFormatterBase {
  11. /**
  12. * The diff represented as an array of rows.
  13. *
  14. * @var array
  15. */
  16. protected $rows = [];
  17. /**
  18. * Creates a DiffFormatter to render diffs in a table.
  19. *
  20. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
  21. * The config factory.
  22. */
  23. public function __construct(ConfigFactoryInterface $config_factory) {
  24. $config = $config_factory->get('system.diff');
  25. $this->leading_context_lines = $config->get('context.lines_leading');
  26. $this->trailing_context_lines = $config->get('context.lines_trailing');
  27. }
  28. /**
  29. * {@inheritdoc}
  30. */
  31. protected function _start_diff() {
  32. $this->rows = [];
  33. }
  34. /**
  35. * {@inheritdoc}
  36. */
  37. protected function _end_diff() {
  38. return $this->rows;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. protected function _block_header($xbeg, $xlen, $ybeg, $ylen) {
  44. return [
  45. [
  46. 'data' => $xbeg + $this->line_stats['offset']['x'],
  47. 'colspan' => 2,
  48. ],
  49. [
  50. 'data' => $ybeg + $this->line_stats['offset']['y'],
  51. 'colspan' => 2,
  52. ],
  53. ];
  54. }
  55. /**
  56. * {@inheritdoc}
  57. */
  58. protected function _start_block($header) {
  59. if ($this->show_header) {
  60. $this->rows[] = $header;
  61. }
  62. }
  63. /**
  64. * {@inheritdoc}
  65. */
  66. protected function _lines($lines, $prefix = ' ', $color = 'white') {
  67. }
  68. /**
  69. * Creates an added line.
  70. *
  71. * @param string $line
  72. * An HTML-escaped line.
  73. *
  74. * @return array
  75. * An array representing a table row.
  76. */
  77. protected function addedLine($line) {
  78. return [
  79. [
  80. 'data' => '+',
  81. 'class' => 'diff-marker',
  82. ],
  83. [
  84. 'data' => ['#markup' => $line],
  85. 'class' => 'diff-context diff-addedline',
  86. ],
  87. ];
  88. }
  89. /**
  90. * Creates a deleted line.
  91. *
  92. * @param string $line
  93. * An HTML-escaped line.
  94. *
  95. * @return array
  96. * An array representing a table row.
  97. */
  98. protected function deletedLine($line) {
  99. return [
  100. [
  101. 'data' => '-',
  102. 'class' => 'diff-marker',
  103. ],
  104. [
  105. 'data' => ['#markup' => $line],
  106. 'class' => 'diff-context diff-deletedline',
  107. ],
  108. ];
  109. }
  110. /**
  111. * Creates a context line.
  112. *
  113. * @param string $line
  114. * An HTML-escaped line.
  115. *
  116. * @return array
  117. * An array representing a table row.
  118. */
  119. protected function contextLine($line) {
  120. return [
  121. ' ',
  122. [
  123. 'data' => ['#markup' => $line],
  124. 'class' => 'diff-context',
  125. ],
  126. ];
  127. }
  128. /**
  129. * Creates an empty line.
  130. *
  131. * @return array
  132. * An array representing a table row.
  133. */
  134. protected function emptyLine() {
  135. return [
  136. ' ',
  137. ' ',
  138. ];
  139. }
  140. /**
  141. * {@inheritdoc}
  142. */
  143. protected function _added($lines) {
  144. foreach ($lines as $line) {
  145. $this->rows[] = array_merge($this->emptyLine(), $this->addedLine(Html::escape($line)));
  146. }
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. protected function _deleted($lines) {
  152. foreach ($lines as $line) {
  153. $this->rows[] = array_merge($this->deletedLine(Html::escape($line)), $this->emptyLine());
  154. }
  155. }
  156. /**
  157. * {@inheritdoc}
  158. */
  159. protected function _context($lines) {
  160. foreach ($lines as $line) {
  161. $this->rows[] = array_merge($this->contextLine(Html::escape($line)), $this->contextLine(Html::escape($line)));
  162. }
  163. }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. protected function _changed($orig, $closing) {
  168. $orig = array_map('\Drupal\Component\Utility\Html::escape', $orig);
  169. $closing = array_map('\Drupal\Component\Utility\Html::escape', $closing);
  170. $diff = new WordLevelDiff($orig, $closing);
  171. $del = $diff->orig();
  172. $add = $diff->closing();
  173. // Notice that WordLevelDiff returns HTML-escaped output. Hence, we will be
  174. // calling addedLine/deletedLine without HTML-escaping.
  175. while ($line = array_shift($del)) {
  176. $aline = array_shift($add);
  177. $this->rows[] = array_merge($this->deletedLine($line), isset($aline) ? $this->addedLine($aline) : $this->emptyLine());
  178. }
  179. // If any leftovers.
  180. foreach ($add as $line) {
  181. $this->rows[] = array_merge($this->emptyLine(), $this->addedLine($line));
  182. }
  183. }
  184. }