From 43bfb5a5c4c3f8e428a92586e54f263716073545 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Mon, 23 Apr 2007 00:19:34 +0000 Subject: [PATCH] - Rewrote the Diff class to be much more easy-to-read and extend - Cleaned up diff.php --- diff.php | 52 ++++----- includes/class_diff.php | 243 ++++++++++++++++++++++------------------ 2 files changed, 158 insertions(+), 137 deletions(-) diff --git a/diff.php b/diff.php index 64859a7..32e0837 100644 --- a/diff.php +++ b/diff.php @@ -41,7 +41,7 @@ $link['log'] = ConstructLink('log', $input->in['repos'], $input->in['path'], $in // ################################################################### -$show['fullchangeset'] = ($input->in['path'] == '' OR $input->in['path'] == '/'); +$show['fullchangeset'] = !($input->in['path'] == '' OR $input->in['path'] == '/'); if ($show['fullchangeset']) { $link['changeset'] = ConstructLink('diff', $input->in['repos'], null, $input->in['rev']); @@ -67,50 +67,46 @@ foreach ($diff->fetch() AS $filename => $file) continue; } - $props = $file['props']; - $show['props'] = (bool)$props; - unset($file['props']); - - foreach ($file AS $hunk) + foreach ($file['lines'] AS $hunk) { $lines = ''; + + $show['hunk'] = true; + $low = $file['revision']['low']; + $high = $file['revision']['high']; + + $filename = (preg_match('/' . preg_quote($filename, '/') . '$/', $input->in['path']) ? $input->in['path'] : BSFunctions::FetchSourcePath($input->in['path']) . $filename); + $rlow = ConstructLink('view', $input->in['repos'], $filename, $low); + $rhigh = ConstructLink('view', $input->in['repos'], $filename, $high); + eval('$lines .= "' . $template->fetch('diff_line') . '";'); + foreach ($hunk AS $key => $line) { $show['hunk'] = false; - if ($key == 'hunk' AND isset($line['old'])) + if ($line['act'] == '+') + { + $class = 'diff_add'; + } + else if ($line['act'] == '-') { - $filepath = ($isdir ? $controller->path . $filename : $controller->path); - // $rlow = ConstructLink('view', $input->in['repos'], $filename, $) - $high = $revision->revision; - $rhigh = ConstructLink('view', $input->in['repos'], $filename, $revision->revision); - $show['hunk'] = true; + $class = 'diff_del'; } else { - if ($line['act'] == '+') - { - $class = 'diff_add'; - } - else if ($line['act'] == '-') - { - $class = 'diff_del'; - } - else - { - $class = 'diff_norm'; - } - - $line['line_clean'] = FormatCode($line['line']); + $class = 'diff_norm'; } + $line['line_clean'] = FormatCode($line['line']); + eval('$lines .= "' . $template->fetch('diff_line') . '";'); } eval('$hunktpl .= "' . $template->fetch('diff_hunk') . '";'); } - if (is_array($props)) + if (is_array($file['props'])) { - foreach ($props AS $name => $values) + $show['props'] = true; + foreach ($file['props'] AS $name => $values) { // modified if (isset($values['add']) AND isset($values['del'])) diff --git a/includes/class_diff.php b/includes/class_diff.php index c8e7893..9fd43e6 100644 --- a/includes/class_diff.php +++ b/includes/class_diff.php @@ -35,7 +35,7 @@ class Diff { /** * Raw unified diff text - * @var string + * @var array */ private $raw; @@ -45,6 +45,30 @@ class Diff */ private $index; + /** + * The array index of where capturing of diff data starts + * @var integer + */ + private $captureStart = 0; + + /** + * Current hunk that is being processed + * @var integer + */ + private $hunkId = 0; + + /** + * The lines on which hunks start + * @var array + */ + private $hunkLines = array('old' => array('line' => 0, 'count' => 0), 'new' => array('line' => 0, 'count' => 0)); + + /** + * The parsed diff output + * @var array + */ + private $diff = array(); + // ################################################################### /** * Constructor @@ -65,61 +89,90 @@ class Diff */ public function fetch() { - global $viewsvn; + for ($i = 0; $i < sizeof($this->raw); $i++) + { + $line = $this->raw[$i]; + + if (preg_match('/^Index: (.*)/', $line, $index)) + { + $this->_processFile(array_slice($this->raw, $this->captureStart, $i - $this->captureStart)); + $this->captureStart = $i; + $this->index = $index[1]; + } + } + $this->_processFile(array_slice($this->raw, $this->captureStart)); - $chunk = 0; - $indexcounter = null; - $curprop = ''; + return $this->diff; + } + + // ################################################################### + /** + * Processes a file part of a diff + * + * @param array An array of lines that make up a file chunk + */ + private function _processFile($lines) + { + preg_match_all('/[\-\+]{3}\s+(.*)\s+\(revision ([0-9]*)\)/', $lines[2] . "\n" . $lines[3], $revs); + $this->diff[$this->index]['revision']['low'] = $revs[2][0]; + $this->diff[$this->index]['revision']['high'] = $revs[2][1]; - $delstack = array(); + $this->hunkId = 0; - foreach ($this->raw AS $line) + $captureStart = 4; + for ($i = 4; $i < sizeof($lines); $i++) { - if (preg_match('#^@@ \-([0-9]*),([0-9]*) \+([0-9]*),([0-9]*) @@$#', $line, $bits)) - { - $property = false; - $delstack = array(); - $this->diff["$index"][ ++$chunk ]['hunk'] = array('old' => array('line' => $bits[1], 'count' => $bits[2]), 'new' => array('line' => $bits[3], 'count' => $bits[4])); - $lines['old'] = $this->diff["$index"]["$chunk"]['hunk']['old']['line'] - 1; - $lines['new'] = $this->diff["$index"]["$chunk"]['hunk']['new']['line'] - 1; - continue; - } - else if (preg_match('#^Property changes on: (.*?)$#', $line, $bits)) - { - $property = true; - $index = $bits[1]; - $this->diff["$index"]['props'] = array(); - continue; - } + $line = $lines[$i]; - if ($indexcounter <= 3 AND $indexcounter !== null) + if (preg_match('/^@@ \-([0-9]*),([0-9]*) \+([0-9]*),([0-9]*) @@/', $line, $hunkHead)) { - $indexcounter++; - continue; + $this->hunkLines = array('old' => array('line' => $hunkHead[1], 'count' => $hunkHead[2]), 'new' => array('line' => $hunkHead[3], 'count' => $hunkHead[4])); + $this->_processHunk(array_slice($lines, $captureStart, $i - $captureStart)); + $captureStart = $i; + $this->hunkId++; } - else if ($indexcounter == 3) + else if (preg_match('#^__*_$#', $line)) { - $indexcounter = null; - continue; + $this->_processHunk(array_slice($lines, $captureStart, $i - $captureStart)); + $this->_processProperties(array_slice($lines, $i)); + return; } + } + $this->_processHunk(array_slice($lines, $captureStart)); + } + + // ################################################################### + /** + * This processes an individual hunk of a file + * + * @param array Array of lines + */ + private function _processHunk($lines) + { + $delstack = array(); + for ($i = 1; $i < sizeof($lines); $i++) + { + $line = $lines[$i]; - if (preg_match('#^([\+\- ])(.*)#', $line, $matches) AND !$property) + if (preg_match('/^([\+\- ])(.*)/', $line, $matches)) { - $act = $matches[1]; + $action = $matches[1]; $content = $matches[2]; - if ($act == ' ') + // leader line + if ($action == ' ') { - $this->diff["$index"]["$chunk"][] = array( + $this->diff[$this->index]['lines'][$this->hunkId][] = array( 'line' => $content, 'act' => '', - 'oldlineno' => ++$lines['old'], - 'newlineno' => ++$lines['new'] + 'oldlineno' => ++$this->hunkLines['old']['line'], + 'newlineno' => ++$this->hunkLines['new']['line'] ); $delstack = array(); } - else if ($act == '+') + // addition + else if ($action == '+') { // potential line delta if (sizeof($delstack) > 0) @@ -131,100 +184,80 @@ class Diff if (strlen($lastline['line']) > ($delta['start'] - $delta['end'])) { $end = strlen($lastline['line']) + $delta['end']; - BSRegister::Debug("RM delta- = " . $end); $change = '{@-' . '-}' . substr($lastline['line'], $delta['start'], $end - $delta['start']) . '{/@-' . '-}'; - $this->diff["$index"]["$chunk"]["$lastline[INDEX]"]['line'] = substr($lastline['line'], 0, $delta['start']) . $change . substr($lastline['line'], $end); + $this->diff[$this->index]['lines'][$this->hunkId][$lastline['index']]['line'] = substr($lastline['line'], 0, $delta['start']) . $change . substr($lastline['line'], $end); } if (strlen($content) > $delta['start'] - $delta['end']) { $end = strlen($content) + $delta['end']; - BSRegister::Debug("MK delta+ = " . $end); $change = '{@+' . '+}' . substr($content, $delta['start'], $end - $delta['start']) . '{/@+' . '+}'; $content = substr($content, 0, $delta['start']) . $change . substr($content, $end); } } } - $this->diff["$index"]["$chunk"][] = array( + $this->diff[$this->index]['lines'][$this->hunkId][] = array( 'line' => $content, 'act' => '+', - 'oldlineno' => '', - 'newlineno' => ++$lines['new'] + 'oldlineno' => 0, + 'newlineno' => ++$this->hunkLines['new']['line'] ); } - else if ($act == '-') + // deletion + else if ($action == '-') { - $this->diff["$index"]["$chunk"][] = $thearray = array( + $this->diff[$this->index]['lines'][$this->hunkId][] = $temp = array( 'line' => $content, 'act' => '-', - 'oldlineno' => ++$lines['old'], - 'newlineno' => '' + 'oldlineno' => ++$this->hunkLines['old']['line'], + 'newlineno' => 0 ); - $key = sizeof($this->diff["$index"]["$chunk"]) - 2; - $thearray['INDEX'] = $key; - - array_push($delstack, $thearray); + $temp['index'] = sizeof($this->diff[$this->index]['lines'][$this->hunkId]) - 1; + array_push($delstack, $temp); } } - // whitespace lines + } + } + + // ################################################################### + /** + * Processes properties + * + * @param array Lines of properties + */ + private function _processProperties($lines) + { + $curprop = ''; + $mode = ''; + $captureStart = 1; + for ($i = 1; $i < sizeof($lines); $i++) + { + $line = $lines[$i]; + if (preg_match('#Name: (.*?)$#', $line, $matches)) + { + $curprop = $matches[1]; + BSRegister::Debug("prop: $curprop"); + } else { - if (preg_match('#^Index: (.*?)$#', $line, $matches)) + if (preg_match('#^\s+?\+(.*)#', $line, $matches)) { - $index = $matches[1]; - $indexcounter = 1; - $chunk = 0; - continue; + $mode = 'add'; + $this->diff[$this->index]['props'][$curprop]['add'] .= $matches[1]; } - - if ($property) + else if (preg_match('#^\s+?\-(.*)#', $line, $matches)) { - if (preg_match('#^__*_$#', trim($line))) - { - BSRegister::Debug("skipping: $line"); - continue; - } - - if (preg_match('#Name: (.*?)$#', $line, $matches)) - { - $curprop = $matches[1]; - BSRegister::Debug("prop: $curprop"); - continue; - } - else - { - if (preg_match('#^\s+?\+(.*)#', $line, $matches)) - { - $mode = 'add'; - $this->diff["$index"]['props']["$curprop"]['add'] .= $matches[1]; - } - else if (preg_match('#^\s+?\-(.*)#', $line, $matches)) - { - $mode = 'del'; - $this->diff["$index"]['props']["$curprop"]['del'] .= $matches[1]; - } - else if (!preg_match('#^\s+[\+\- ](.*)#', $line) AND trim($line) != '') - { - $this->diff["$index"]['props']["$curprop"]["$mode"] .= "\n" . $line; - } - continue; - } + $mode = 'del'; + $this->diff[$this->index]['props'][$curprop]['del'] .= $matches[1]; + } + else if (!preg_match('#^\s+[\+\- ](.*)#', $line) AND trim($line) != '') + { + $this->diff[$this->index]['props'][$curprop][$mode] .= "\n" . $line; } - - $this->diff["$index"]["$chunk"][] = array( - 'line' => '', - 'act' => '', - 'oldlineno' => ++$lines['old'], - 'newlineno' => ++$lines['new'] - ); - - $delstack = array(); } } - - return $this->diff; } // ################################################################### @@ -238,14 +271,10 @@ class Diff */ private function _fetchDiffExtent($old, $new) { - global $viewsvn; - $start = 0; $min = min(strlen($old), strlen($new)); - BSRegister::Debug("min1 = $min"); - - while ($start < $min AND $old["$start"] == $new["$start"]) + while ($start < $min AND $old[$start] == $new[$start]) { $start++; } @@ -253,11 +282,7 @@ class Diff $end = -1; $min = $min - $start; - BSRegister::Debug("min2 = $min"); - - BSRegister::Debug("checking: " . $old[ strlen($old) + $end ] . ' == ' . $new[ strlen($new) + $end ]); - - while (-$end <= $min AND $old[ strlen($old) + $end ] == $new[ strlen($new) + $end ]) + while (-$end <= $min AND $old[strlen($old) + $end] == $new[strlen($new) + $end]) { $end--; } -- 2.22.5