'Horde/Autoloader/Default.php']); } /** * Set/Get renderer * * @param string $renderType * 'unified', 'inline', 'context', 'sidebyside' * defaults to "inline" * @return bool Success */ public function renderType($type = null) { if ($type === null) { return $this->renderer; } if (in_array($type, $this->renderers)) { $this->renderer = $type; return true; } return false; } /** * Set/Get engine * * @param string $engineType * 'auto', 'native', 'xdiff', 'shell', 'string' * defaults to "auto" * @return bool Success */ public function engineType($type = null) { if ($type === null) { return $this->engine; } if (in_array($type, $this->engines)) { $this->engine = $type; return true; } return false; } /** * Compare function * Compares two strings/arrays using the specified method and renderer * * @param mixed $original * @param mixed $changed * @param array $options * - div: true/false * - class: defaults to "diff" * - escape: defaults to true * @return string output */ public function compare($original, $changed, array $options = []) { if (!is_array($original)) { $original = $this->_explode($original); } if (!is_array($changed)) { $changed = $this->_explode($changed); } $rendererClassName = 'Horde_Text_Diff_Renderer_' . ucfirst($this->renderer); $renderer = new $rendererClassName(['context_lines' => $this->contextLines, 'character_diff' => $this->characterDiff]); $diff = new Horde_Text_Diff($this->engine, [$original, $changed]); $string = $renderer->render($diff); return $string; } /** * @param string $string Either context or unified diff snippet * @param array $options * - mode (autodetect, context, unified) */ public function reverse($string, array $options = []) { $defaults = [ 'mode' => 'autodetect', ]; $options += $defaults; $diff = new Horde_Text_Diff('string', [$string, $options['mode']]); $rendererClassName = 'Horde_Text_Diff_Renderer_' . ucfirst($this->renderer); $renderer = new $rendererClassName(['context_lines' => $this->contextLines, 'character_diff' => $this->characterDiff]); $string = $renderer->render($diff); return $string; } /** * Explodes the string into an array * * @param string $text * @return array */ protected function _explode($text) { if (is_array($this->explodeOn)) { foreach ($this->explodeOn as $explodeOn) { $text = explode($explodeOn, $text); } return $text; } return explode($this->explodeOn, $text); } /** * Parses a unified diff output * * @param array $text an entire section of a unified diff (between @@ lines) * @param char $_check a '+' or '-' denoting whether we're looking for lines * added or removed * @return */ public function parseDiff($text, $_check) { $start = 0; // Start of the diff $length = 0; // number of lines to recurse $changes = []; // all the changes $regs = []; if (preg_match("/^@@ ([\+\-])([0-9]+)(?:,([0-9]+))? [\+\-]([0-9]+)(?:,([0-9]+))? @@$/", array_shift($text), $regs) == false) { return; } $start = $regs[4]; $length = count($text); $instance = new Changes(); /* We don't count removed lines when looking at start of a change. For * example, we have this : * - foo * + bar * bar starts at line 1, not line 2. */ $minus = 0; for ($i = 0; $i < $length; $i++) { $line = $text[$i]; // empty line? EOF? if (strlen($line) === 0) { if ($instance->length > 0) { array_push($changes, $instance); $instance = new Changes(); } continue; } if ($_check === '-' && $_check == $line[0]) { if ($instance->length == 0) { $instance->line = $start + $i - $minus; $instance->symbol = $line[0]; $instance->length++; array_push($instance->oldline, substr($line, 1)); } elseif ($_check === '+' && $_check == $line[0]) { if ($instance->length == 0) { $instance->line = $start + $i - $minus; $instance->symbol = $line[0]; } $instance->length++; } else { if ($instance->length > 0) { array_push($changes, $instance); $instance = new Changes(); } } if ($line[0] === '-') { $minus++; } } } if ($instance->length > 0) { array_push($changes, $instance); $instance = new Changes(); } return $changes; } /** * Appends or Replaces text * * @param array &$text Array of Line objects * @param array $change Array of Change objects * @param int &$offset how many lines to skip due to previous additions */ public function applyChange(&$text, $change, &$offset = 0) { $index = 0; // $i is the change we are on for ($i = 0; $i < count($change); $i++) { $lines = $change[$i]; // $j is the line within the change for ($j = 0; $j < $lines->length; $j++) { $linenum = $lines->line - 1; $line = $text[$linenum + $j + $offset]; $color = 'green'; if (strlen(ltrim($line->text)) === 0) { continue; } if ($lines->symbol === '-') { $add = $lines->oldline; array_splice($text, $linenum + $j + $offset, 0, $add); // $k is the counter for the old lines we // removed from the previous version for ($k = 0; $k < count($add); $k++) { $l = new Line(); $l->changed = true; $l->symbol = '-'; $l->text = sprintf("%s %s\n", "-", rtrim($add[$k], "\r\n")); $text[$linenum + $j + $k + $offset] = $l; } $offset += count($add); } else { $l = new Line(); $l->symbol = '+'; $l->changed = true; $l->text = sprintf("%s %s\n", $lines->symbol, rtrim($line->text, "\r\n")); $text[$linenum + $j] = $l; } } } } } /*** other files **/ class Changes { public $line = 0; public $length = 0; public $symbol; public $oldline = []; // only for code removed } // This object is created for every line of text in the file. // It was either this, or some funk string changes class Line { public $text = ''; public $symbol = ''; public $changed = false; }