MediaWiki master
DiffFormatter.php
Go to the documentation of this file.
1<?php
13namespace Wikimedia\Diff;
14
15use UnexpectedValueException;
16
26abstract class DiffFormatter {
27
33 protected $leadingContextLines = 0;
34
40 protected $trailingContextLines = 0;
41
43 private $result = '';
44
52 public function format( $diff ) {
53 $xi = $yi = 1;
54 $block = false;
55 $context = [];
56
59
60 $this->startDiff();
61
62 // Initialize $x0 and $y0 to prevent IDEs from getting confused.
63 $x0 = $y0 = 0;
64 foreach ( $diff->edits as $edit ) {
65 if ( $edit->type == 'copy' ) {
66 if ( is_array( $block ) ) {
67 if ( count( $edit->orig ) <= $nlead + $ntrail ) {
68 $block[] = $edit;
69 } else {
70 if ( $ntrail ) {
71 $context = array_slice( $edit->orig, 0, $ntrail );
72 $block[] = new DiffOpCopy( $context );
73 }
74 $this->block( $x0, $ntrail + $xi - $x0,
75 $y0, $ntrail + $yi - $y0,
76 $block );
77 $block = false;
78 }
79 }
80 $context = $edit->orig;
81 } else {
82 if ( !is_array( $block ) ) {
83 $context = array_slice( $context, count( $context ) - $nlead );
84 $x0 = $xi - count( $context );
85 $y0 = $yi - count( $context );
86 $block = [];
87 if ( $context ) {
88 $block[] = new DiffOpCopy( $context );
89 }
90 }
91 $block[] = $edit;
92 }
93
94 if ( $edit->orig ) {
95 $xi += count( $edit->orig );
96 }
97 if ( $edit->closing ) {
98 $yi += count( $edit->closing );
99 }
100 }
101
102 if ( is_array( $block ) ) {
103 $this->block( $x0, $xi - $x0,
104 $y0, $yi - $y0,
105 $block );
106 }
107
108 $end = $this->endDiff();
109
110 return $end;
111 }
112
120 protected function block( $xbeg, $xlen, $ybeg, $ylen, &$edits ) {
121 $this->startBlock( $this->blockHeader( $xbeg, $xlen, $ybeg, $ylen ) );
122 foreach ( $edits as $edit ) {
123 if ( $edit->type == 'copy' ) {
124 $this->context( $edit->orig );
125 } elseif ( $edit->type == 'add' ) {
126 $this->added( $edit->closing );
127 } elseif ( $edit->type == 'delete' ) {
128 $this->deleted( $edit->orig );
129 } elseif ( $edit->type == 'change' ) {
130 $this->changed( $edit->orig, $edit->closing );
131 } else {
132 throw new UnexpectedValueException( "Unknown edit type: {$edit->type}" );
133 }
134 }
135 $this->endBlock();
136 }
137
138 protected function startDiff() {
139 $this->result = '';
140 }
141
147 protected function writeOutput( $text ) {
148 $this->result .= $text;
149 }
150
154 protected function endDiff() {
155 $val = $this->result;
156 $this->result = '';
157
158 return $val;
159 }
160
169 protected function blockHeader( $xbeg, $xlen, $ybeg, $ylen ) {
170 if ( $xlen > 1 ) {
171 $xbeg .= ',' . ( $xbeg + $xlen - 1 );
172 }
173 if ( $ylen > 1 ) {
174 $ybeg .= ',' . ( $ybeg + $ylen - 1 );
175 }
176
177 return $xbeg . ( $xlen ? ( $ylen ? 'c' : 'd' ) : 'a' ) . $ybeg;
178 }
179
186 protected function startBlock( $header ) {
187 $this->writeOutput( $header . "\n" );
188 }
189
194 protected function endBlock() {
195 }
196
203 protected function lines( $lines, $prefix = ' ' ) {
204 foreach ( $lines as $line ) {
205 $this->writeOutput( "$prefix $line\n" );
206 }
207 }
208
212 protected function context( $lines ) {
213 $this->lines( $lines );
214 }
215
219 protected function added( $lines ) {
220 $this->lines( $lines, '>' );
221 }
222
226 protected function deleted( $lines ) {
227 $this->lines( $lines, '<' );
228 }
229
236 protected function changed( $orig, $closing ) {
237 $this->deleted( $orig );
238 $this->writeOutput( "---\n" );
239 $this->added( $closing );
240 }
241
242}
243
245class_alias( DiffFormatter::class, 'DiffFormatter' );
Base class for diff formatters.
startBlock( $header)
Called at the start of a block of connected edits.
int $leadingContextLines
Number of leading context "lines" to preserve.
lines( $lines, $prefix=' ')
Writes all (optionally prefixed) lines to the output buffer, separated by newlines.
int $trailingContextLines
Number of trailing context "lines" to preserve.
changed( $orig, $closing)
Writes the two sets of lines to the output buffer, separated by "---" and a newline.
writeOutput( $text)
Writes a string to the output buffer.
endBlock()
Called at the end of a block of connected edits.
block( $xbeg, $xlen, $ybeg, $ylen, &$edits)
format( $diff)
Format a diff.
blockHeader( $xbeg, $xlen, $ybeg, $ylen)