diff --git a/src/applications/differential/parser/DifferentialHunkParser.php b/src/applications/differential/parser/DifferentialHunkParser.php index fc1e88814f..e381ca8346 100644 --- a/src/applications/differential/parser/DifferentialHunkParser.php +++ b/src/applications/differential/parser/DifferentialHunkParser.php @@ -418,9 +418,7 @@ final class DifferentialHunkParser { $old_lines = array(); $new_lines = array(); foreach ($hunks as $hunk) { - - $lines = $hunk->getChanges(); - $lines = phutil_split_lines($lines); + $lines = $hunk->getSplitLines(); $line_type_map = array(); $line_text = array(); @@ -514,22 +512,32 @@ final class DifferentialHunkParser { // Put changes side by side. $olds = array(); $news = array(); + $olds_cursor = -1; + $news_cursor = -1; foreach ($changeset_hunks as $hunk) { $n_old = $hunk->getOldOffset(); $n_new = $hunk->getNewOffset(); - $changes = phutil_split_lines($hunk->getChanges()); + $changes = $hunk->getSplitLines(); foreach ($changes as $line) { $diff_type = $line[0]; // Change type in diff of diffs. $orig_type = $line[1]; // Change type in the original diff. if ($diff_type == ' ') { // Use the same key for lines that are next to each other. - $key = max(last_key($olds), last_key($news)) + 1; + if ($olds_cursor > $news_cursor) { + $key = $olds_cursor + 1; + } else { + $key = $news_cursor + 1; + } $olds[$key] = null; $news[$key] = null; + $olds_cursor = $key; + $news_cursor = $key; } else if ($diff_type == '-') { $olds[] = array($n_old, $orig_type); + $olds_cursor++; } else if ($diff_type == '+') { $news[] = array($n_new, $orig_type); + $news_cursor++; } if (($diff_type == '-' || $diff_type == ' ') && $orig_type != '-') { $n_old++; @@ -660,11 +668,15 @@ final class DifferentialHunkParser { $offsets = array(); $n = 1; foreach ($hunks as $hunk) { - for ($i = 0; $i < $hunk->getNewLen(); $i++) { - $offsets[$n] = $hunk->getNewOffset() + $i; + $new_length = $hunk->getNewLen(); + $new_offset = $hunk->getNewOffset(); + + for ($i = 0; $i < $new_length; $i++) { + $offsets[$n] = $new_offset + $i; $n++; } } + return $offsets; } } diff --git a/src/applications/differential/storage/DifferentialHunk.php b/src/applications/differential/storage/DifferentialHunk.php index 2850bd9f4f..f22ba59d2b 100644 --- a/src/applications/differential/storage/DifferentialHunk.php +++ b/src/applications/differential/storage/DifferentialHunk.php @@ -10,6 +10,7 @@ abstract class DifferentialHunk extends DifferentialDAO protected $newLen; private $changeset; + private $splitLines; private $structuredLines; private $structuredFiles = array(); @@ -109,9 +110,16 @@ abstract class DifferentialHunk extends DifferentialDAO return $this->structuredFiles[$kind]; } + public function getSplitLines() { + if ($this->splitLines === null) { + $this->splitLines = phutil_split_lines($this->getChanges()); + } + return $this->splitLines; + } + private function getStructuredLines() { if ($this->structuredLines === null) { - $lines = phutil_split_lines($this->getChanges()); + $lines = $this->getSplitLines(); $structured = array(); foreach ($lines as $line) { @@ -154,13 +162,20 @@ abstract class DifferentialHunk extends DifferentialDAO } final private function makeContent($include) { + $lines = $this->getSplitLines(); $results = array(); - $lines = explode("\n", $this->getChanges()); + $include_map = array(); + for ($ii = 0; $ii < strlen($include); $ii++) { + $include_map[$include[$ii]] = true; + } + + if (isset($include_map['+'])) { + $n = $this->newOffset; + } else { + $n = $this->oldOffset; + } - $n = (strpos($include, '+') !== false ? - $this->newOffset : - $this->oldOffset); $use_next_newline = false; foreach ($lines as $line) { if (!isset($line[0])) { @@ -171,14 +186,14 @@ abstract class DifferentialHunk extends DifferentialDAO if ($use_next_newline) { $results[last_key($results)] = rtrim(end($results), "\n"); } - } else if (strpos($include, $line[0]) === false) { + } else if (empty($include_map[$line[0]])) { $use_next_newline = false; } else { $use_next_newline = true; - $results[$n] = substr($line, 1)."\n"; + $results[$n] = substr($line, 1); } - if ($line[0] == ' ' || strpos($include, $line[0]) !== false) { + if ($line[0] == ' ' || isset($include_map[$line[0]])) { $n++; } }