Changeset View
Changeset View
Standalone View
Standalone View
src/applications/differential/parser/DifferentialChangesetParser.php
Show All 13 Lines | final class DifferentialChangesetParser extends Phobject { | ||||
protected $filename = null; | protected $filename = null; | ||||
protected $hunkStartLines = array(); | protected $hunkStartLines = array(); | ||||
protected $comments = array(); | protected $comments = array(); | ||||
protected $specialAttributes = array(); | protected $specialAttributes = array(); | ||||
protected $changeset; | protected $changeset; | ||||
protected $whitespaceMode = null; | |||||
protected $renderCacheKey = null; | protected $renderCacheKey = null; | ||||
private $handles = array(); | private $handles = array(); | ||||
private $user; | private $user; | ||||
private $leftSideChangesetID; | private $leftSideChangesetID; | ||||
private $leftSideAttachesToNewFile; | private $leftSideAttachesToNewFile; | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | public static function getDefaultRendererForViewer(PhabricatorUser $viewer) { | ||||
if ($is_unified) { | if ($is_unified) { | ||||
return '1up'; | return '1up'; | ||||
} | } | ||||
return null; | return null; | ||||
} | } | ||||
public function readParametersFromRequest(AphrontRequest $request) { | public function readParametersFromRequest(AphrontRequest $request) { | ||||
$this->setWhitespaceMode($request->getStr('whitespace')); | |||||
$this->setCharacterEncoding($request->getStr('encoding')); | $this->setCharacterEncoding($request->getStr('encoding')); | ||||
$this->setHighlightAs($request->getStr('highlight')); | $this->setHighlightAs($request->getStr('highlight')); | ||||
$renderer = null; | $renderer = null; | ||||
// If the viewer prefers unified diffs, always set the renderer to unified. | // If the viewer prefers unified diffs, always set the renderer to unified. | ||||
// Otherwise, we leave it unspecified and the client will choose a | // Otherwise, we leave it unspecified and the client will choose a | ||||
// renderer based on the screen size. | // renderer based on the screen size. | ||||
Show All 11 Lines | switch ($renderer) { | ||||
default: | default: | ||||
$this->setRenderer(new DifferentialChangesetTwoUpRenderer()); | $this->setRenderer(new DifferentialChangesetTwoUpRenderer()); | ||||
break; | break; | ||||
} | } | ||||
return $this; | return $this; | ||||
} | } | ||||
const CACHE_VERSION = 12; | const CACHE_VERSION = 13; | ||||
const CACHE_MAX_SIZE = 8e6; | const CACHE_MAX_SIZE = 8e6; | ||||
const ATTR_GENERATED = 'attr:generated'; | const ATTR_GENERATED = 'attr:generated'; | ||||
const ATTR_DELETED = 'attr:deleted'; | const ATTR_DELETED = 'attr:deleted'; | ||||
const ATTR_UNCHANGED = 'attr:unchanged'; | const ATTR_UNCHANGED = 'attr:unchanged'; | ||||
const ATTR_WHITELINES = 'attr:white'; | |||||
const ATTR_MOVEAWAY = 'attr:moveaway'; | const ATTR_MOVEAWAY = 'attr:moveaway'; | ||||
const WHITESPACE_SHOW_ALL = 'show-all'; | |||||
const WHITESPACE_IGNORE_TRAILING = 'ignore-trailing'; | |||||
const WHITESPACE_IGNORE_MOST = 'ignore-most'; | |||||
const WHITESPACE_IGNORE_ALL = 'ignore-all'; | |||||
public function setOldLines(array $lines) { | public function setOldLines(array $lines) { | ||||
$this->old = $lines; | $this->old = $lines; | ||||
return $this; | return $this; | ||||
} | } | ||||
public function setNewLines(array $lines) { | public function setNewLines(array $lines) { | ||||
$this->new = $lines; | $this->new = $lines; | ||||
return $this; | return $this; | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | final class DifferentialChangesetParser extends Phobject { | ||||
public function setChangeset(DifferentialChangeset $changeset) { | public function setChangeset(DifferentialChangeset $changeset) { | ||||
$this->changeset = $changeset; | $this->changeset = $changeset; | ||||
$this->setFilename($changeset->getFilename()); | $this->setFilename($changeset->getFilename()); | ||||
return $this; | return $this; | ||||
} | } | ||||
public function setWhitespaceMode($whitespace_mode) { | |||||
$this->whitespaceMode = $whitespace_mode; | |||||
return $this; | |||||
} | |||||
public function setRenderingReference($ref) { | public function setRenderingReference($ref) { | ||||
$this->renderingReference = $ref; | $this->renderingReference = $ref; | ||||
return $this; | return $this; | ||||
} | } | ||||
private function getRenderingReference() { | private function getRenderingReference() { | ||||
return $this->renderingReference; | return $this->renderingReference; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | final class DifferentialChangesetParser extends Phobject { | ||||
public function isDeleted() { | public function isDeleted() { | ||||
return idx($this->specialAttributes, self::ATTR_DELETED, false); | return idx($this->specialAttributes, self::ATTR_DELETED, false); | ||||
} | } | ||||
public function isUnchanged() { | public function isUnchanged() { | ||||
return idx($this->specialAttributes, self::ATTR_UNCHANGED, false); | return idx($this->specialAttributes, self::ATTR_UNCHANGED, false); | ||||
} | } | ||||
public function isWhitespaceOnly() { | |||||
return idx($this->specialAttributes, self::ATTR_WHITELINES, false); | |||||
} | |||||
public function isMoveAway() { | public function isMoveAway() { | ||||
return idx($this->specialAttributes, self::ATTR_MOVEAWAY, false); | return idx($this->specialAttributes, self::ATTR_MOVEAWAY, false); | ||||
} | } | ||||
private function applyIntraline(&$render, $intra, $corpus) { | private function applyIntraline(&$render, $intra, $corpus) { | ||||
foreach ($render as $key => $text) { | foreach ($render as $key => $text) { | ||||
if (isset($intra[$key])) { | if (isset($intra[$key])) { | ||||
Show All 30 Lines | foreach ($data as $key => $info) { | ||||
if (!$info) { | if (!$info) { | ||||
unset($result_lines[$key]); | unset($result_lines[$key]); | ||||
} | } | ||||
} | } | ||||
return $result_lines; | return $result_lines; | ||||
} | } | ||||
private function tryCacheStuff() { | private function tryCacheStuff() { | ||||
$whitespace_mode = $this->whitespaceMode; | $skip_cache = false; | ||||
switch ($whitespace_mode) { | |||||
case self::WHITESPACE_SHOW_ALL: | |||||
case self::WHITESPACE_IGNORE_TRAILING: | |||||
case self::WHITESPACE_IGNORE_ALL: | |||||
break; | |||||
default: | |||||
$whitespace_mode = self::WHITESPACE_IGNORE_MOST; | |||||
break; | |||||
} | |||||
$skip_cache = ($whitespace_mode != self::WHITESPACE_IGNORE_MOST); | |||||
if ($this->disableCache) { | if ($this->disableCache) { | ||||
$skip_cache = true; | $skip_cache = true; | ||||
} | } | ||||
if ($this->characterEncoding) { | if ($this->characterEncoding) { | ||||
$skip_cache = true; | $skip_cache = true; | ||||
} | } | ||||
if ($this->highlightAs) { | if ($this->highlightAs) { | ||||
$skip_cache = true; | $skip_cache = true; | ||||
} | } | ||||
$this->whitespaceMode = $whitespace_mode; | |||||
$changeset = $this->changeset; | $changeset = $this->changeset; | ||||
if ($changeset->getFileType() != DifferentialChangeType::FILE_TEXT && | if ($changeset->getFileType() != DifferentialChangeType::FILE_TEXT && | ||||
$changeset->getFileType() != DifferentialChangeType::FILE_SYMLINK) { | $changeset->getFileType() != DifferentialChangeType::FILE_SYMLINK) { | ||||
$this->markGenerated(); | $this->markGenerated(); | ||||
} else { | } else { | ||||
if ($skip_cache || !$this->loadCache()) { | if ($skip_cache || !$this->loadCache()) { | ||||
$this->process(); | $this->process(); | ||||
if (!$skip_cache) { | if (!$skip_cache) { | ||||
$this->saveCache(); | $this->saveCache(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private function process() { | private function process() { | ||||
$whitespace_mode = $this->whitespaceMode; | |||||
$changeset = $this->changeset; | $changeset = $this->changeset; | ||||
$ignore_all = (($whitespace_mode == self::WHITESPACE_IGNORE_MOST) || | |||||
($whitespace_mode == self::WHITESPACE_IGNORE_ALL)); | |||||
$force_ignore = ($whitespace_mode == self::WHITESPACE_IGNORE_ALL); | |||||
if (!$force_ignore) { | |||||
if ($ignore_all && $changeset->getWhitespaceMatters()) { | |||||
$ignore_all = false; | |||||
} | |||||
} | |||||
// The "ignore all whitespace" algorithm depends on rediffing the | |||||
// files, and we currently need complete representations of both | |||||
// files to do anything reasonable. If we only have parts of the files, | |||||
// don't use the "ignore all" algorithm. | |||||
if ($ignore_all) { | |||||
$hunks = $changeset->getHunks(); | |||||
if (count($hunks) !== 1) { | |||||
$ignore_all = false; | |||||
} else { | |||||
$first_hunk = reset($hunks); | |||||
if ($first_hunk->getOldOffset() != 1 || | |||||
$first_hunk->getNewOffset() != 1) { | |||||
$ignore_all = false; | |||||
} | |||||
} | |||||
} | |||||
if ($ignore_all) { | |||||
$old_file = $changeset->makeOldFile(); | |||||
$new_file = $changeset->makeNewFile(); | |||||
if ($old_file == $new_file) { | |||||
// If the old and new files are exactly identical, the synthetic | |||||
// diff below will give us nonsense and whitespace modes are | |||||
// irrelevant anyway. This occurs when you, e.g., copy a file onto | |||||
// itself in Subversion (see T271). | |||||
$ignore_all = false; | |||||
} | |||||
} | |||||
$hunk_parser = new DifferentialHunkParser(); | $hunk_parser = new DifferentialHunkParser(); | ||||
$hunk_parser->setWhitespaceMode($whitespace_mode); | |||||
$hunk_parser->parseHunksForLineData($changeset->getHunks()); | $hunk_parser->parseHunksForLineData($changeset->getHunks()); | ||||
// Depending on the whitespace mode, we may need to compute a different | |||||
// set of changes than the set of changes in the hunk data (specifically, | |||||
// we might want to consider changed lines which have only whitespace | |||||
// changes as unchanged). | |||||
if ($ignore_all) { | |||||
$engine = new PhabricatorDifferenceEngine(); | |||||
$engine->setIgnoreWhitespace(true); | |||||
$no_whitespace_changeset = $engine->generateChangesetFromFileContent( | |||||
$old_file, | |||||
$new_file); | |||||
$type_parser = new DifferentialHunkParser(); | |||||
$type_parser->parseHunksForLineData($no_whitespace_changeset->getHunks()); | |||||
$hunk_parser->setOldLineTypeMap($type_parser->getOldLineTypeMap()); | |||||
$hunk_parser->setNewLineTypeMap($type_parser->getNewLineTypeMap()); | |||||
} | |||||
epriestley: See T13161. This is basically the piece I'm going to restore in the next diff to improve line… | |||||
$hunk_parser->reparseHunksForSpecialAttributes(); | $hunk_parser->reparseHunksForSpecialAttributes(); | ||||
$unchanged = false; | $unchanged = false; | ||||
if (!$hunk_parser->getHasAnyChanges()) { | if (!$hunk_parser->getHasAnyChanges()) { | ||||
$filetype = $this->changeset->getFileType(); | $filetype = $this->changeset->getFileType(); | ||||
if ($filetype == DifferentialChangeType::FILE_TEXT || | if ($filetype == DifferentialChangeType::FILE_TEXT || | ||||
$filetype == DifferentialChangeType::FILE_SYMLINK) { | $filetype == DifferentialChangeType::FILE_SYMLINK) { | ||||
$unchanged = true; | $unchanged = true; | ||||
} | } | ||||
} | } | ||||
$moveaway = false; | $moveaway = false; | ||||
$changetype = $this->changeset->getChangeType(); | $changetype = $this->changeset->getChangeType(); | ||||
if ($changetype == DifferentialChangeType::TYPE_MOVE_AWAY) { | if ($changetype == DifferentialChangeType::TYPE_MOVE_AWAY) { | ||||
$moveaway = true; | $moveaway = true; | ||||
} | } | ||||
$this->setSpecialAttributes(array( | $this->setSpecialAttributes(array( | ||||
self::ATTR_UNCHANGED => $unchanged, | self::ATTR_UNCHANGED => $unchanged, | ||||
self::ATTR_DELETED => $hunk_parser->getIsDeleted(), | self::ATTR_DELETED => $hunk_parser->getIsDeleted(), | ||||
self::ATTR_WHITELINES => !$hunk_parser->getHasTextChanges(), | |||||
self::ATTR_MOVEAWAY => $moveaway, | self::ATTR_MOVEAWAY => $moveaway, | ||||
)); | )); | ||||
$lines_context = $this->getLinesOfContext(); | $lines_context = $this->getLinesOfContext(); | ||||
$hunk_parser->generateIntraLineDiffs(); | $hunk_parser->generateIntraLineDiffs(); | ||||
$hunk_parser->generateVisibileLinesMask($lines_context); | $hunk_parser->generateVisibileLinesMask($lines_context); | ||||
▲ Show 20 Lines • Show All 201 Lines • ▼ Show 20 Lines | if ($this->isTopLevel && !$this->comments) { | ||||
$shield = $renderer->renderShield( | $shield = $renderer->renderShield( | ||||
pht('This is an empty file.'), | pht('This is an empty file.'), | ||||
$type); | $type); | ||||
} else { | } else { | ||||
$shield = $renderer->renderShield( | $shield = $renderer->renderShield( | ||||
pht('The contents of this file were not changed.'), | pht('The contents of this file were not changed.'), | ||||
$type); | $type); | ||||
} | } | ||||
} else if ($this->isWhitespaceOnly()) { | |||||
$shield = $renderer->renderShield( | |||||
pht('This file was changed only by adding or removing whitespace.'), | |||||
'whitespace'); | |||||
} else if ($this->isDeleted()) { | } else if ($this->isDeleted()) { | ||||
$shield = $renderer->renderShield( | $shield = $renderer->renderShield( | ||||
pht('This file was completely deleted.')); | pht('This file was completely deleted.')); | ||||
} else if ($this->changeset->getAffectedLineCount() > 2500) { | } else if ($this->changeset->getAffectedLineCount() > 2500) { | ||||
$shield = $renderer->renderShield( | $shield = $renderer->renderShield( | ||||
pht( | pht( | ||||
'This file has a very large number of changes (%s lines).', | 'This file has a very large number of changes (%s lines).', | ||||
new PhutilNumber($this->changeset->getAffectedLineCount()))); | new PhutilNumber($this->changeset->getAffectedLineCount()))); | ||||
▲ Show 20 Lines • Show All 479 Lines • Show Last 20 Lines |
See T13161. This is basically the piece I'm going to restore in the next diff to improve line alignment when lines changes only by changing whitespace, so this is coming back in some form soon.