diff --git a/src/applications/differential/parser/DifferentialChangesetParser.php b/src/applications/differential/parser/DifferentialChangesetParser.php index 60a1c080a5..774e72b56a 100644 --- a/src/applications/differential/parser/DifferentialChangesetParser.php +++ b/src/applications/differential/parser/DifferentialChangesetParser.php @@ -60,7 +60,7 @@ final class DifferentialChangesetParser { private $markupEngine; private $highlightErrors; - const CACHE_VERSION = 6; + const CACHE_VERSION = 7; const CACHE_MAX_SIZE = 8e6; const ATTR_GENERATED = 'attr:generated'; @@ -132,8 +132,8 @@ final class DifferentialChangesetParser { foreach ($changeset->getHunks() as $hunk) { $n_old = $hunk->getOldOffset(); $n_new = $hunk->getNewOffset(); - $changes = rtrim($hunk->getChanges(), "\n"); - foreach (explode("\n", $changes) as $line) { + $changes = phutil_split_lines($hunk->getChanges()); + 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 == ' ') { @@ -267,12 +267,7 @@ final class DifferentialChangesetParser { public function parseHunk(DifferentialHunk $hunk) { $lines = $hunk->getChanges(); - - $lines = str_replace( - array("\t", "\r\n", "\r"), - array(' ', "\n", "\n"), - $lines); - $lines = explode("\n", $lines); + $lines = phutil_split_lines($lines); $types = array(); foreach ($lines as $line_index => $line) { @@ -573,7 +568,7 @@ final class DifferentialChangesetParser { $old_corpus[] = $o['text']; } } - $old_corpus_block = implode("\n", $old_corpus); + $old_corpus_block = implode('', $old_corpus); $new_corpus = array(); foreach ($this->new as $n) { @@ -581,7 +576,7 @@ final class DifferentialChangesetParser { $new_corpus[] = $n['text']; } } - $new_corpus_block = implode("\n", $new_corpus); + $new_corpus_block = implode('', $new_corpus); $this->markGenerated($new_corpus_block); @@ -600,6 +595,7 @@ final class DifferentialChangesetParser { 'old' => $old_corpus_block, 'new' => $new_corpus_block, ); + $this->highlightErrors = false; foreach (Futures($futures) as $key => $future) { try { @@ -820,6 +816,14 @@ final class DifferentialChangesetParser { } protected function getHighlightFuture($corpus) { + if (preg_match('/\r(?!\n)/', $corpus)) { + // TODO: Pygments converts "\r" newlines into "\n" newlines, so we can't + // use it on files with "\r" newlines. If we have "\r" not followed by + // "\n" in the file, skip highlighting. + $result = phutil_escape_html($corpus); + return new ImmediateFuture($result); + } + return $this->highlightEngine->getHighlightFuture( $this->highlightEngine->getLanguageFromFilename($this->filename), $corpus); @@ -827,7 +831,7 @@ final class DifferentialChangesetParser { protected function processHighlightedSource($data, $result) { - $result_lines = explode("\n", $result); + $result_lines = phutil_split_lines($result); foreach ($data as $key => $info) { if (!$info) { unset($result_lines[$key]); @@ -1774,13 +1778,20 @@ final class DifferentialChangesetParser { $notice = $this->renderChangeTypeHeader($this->changeset, false); } - return implode( + $result = implode( "\n", array( $notice, $props, $table, )); + + // TODO: Let the user customize their tab width / display style. + $result = str_replace("\t", ' ', $result); + + // TODO: We should possibly post-process "\r" as well. + + return $result; } protected function renderChangeTypeHeader($changeset, $force) {