source: trunk/www.guidonia.net/wp/wp-includes/Text/Diff/Renderer.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 15 years ago
File size: 6.6 KB
Line 
1<?php
2/**
3 * A class to render Diffs in different formats.
4 *
5 * This class renders the diff in classic diff format. It is intended that
6 * this class be customized via inheritance, to obtain fancier outputs.
7 *
8 * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.21 2008/01/04 10:07:50 jan Exp $
9 *
10 * Copyright 2004-2008 The Horde Project (http://www.horde.org/)
11 *
12 * See the enclosed file COPYING for license information (LGPL). If you did
13 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
14 *
15 * @package Text_Diff
16 */
17class Text_Diff_Renderer {
18
19 /**
20 * Number of leading context "lines" to preserve.
21 *
22 * This should be left at zero for this class, but subclasses may want to
23 * set this to other values.
24 */
25 var $_leading_context_lines = 0;
26
27 /**
28 * Number of trailing context "lines" to preserve.
29 *
30 * This should be left at zero for this class, but subclasses may want to
31 * set this to other values.
32 */
33 var $_trailing_context_lines = 0;
34
35 /**
36 * Constructor.
37 */
38 function Text_Diff_Renderer($params = array())
39 {
40 foreach ($params as $param => $value) {
41 $v = '_' . $param;
42 if (isset($this->$v)) {
43 $this->$v = $value;
44 }
45 }
46 }
47
48 /**
49 * Get any renderer parameters.
50 *
51 * @return array All parameters of this renderer object.
52 */
53 function getParams()
54 {
55 $params = array();
56 foreach (get_object_vars($this) as $k => $v) {
57 if ($k[0] == '_') {
58 $params[substr($k, 1)] = $v;
59 }
60 }
61
62 return $params;
63 }
64
65 /**
66 * Renders a diff.
67 *
68 * @param Text_Diff $diff A Text_Diff object.
69 *
70 * @return string The formatted output.
71 */
72 function render($diff)
73 {
74 $xi = $yi = 1;
75 $block = false;
76 $context = array();
77
78 $nlead = $this->_leading_context_lines;
79 $ntrail = $this->_trailing_context_lines;
80
81 $output = $this->_startDiff();
82
83 $diffs = $diff->getDiff();
84 foreach ($diffs as $i => $edit) {
85 /* If these are unchanged (copied) lines, and we want to keep
86 * leading or trailing context lines, extract them from the copy
87 * block. */
88 if (is_a($edit, 'Text_Diff_Op_copy')) {
89 /* Do we have any diff blocks yet? */
90 if (is_array($block)) {
91 /* How many lines to keep as context from the copy
92 * block. */
93 $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
94 if (count($edit->orig) <= $keep) {
95 /* We have less lines in the block than we want for
96 * context => keep the whole block. */
97 $block[] = $edit;
98 } else {
99 if ($ntrail) {
100 /* Create a new block with as many lines as we need
101 * for the trailing context. */
102 $context = array_slice($edit->orig, 0, $ntrail);
103 $block[] = &new Text_Diff_Op_copy($context);
104 }
105 /* @todo */
106 $output .= $this->_block($x0, $ntrail + $xi - $x0,
107 $y0, $ntrail + $yi - $y0,
108 $block);
109 $block = false;
110 }
111 }
112 /* Keep the copy block as the context for the next block. */
113 $context = $edit->orig;
114 } else {
115 /* Don't we have any diff blocks yet? */
116 if (!is_array($block)) {
117 /* Extract context lines from the preceding copy block. */
118 $context = array_slice($context, count($context) - $nlead);
119 $x0 = $xi - count($context);
120 $y0 = $yi - count($context);
121 $block = array();
122 if ($context) {
123 $block[] = &new Text_Diff_Op_copy($context);
124 }
125 }
126 $block[] = $edit;
127 }
128
129 if ($edit->orig) {
130 $xi += count($edit->orig);
131 }
132 if ($edit->final) {
133 $yi += count($edit->final);
134 }
135 }
136
137 if (is_array($block)) {
138 $output .= $this->_block($x0, $xi - $x0,
139 $y0, $yi - $y0,
140 $block);
141 }
142
143 return $output . $this->_endDiff();
144 }
145
146 function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
147 {
148 $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
149
150 foreach ($edits as $edit) {
151 switch (strtolower(get_class($edit))) {
152 case 'text_diff_op_copy':
153 $output .= $this->_context($edit->orig);
154 break;
155
156 case 'text_diff_op_add':
157 $output .= $this->_added($edit->final);
158 break;
159
160 case 'text_diff_op_delete':
161 $output .= $this->_deleted($edit->orig);
162 break;
163
164 case 'text_diff_op_change':
165 $output .= $this->_changed($edit->orig, $edit->final);
166 break;
167 }
168 }
169
170 return $output . $this->_endBlock();
171 }
172
173 function _startDiff()
174 {
175 return '';
176 }
177
178 function _endDiff()
179 {
180 return '';
181 }
182
183 function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
184 {
185 if ($xlen > 1) {
186 $xbeg .= ',' . ($xbeg + $xlen - 1);
187 }
188 if ($ylen > 1) {
189 $ybeg .= ',' . ($ybeg + $ylen - 1);
190 }
191
192 // this matches the GNU Diff behaviour
193 if ($xlen && !$ylen) {
194 $ybeg--;
195 } elseif (!$xlen) {
196 $xbeg--;
197 }
198
199 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
200 }
201
202 function _startBlock($header)
203 {
204 return $header . "\n";
205 }
206
207 function _endBlock()
208 {
209 return '';
210 }
211
212 function _lines($lines, $prefix = ' ')
213 {
214 return $prefix . implode("\n$prefix", $lines) . "\n";
215 }
216
217 function _context($lines)
218 {
219 return $this->_lines($lines, ' ');
220 }
221
222 function _added($lines)
223 {
224 return $this->_lines($lines, '> ');
225 }
226
227 function _deleted($lines)
228 {
229 return $this->_lines($lines, '< ');
230 }
231
232 function _changed($orig, $final)
233 {
234 return $this->_deleted($orig) . "---\n" . $this->_added($final);
235 }
236
237}
Note: See TracBrowser for help on using the repository browser.