Indefero

Indefero Git Source Tree

Root/src/IDF/Diff.php

1<?php
2/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3/*
4# ***** BEGIN LICENSE BLOCK *****
5# This file is part of InDefero, an open source project management application.
6# Copyright (C) 2008 Céondo Ltd and contributors.
7#
8# InDefero is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# InDefero is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21#
22# ***** END LICENSE BLOCK ***** */
23
24/**
25 * Diff parser.
26 *
27 */
28class IDF_Diff
29{
30 public $repo = '';
31 public $diff = '';
32 protected $lines = array();
33
34 public $files = array();
35
36 public function __construct($diff, $repo='')
37 {
38 $this->repo = $repo;
39 $this->diff = $diff;
40 $this->lines = preg_split("/\015\012|\015|\012/", $diff);
41 }
42
43 public function parse()
44 {
45 $current_file = '';
46 $current_chunk = 0;
47 $lline = 0;
48 $rline = 0;
49 $files = array();
50 foreach ($this->lines as $line) {
51 if (0 === strpos($line, 'diff --git a')) {
52 $current_file = self::getFile($line);
53 $files[$current_file] = array();
54 $files[$current_file]['chunks'] = array();
55 $files[$current_file]['chunks_def'] = array();
56 $current_chunk = 0;
57 continue;
58 }
59 if (0 === strpos($line, 'Index: ')) {
60 $current_file = self::getSvnFile($line);
61 $files[$current_file] = array();
62 $files[$current_file]['chunks'] = array();
63 $files[$current_file]['chunks_def'] = array();
64 $current_chunk = 0;
65 continue;
66 }
67 if (0 === strpos($line, '@@ ')) {
68 $files[$current_file]['chunks_def'][] = self::getChunk($line);
69 $files[$current_file]['chunks'][] = array();
70 $current_chunk++;
71 $lline = $files[$current_file]['chunks_def'][$current_chunk-1][0][0];
72 $rline = $files[$current_file]['chunks_def'][$current_chunk-1][1][0];
73 continue;
74 }
75 if (0 === strpos($line, '---') or 0 === strpos($line, '+++')) {
76 continue;
77 }
78 if (0 === strpos($line, '-')) {
79 $files[$current_file]['chunks'][$current_chunk-1][] = array($lline, '', substr($line, 1));
80 $lline++;
81 continue;
82 }
83 if (0 === strpos($line, '+')) {
84 $files[$current_file]['chunks'][$current_chunk-1][] = array('', $rline, substr($line, 1));
85 $rline++;
86 continue;
87 }
88 if (0 === strpos($line, ' ')) {
89 $files[$current_file]['chunks'][$current_chunk-1][] = array($lline, $rline, substr($line, 1));
90 $rline++;
91 $lline++;
92 continue;
93 }
94 }
95 $this->files = $files;
96 return $files;
97 }
98
99 public static function getFile($line)
100 {
101 $line = substr(trim($line), 10);
102 $n = (int) strlen($line)/2;
103 return trim(substr($line, 3, $n-3));
104 }
105
106 public static function getSvnFile($line)
107 {
108 return substr(trim($line), 7);
109 }
110
111 /**
112 * Return the html version of a parsed diff.
113 */
114 public function as_html()
115 {
116 $out = '';
117 foreach ($this->files as $filename=>$file) {
118 $pretty = '';
119 $fileinfo = IDF_Views_Source::getMimeType($filename);
120 if (IDF_Views_Source::isSupportedExtension($fileinfo[2])) {
121 $pretty = ' prettyprint';
122 }
123 $out .= "\n".'<table class="diff" summary="">'."\n";
124 $out .= '<tr id="diff-'.md5($filename).'"><th colspan="3">'.Pluf_esc($filename).'</th></tr>'."\n";
125 $cc = 1;
126 foreach ($file['chunks'] as $chunk) {
127 foreach ($chunk as $line) {
128 if ($line[0] and $line[1]) {
129 $class = 'diff-c';
130 } elseif ($line[0]) {
131 $class = 'diff-r';
132 } else {
133 $class = 'diff-a';
134 }
135 $line_content = self::padLine(Pluf_esc($line[2]));
136 $out .= sprintf('<tr class="diff-line"><td class="diff-lc">%s</td><td class="diff-lc">%s</td><td class="%s%s mono">%s</td></tr>'."\n", $line[0], $line[1], $class, $pretty, $line_content);
137 }
138 if (count($file['chunks']) > $cc)
139 $out .= '<tr class="diff-next"><td>...</td><td>...</td><td>&nbsp;</td></tr>'."\n";
140 $cc++;
141 }
142 $out .= '</table>';
143 }
144 return Pluf_Template::markSafe($out);
145 }
146
147
148 public static function padLine($line)
149 {
150 $n = strlen($line);
151 for ($i=0;$i<$n;$i++) {
152 if (substr($line, $i, 1) != ' ') {
153 break;
154 }
155 }
156 return str_repeat('&nbsp;', $i).substr($line, $i);
157 }
158
159 /**
160 * @return array array(array(start, n), array(start, n))
161 */
162 public static function getChunk($line)
163 {
164 $elts = split(' ', $line);
165 $res = array();
166 for ($i=1;$i<3;$i++) {
167 $res[] = split(',', trim(substr($elts[$i], 1)));
168 }
169 return $res;
170 }
171
172}

Archive Download this file