]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/diff.php
Added a few comments.
[SourceForge/phpwiki.git] / lib / diff.php
1 <?php
2 rcs_id('$Id: diff.php,v 1.19 2001-12-14 20:15:02 dairiki Exp $');
3 // diff.php
4 //
5 // PhpWiki diff output code.
6 //
7 // Copyright (C) 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
8 // You may copy this code freely under the conditions of the GPL.
9 //
10
11 require_once('lib/difflib.php');
12
13 /**
14  * HTML unified diff formatter.
15  *
16  * This class formats a diff into a CSS-based
17  * unified diff format.
18  *
19  * Within groups of changed lines, diffs are highlit
20  * at the character-diff level.
21  */
22 class HtmlUnifiedDiffFormatter extends UnifiedDiffFormatter
23 {
24     function HtmlUnifiedDiffFormatter($context_lines = 4) {
25         $this->UnifiedDiffFormatter($context_lines);
26     }
27
28     function _start_diff() {
29         echo "<div class='diff'>\n";
30     }
31     function _end_diff() {
32         echo "</div>\n";
33     }
34     
35     function _start_block($header) {
36         echo "<div class='block'>\n";
37         echo QElement('tt', $header);
38     }
39
40     function _end_block() {
41         echo "</div>\n";
42     }
43
44     function _lines($lines, $class, $prefix = '&nbsp;', $elem = false) {
45         foreach ($lines as $line) {
46             if (!trim($line))
47                 $line = '&nbsp;';
48             elseif ($elem)
49                 $line = QElement($elem, $line);
50                     
51             echo Element('div', array('class' => $class),
52                          Element('tt', array('class' => 'prefix'), $prefix)
53                          . " $line") . "\n";
54         }
55     }
56
57     function _context($lines) {
58         $this->_lines($lines, 'context');
59     }
60     function _deleted($lines) {
61         $this->_lines($lines, 'deleted', '-', 'del');
62     }
63     function _added($lines) {
64         $this->_lines($lines, 'added', '+', 'ins');
65     }
66
67     function _pack_in_span($chars, $elem) {
68         $end_span = "";
69         $packed = '';
70         foreach ($chars as $c) {
71             if ($c == "\n") {
72                 $packed .= $end_span;
73                 $end_span = "";
74             }
75             elseif (!$end_span) {
76                 $packed .= "<$elem>";
77                 $end_span = "</$elem>";
78             }
79             $packed .= htmlspecialchars($c);
80         }
81         return $packed . $end_span;
82     }
83         
84     function _split_to_chars($lines) {
85         // Split into characters --- there must be a better way ...
86         $joined = implode("\n", $lines);
87         $split = array();
88         for ($i = 0; $i < strlen($joined); $i++)
89             $split[$i] = $joined[$i];
90         return $split;
91     }
92     
93             
94     function _changed($orig, $final) {
95         // Compute character-wise diff in changed region.
96         $diff = new Diff($this->_split_to_chars($orig),
97                          $this->_split_to_chars($final));
98         
99         $orig = $final = '';
100         foreach ($diff->edits as $edit) {
101             switch ($edit->type) {
102             case 'copy':
103                 $packed = implode('', $edit->orig);
104                 $orig .= $packed;
105                 $final .= $packed;
106                 break;
107             case 'add':
108                 $final .= $this->_pack_in_span($edit->final, 'ins');
109                 break;
110             case 'delete':
111                 $orig .= $this->_pack_in_span($edit->orig, 'del');
112                 break;
113             case 'change':
114                 $orig .= $this->_pack_in_span($edit->orig, 'del');
115                 $final .= $this->_pack_in_span($edit->final, 'ins');
116                 break;
117             }
118         }
119
120         $this->_lines(explode("\n", $orig),  'changed', '-');
121         $this->_lines(explode("\n", $final), 'changed', '+');
122     }
123 }
124
125 /**
126  * HTML table-based unified diff formatter.
127  *
128  * This class formats a diff into a table-based
129  * unified diff format.  (Similar to what was produced
130  * by previous versions of PhpWiki.)
131  *
132  * Within groups of changed lines, diffs are highlit
133  * at the character-diff level.
134  */
135 class TableUnifiedDiffFormatter extends HtmlUnifiedDiffFormatter
136 {
137     function TableUnifiedDiffFormatter($context_lines = 4) {
138         $this->HtmlUnifiedDiffFormatter($context_lines);
139     }
140
141     function _start_diff() {
142         echo "\n<table width='100%' class='diff'";
143         echo " cellspacing='1' cellpadding='1' border='1'>\n";
144     }
145     function _end_diff() {
146         echo "</table>\n";
147     }
148     
149     function _start_block($header) {
150         echo "<tr><td><table width='100%' class='block'";
151         echo " cellspacing='0' cellpadding='1' border='0'>\n";
152         echo Element('tr',
153                      Element('td', array('colspan' => 2),
154                              QElement('tt', $header))) . "\n";
155     }
156
157     function _end_block() {
158         echo "</table></td></tr>\n";
159     }
160
161     function _lines($lines, $class, $prefix = '&nbsp;', $elem = false) {
162         $prefix = Element('td', array('class' => 'prefix', 'width' => "1%"), $prefix);
163         foreach ($lines as $line) {
164             if (! trim($line))
165                 $line = '&nbsp';
166             elseif ($elem)
167                 $line = QElement($elem, $line);
168
169             echo Element('tr', array('valign' => 'top'), 
170                          $prefix . Element('td', array('class' => $class),
171                                            $line)) . "\n";
172         }
173     }
174 }
175
176     
177 /////////////////////////////////////////////////////////////////
178
179 function PageInfoRow ($pagename, $label, $rev)
180 {
181    global $datetimeformat;
182    
183    $cols = QElement('td', array('align' => 'right'), $label);
184    
185    if ($rev) {
186        $url = WikiURL($pagename, array('version' => $rev->getVersion()));
187        $linked_version = QElement('a', array('href' => $url), $rev->getVersion());
188        $cols .= Element('td',
189                         gettext("version") . " " . $linked_version);
190
191        $cols .= QElement('td',
192                          sprintf(gettext ("last modified on %s"),
193                                  strftime($datetimeformat, $rev->get('mtime'))));
194        $cols .= QElement('td',
195                          sprintf(gettext ("by %s"), $rev->get('author')));
196    } else {
197        $cols .= QElement('td', array('colspan' => '3'),
198                          gettext ("None"));
199    }
200    return Element('tr', $cols);
201 }
202
203 function showDiff ($dbi, $request) {
204     $pagename = $request->getArg('pagename');
205     if (is_array($versions = $request->getArg('versions'))) {
206         // Version selection from pageinfo.php display:
207         rsort($versions);
208         list ($version, $previous) = $versions;
209     }
210     else {
211         $version = $request->getArg('version');
212         $previous = $request->getArg('previous');
213     }
214     
215     $page = $dbi->getPage($pagename);
216     if ($version) {
217         if (!($new = $page->getRevision($version)))
218             NoSuchRevision($page, $version);
219         $new_version = sprintf(gettext("version %d"), $version);
220     }
221     else {
222         $new = $page->getCurrentRevision();
223         $new_version = gettext('current version');
224     }
225
226     if (preg_match('/^\d+$/', $previous)) {
227         if ( !($old = $page->getRevision($previous)) )
228             NoSuchRevision($page, $previous);
229         $old_version = sprintf(gettext("version %d"), $previous);
230         $others = array('major', 'minor', 'author');
231     }
232     else {
233         switch ($previous) {
234         case 'major':
235             $old = $new;
236             while ($old = $page->getRevisionBefore($old)) {
237                 if (! $old->get('is_minor_edit'))
238                     break;
239             }
240             $old_version = gettext("previous major revision");
241             $others = array('minor', 'author');
242             break;
243         case 'author':
244             $old = $new;
245             while ($old = $page->getRevisionBefore($old)) {
246                 if ($old->get('author') != $new->get('author'))
247                     break;
248             }
249             $old_version = gettext("revision by previous author");
250             $others = array('major', 'minor');
251             break;
252         case 'minor':
253         default:
254             $previous='minor';
255             $old = $page->getRevisionBefore($new);
256             $old_version = gettext("previous revision");
257             $others = array('major', 'author');
258             break;
259         }
260     }
261
262     $new_url = WikiURL($pagename, array('version' => $new->getVersion()));
263     $new_link = QElement('a', array('href' => $new_url), $new_version);
264     $old_url = WikiURL($pagename, array('version' => $old ? $old->getVersion() : 0));
265     $old_link = QElement('a', array('href' => $old_url), $old_version);
266     $page_link = LinkExistingWikiWord($pagename);
267     
268     $html = Element('p',
269                     sprintf(htmlspecialchars(gettext("Differences between %s and %s of %s.")),
270                             $new_link, $old_link, $page_link));
271
272     $otherdiffs='';
273     $label = array('major' => gettext("Previous Major Revision"),
274                    'minor' => gettext("Previous Revision"),
275                    'author'=> gettext("Previous Author"));
276     foreach ($others as $other) {
277         $args = array('action' => 'diff', 'previous' => $other);
278         if ($version)
279             $args['version'] = $version;
280         $otherdiffs .= ' ' . QElement('a', array('href' => WikiURL($pagename, $args),
281                                                  'class' => 'wikiaction'),
282                                       $label[$other]);
283     }
284     $html .= Element('p',
285                      htmlspecialchars(gettext("Other diffs:"))
286                      . $otherdiffs);
287             
288             
289     if ($old and $old->getVersion() == 0)
290         $old = false;
291     
292     $html .= Element('table',
293                     PageInfoRow($pagename, gettext ("Newer page:"), $new)
294                     . PageInfoRow($pagename, gettext ("Older page:"), $old));
295
296
297     if ($new && $old) {
298         $diff = new Diff($old->getContent(), $new->getContent());
299         
300         if ($diff->isEmpty()) {
301             $html .= Element('hr');
302             $html .= QElement('p', '[' . gettext ("Versions are identical") . ']');
303         }
304         else {
305             // New CSS formatted unified diffs (ugly in NS4).
306             $fmt = new HtmlUnifiedDiffFormatter;
307
308             // Use this for old table-formatted diffs.
309             //$fmt = new TableUnifiedDiffFormatter;
310             $html .= $fmt->format($diff);
311         }
312     }
313     
314     include_once('lib/Template.php');
315     echo GeneratePage('MESSAGE', $html,
316                       sprintf(gettext ("Diff: %s"), $pagename));
317 }
318   
319 // Local Variables:
320 // mode: php
321 // tab-width: 8
322 // c-basic-offset: 4
323 // c-hanging-comment-ender-p: nil
324 // indent-tabs-mode: nil
325 // End:   
326 ?>