9 * |
9 * |
10 * @package Text_Diff |
10 * @package Text_Diff |
11 */ |
11 */ |
12 class Text_Diff_Renderer { |
12 class Text_Diff_Renderer { |
13 |
13 |
14 /** |
14 /** |
15 * Number of leading context "lines" to preserve. |
15 * Number of leading context "lines" to preserve. |
16 * |
16 * |
17 * This should be left at zero for this class, but subclasses may want to |
17 * This should be left at zero for this class, but subclasses may want to |
18 * set this to other values. |
18 * set this to other values. |
19 */ |
19 */ |
20 var $_leading_context_lines = 0; |
20 var $_leading_context_lines = 0; |
21 |
21 |
22 /** |
22 /** |
23 * Number of trailing context "lines" to preserve. |
23 * Number of trailing context "lines" to preserve. |
24 * |
24 * |
25 * This should be left at zero for this class, but subclasses may want to |
25 * This should be left at zero for this class, but subclasses may want to |
26 * set this to other values. |
26 * set this to other values. |
27 */ |
27 */ |
28 var $_trailing_context_lines = 0; |
28 var $_trailing_context_lines = 0; |
29 |
29 |
30 /** |
30 /** |
31 * Constructor. |
31 * Constructor. |
32 */ |
32 */ |
33 function Text_Diff_Renderer($params = array()) |
33 function Text_Diff_Renderer($params = array()) |
34 { |
34 { |
35 foreach ($params as $param => $value) { |
35 foreach ($params as $param => $value) { |
36 $v = '_' . $param; |
36 $v = '_' . $param; |
37 if (isset($this->$v)) { |
37 if (isset($this->$v)) { |
38 $this->$v = $value; |
38 $this->$v = $value; |
39 } |
39 } |
40 } |
40 } |
41 } |
41 } |
42 |
42 |
43 /** |
43 /** |
44 * Get any renderer parameters. |
44 * Get any renderer parameters. |
45 * |
45 * |
46 * @return array All parameters of this renderer object. |
46 * @return array All parameters of this renderer object. |
47 */ |
47 */ |
48 function getParams() |
48 function getParams() |
49 { |
49 { |
50 $params = array(); |
50 $params = array(); |
51 foreach (get_object_vars($this) as $k => $v) { |
51 foreach (get_object_vars($this) as $k => $v) { |
52 if ($k[0] == '_') { |
52 if ($k[0] == '_') { |
53 $params[substr($k, 1)] = $v; |
53 $params[substr($k, 1)] = $v; |
54 } |
54 } |
55 } |
55 } |
56 |
56 |
57 return $params; |
57 return $params; |
58 } |
58 } |
59 |
59 |
60 /** |
60 /** |
61 * Renders a diff. |
61 * Renders a diff. |
62 * |
62 * |
63 * @param Text_Diff $diff A Text_Diff object. |
63 * @param Text_Diff $diff A Text_Diff object. |
64 * |
64 * |
65 * @return string The formatted output. |
65 * @return string The formatted output. |
66 */ |
66 */ |
67 function render($diff) |
67 function render($diff) |
68 { |
68 { |
69 $xi = $yi = 1; |
69 $xi = $yi = 1; |
70 $block = false; |
70 $block = false; |
71 $context = array(); |
71 $context = array(); |
72 |
72 |
73 $nlead = $this->_leading_context_lines; |
73 $nlead = $this->_leading_context_lines; |
74 $ntrail = $this->_trailing_context_lines; |
74 $ntrail = $this->_trailing_context_lines; |
75 |
75 |
76 $output = $this->_startDiff(); |
76 $output = $this->_startDiff(); |
77 |
77 |
78 $diffs = $diff->getDiff(); |
78 $diffs = $diff->getDiff(); |
79 foreach ($diffs as $i => $edit) { |
79 foreach ($diffs as $i => $edit) { |
80 if (is_a($edit, 'Text_Diff_Op_copy')) { |
80 if (is_a($edit, 'Text_Diff_Op_copy')) { |
81 if (is_array($block)) { |
81 if (is_array($block)) { |
82 $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; |
82 $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; |
83 if (count($edit->orig) <= $keep) { |
83 if (count($edit->orig) <= $keep) { |
84 $block[] = $edit; |
84 $block[] = $edit; |
85 } else { |
85 } else { |
86 if ($ntrail) { |
86 if ($ntrail) { |
87 $context = array_slice($edit->orig, 0, $ntrail); |
87 $context = array_slice($edit->orig, 0, $ntrail); |
88 $block[] = &new Text_Diff_Op_copy($context); |
88 $block[] = &new Text_Diff_Op_copy($context); |
89 } |
89 } |
90 $output .= $this->_block($x0, $ntrail + $xi - $x0, |
90 $output .= $this->_block($x0, $ntrail + $xi - $x0, |
91 $y0, $ntrail + $yi - $y0, |
91 $y0, $ntrail + $yi - $y0, |
92 $block); |
92 $block); |
93 $block = false; |
93 $block = false; |
94 } |
94 } |
95 } |
95 } |
96 $context = $edit->orig; |
96 $context = $edit->orig; |
97 } else { |
97 } else { |
98 if (!is_array($block)) { |
98 if (!is_array($block)) { |
99 $context = array_slice($context, count($context) - $nlead); |
99 $context = array_slice($context, count($context) - $nlead); |
100 $x0 = $xi - count($context); |
100 $x0 = $xi - count($context); |
101 $y0 = $yi - count($context); |
101 $y0 = $yi - count($context); |
102 $block = array(); |
102 $block = array(); |
103 if ($context) { |
103 if ($context) { |
104 $block[] = &new Text_Diff_Op_copy($context); |
104 $block[] = &new Text_Diff_Op_copy($context); |
105 } |
105 } |
106 } |
106 } |
107 $block[] = $edit; |
107 $block[] = $edit; |
108 } |
108 } |
109 |
109 |
110 if ($edit->orig) { |
110 if ($edit->orig) { |
111 $xi += count($edit->orig); |
111 $xi += count($edit->orig); |
112 } |
112 } |
113 if ($edit->final) { |
113 if ($edit->final) { |
114 $yi += count($edit->final); |
114 $yi += count($edit->final); |
115 } |
115 } |
116 } |
116 } |
117 |
117 |
118 if (is_array($block)) { |
118 if (is_array($block)) { |
119 $output .= $this->_block($x0, $xi - $x0, |
119 $output .= $this->_block($x0, $xi - $x0, |
120 $y0, $yi - $y0, |
120 $y0, $yi - $y0, |
121 $block); |
121 $block); |
122 } |
122 } |
123 |
123 |
124 return $output . $this->_endDiff(); |
124 return $output . $this->_endDiff(); |
125 } |
125 } |
126 |
126 |
127 function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) |
127 function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) |
128 { |
128 { |
129 $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen)); |
129 $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen)); |
130 |
130 |
131 foreach ($edits as $edit) { |
131 foreach ($edits as $edit) { |
132 switch (strtolower(get_class($edit))) { |
132 switch (strtolower(get_class($edit))) { |
133 case 'text_diff_op_copy': |
133 case 'text_diff_op_copy': |
134 $output .= $this->_context($edit->orig); |
134 $output .= $this->_context($edit->orig); |
135 break; |
135 break; |
136 |
136 |
137 case 'text_diff_op_add': |
137 case 'text_diff_op_add': |
138 $output .= $this->_added($edit->final); |
138 $output .= $this->_added($edit->final); |
139 break; |
139 break; |
140 |
140 |
141 case 'text_diff_op_delete': |
141 case 'text_diff_op_delete': |
142 $output .= $this->_deleted($edit->orig); |
142 $output .= $this->_deleted($edit->orig); |
143 break; |
143 break; |
144 |
144 |
145 case 'text_diff_op_change': |
145 case 'text_diff_op_change': |
146 $output .= $this->_changed($edit->orig, $edit->final); |
146 $output .= $this->_changed($edit->orig, $edit->final); |
147 break; |
147 break; |
148 } |
148 } |
149 } |
149 } |
150 |
150 |
151 return $output . $this->_endBlock(); |
151 return $output . $this->_endBlock(); |
152 } |
152 } |
153 |
153 |
154 function _startDiff() |
154 function _startDiff() |
155 { |
155 { |
156 return ''; |
156 return ''; |
157 } |
157 } |
158 |
158 |
159 function _endDiff() |
159 function _endDiff() |
160 { |
160 { |
161 return ''; |
161 return ''; |
162 } |
162 } |
163 |
163 |
164 function _blockHeader($xbeg, $xlen, $ybeg, $ylen) |
164 function _blockHeader($xbeg, $xlen, $ybeg, $ylen) |
165 { |
165 { |
166 if ($xlen > 1) { |
166 if ($xlen > 1) { |
167 $xbeg .= ',' . ($xbeg + $xlen - 1); |
167 $xbeg .= ',' . ($xbeg + $xlen - 1); |
168 } |
168 } |
169 if ($ylen > 1) { |
169 if ($ylen > 1) { |
170 $ybeg .= ',' . ($ybeg + $ylen - 1); |
170 $ybeg .= ',' . ($ybeg + $ylen - 1); |
171 } |
171 } |
172 |
172 |
173 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; |
173 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; |
174 } |
174 } |
175 |
175 |
176 function _startBlock($header) |
176 function _startBlock($header) |
177 { |
177 { |
178 return $header . "\n"; |
178 return $header . "\n"; |
179 } |
179 } |
180 |
180 |
181 function _endBlock() |
181 function _endBlock() |
182 { |
182 { |
183 return ''; |
183 return ''; |
184 } |
184 } |
185 |
185 |
186 function _lines($lines, $prefix = ' ') |
186 function _lines($lines, $prefix = ' ') |
187 { |
187 { |
188 return $prefix . implode("\n$prefix", $lines) . "\n"; |
188 return $prefix . implode("\n$prefix", $lines) . "\n"; |
189 } |
189 } |
190 |
190 |
191 function _context($lines) |
191 function _context($lines) |
192 { |
192 { |
193 return $this->_lines($lines); |
193 return $this->_lines($lines); |
194 } |
194 } |
195 |
195 |
196 function _added($lines) |
196 function _added($lines) |
197 { |
197 { |
198 return $this->_lines($lines, '>'); |
198 return $this->_lines($lines, '>'); |
199 } |
199 } |
200 |
200 |
201 function _deleted($lines) |
201 function _deleted($lines) |
202 { |
202 { |
203 return $this->_lines($lines, '<'); |
203 return $this->_lines($lines, '<'); |
204 } |
204 } |
205 |
205 |
206 function _changed($orig, $final) |
206 function _changed($orig, $final) |
207 { |
207 { |
208 return $this->_deleted($orig) . "---\n" . $this->_added($final); |
208 return $this->_deleted($orig) . "---\n" . $this->_added($final); |
209 } |
209 } |
210 |
210 |
211 } |
211 } |