Changeset View
Changeset View
Standalone View
Standalone View
src/applications/diffusion/controller/DiffusionBrowseController.php
Show First 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | private function browseFile() { | ||||
// this is a colorized request, we don't show blame at first (we ajax it | // this is a colorized request, we don't show blame at first (we ajax it | ||||
// in afterward) so we don't need to query for it. | // in afterward) so we don't need to query for it. | ||||
$needs_blame = ($show_blame && !$show_color) || | $needs_blame = ($show_blame && !$show_color) || | ||||
($show_blame && $request->isAjax()); | ($show_blame && $request->isAjax()); | ||||
$params = array( | $params = array( | ||||
'commit' => $drequest->getCommit(), | 'commit' => $drequest->getCommit(), | ||||
'path' => $drequest->getPath(), | 'path' => $drequest->getPath(), | ||||
'needsBlame' => $needs_blame, | |||||
); | ); | ||||
$byte_limit = null; | $byte_limit = null; | ||||
if ($view !== 'raw') { | if ($view !== 'raw') { | ||||
$byte_limit = PhabricatorFileStorageEngine::getChunkThreshold(); | $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold(); | ||||
$time_limit = 10; | $time_limit = 10; | ||||
$params += array( | $params += array( | ||||
▲ Show 20 Lines • Show All 425 Lines • ▼ Show 20 Lines | private function buildCorpus( | ||||
$show_blame, | $show_blame, | ||||
$show_color, | $show_color, | ||||
DiffusionFileContent $file_content, | DiffusionFileContent $file_content, | ||||
$needs_blame, | $needs_blame, | ||||
DiffusionRequest $drequest, | DiffusionRequest $drequest, | ||||
$path, | $path, | ||||
$data) { | $data) { | ||||
$viewer = $this->getViewer(); | |||||
$blame_handles = array(); | |||||
if ($needs_blame) { | |||||
$blame = $this->loadBlame($path, $drequest->getCommit()); | |||||
if ($blame) { | |||||
$author_phids = mpull($blame, 'getAuthorPHID'); | |||||
$blame_handles = $viewer->loadHandles($author_phids); | |||||
} | |||||
} else { | |||||
$blame = array(); | |||||
} | |||||
$file_corpus = $file_content->getCorpus(); | |||||
if (!$show_color) { | if (!$show_color) { | ||||
$lines = phutil_split_lines($file_corpus); | |||||
$style = | $style = | ||||
'border: none; width: 100%; height: 80em; font-family: monospace'; | 'border: none; width: 100%; height: 80em; font-family: monospace'; | ||||
if (!$show_blame) { | if (!$show_blame) { | ||||
$corpus = phutil_tag( | $corpus = phutil_tag( | ||||
'textarea', | 'textarea', | ||||
array( | array( | ||||
'style' => $style, | 'style' => $style, | ||||
), | ), | ||||
$file_content->getCorpus()); | $file_corpus); | ||||
} else { | } else { | ||||
$text_list = $file_content->getTextList(); | |||||
$rev_list = $file_content->getRevList(); | |||||
$blame_dict = $file_content->getBlameDict(); | |||||
$rows = array(); | $rows = array(); | ||||
foreach ($text_list as $k => $line) { | foreach ($lines as $line_number => $line) { | ||||
$rev = $rev_list[$k]; | $commit = idx($blame, $line_number); | ||||
$author = $blame_dict[$rev]['author']; | if ($commit) { | ||||
$rows[] = | $author = $commit->renderAuthorShortName($blame_handles); | ||||
sprintf('%-10s %-20s %s', substr($rev, 0, 7), $author, $line); | $commit_name = $commit->getShortName(); | ||||
} else { | |||||
$author = null; | |||||
$commit_name = null; | |||||
} | |||||
$rows[] = sprintf( | |||||
'%-10s %-20s %s', | |||||
$commit_name, | |||||
$author, | |||||
$line); | |||||
} | } | ||||
$corpus = phutil_tag( | $corpus = phutil_tag( | ||||
'textarea', | 'textarea', | ||||
array( | array( | ||||
'style' => $style, | 'style' => $style, | ||||
), | ), | ||||
implode("\n", $rows)); | implode('', $rows)); | ||||
} | } | ||||
} else { | } else { | ||||
require_celerity_resource('syntax-highlighting-css'); | require_celerity_resource('syntax-highlighting-css'); | ||||
$text_list = $file_content->getTextList(); | |||||
$rev_list = $file_content->getRevList(); | |||||
$blame_dict = $file_content->getBlameDict(); | |||||
$text_list = implode("\n", $text_list); | $highlighted = PhabricatorSyntaxHighlighter::highlightWithFilename( | ||||
$text_list = PhabricatorSyntaxHighlighter::highlightWithFilename( | |||||
$path, | $path, | ||||
$text_list); | $file_corpus); | ||||
$text_list = explode("\n", $text_list); | $lines = phutil_split_lines($highlighted); | ||||
$rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict, | $rows = $this->buildDisplayRows( | ||||
$needs_blame, $drequest, $show_blame, $show_color); | $lines, | ||||
$blame, | |||||
$show_blame, | |||||
$show_color); | |||||
$corpus_table = javelin_tag( | $corpus_table = javelin_tag( | ||||
'table', | 'table', | ||||
array( | array( | ||||
'class' => 'diffusion-source remarkup-code PhabricatorMonospaced', | 'class' => 'diffusion-source remarkup-code PhabricatorMonospaced', | ||||
'sigil' => 'phabricator-source', | 'sigil' => 'phabricator-source', | ||||
), | ), | ||||
$rows); | $rows); | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | $button = id(new PHUIButtonView()) | ||||
->setHref($href) | ->setHref($href) | ||||
->setIcon($iconview); | ->setIcon($iconview); | ||||
return $button; | return $button; | ||||
} | } | ||||
private function buildDisplayRows( | private function buildDisplayRows( | ||||
array $text_list, | array $lines, | ||||
array $rev_list, | array $blame, | ||||
array $blame_dict, | $show_color, | ||||
$needs_blame, | $show_blame) { | ||||
DiffusionRequest $drequest, | |||||
$show_blame, | $drequest = $this->getDiffusionRequest(); | ||||
$show_color) { | |||||
$handles = array(); | $handles = array(); | ||||
if ($blame_dict) { | if ($blame) { | ||||
$epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch'); | $epoch_list = mpull($blame, 'getEpoch', 'getID'); | ||||
$epoch_list = array_filter($epoch_list); | |||||
$epoch_list = array_unique($epoch_list); | |||||
$epoch_list = array_values($epoch_list); | |||||
$epoch_min = min($epoch_list); | $epoch_min = min($epoch_list); | ||||
$epoch_max = max($epoch_list); | $epoch_max = max($epoch_list); | ||||
$epoch_range = ($epoch_max - $epoch_min) + 1; | $epoch_range = ($epoch_max - $epoch_min) + 1; | ||||
$author_phids = ipull(ifilter($blame_dict, 'authorPHID'), 'authorPHID'); | |||||
$handles = $this->loadViewerHandles($author_phids); | |||||
} | } | ||||
$line_arr = array(); | $line_arr = array(); | ||||
$line_str = $drequest->getLine(); | $line_str = $drequest->getLine(); | ||||
$ranges = explode(',', $line_str); | $ranges = explode(',', $line_str); | ||||
foreach ($ranges as $range) { | foreach ($ranges as $range) { | ||||
if (strpos($range, '-') !== false) { | if (strpos($range, '-') !== false) { | ||||
list($min, $max) = explode('-', $range, 2); | list($min, $max) = explode('-', $range, 2); | ||||
$line_arr[] = array( | $line_arr[] = array( | ||||
'min' => min($min, $max), | 'min' => min($min, $max), | ||||
'max' => max($min, $max), | 'max' => max($min, $max), | ||||
); | ); | ||||
} else if (strlen($range)) { | } else if (strlen($range)) { | ||||
$line_arr[] = array( | $line_arr[] = array( | ||||
'min' => $range, | 'min' => $range, | ||||
'max' => $range, | 'max' => $range, | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
$display = array(); | $display = array(); | ||||
$line_number = 1; | $line_number = 1; | ||||
$last_rev = null; | $last_commit = null; | ||||
$color = null; | $color = null; | ||||
foreach ($text_list as $k => $line) { | foreach ($lines as $line_index => $line) { | ||||
$display_line = array( | $display_line = array( | ||||
'epoch' => null, | 'epoch' => null, | ||||
'commit' => null, | 'commit' => null, | ||||
'author' => null, | 'author' => null, | ||||
'target' => null, | 'target' => null, | ||||
'highlighted' => null, | 'highlighted' => null, | ||||
'line' => $line_number, | 'line' => $line_number, | ||||
'data' => $line, | 'data' => $line, | ||||
); | ); | ||||
if ($show_blame) { | if ($show_blame) { | ||||
// If the line's rev is same as the line above, show empty content | // If the line's rev is same as the line above, show empty content | ||||
// with same color; otherwise generate blame info. The newer a change | // with same color; otherwise generate blame info. The newer a change | ||||
// is, the more saturated the color. | // is, the more saturated the color. | ||||
$rev = idx($rev_list, $k, $last_rev); | $commit = idx($blame, $line_index, $last_commit); | ||||
if ($last_rev == $rev) { | if ($commit && $last_commit && | ||||
($last_commit->getID() == $commit->getID())) { | |||||
$display_line['color'] = $color; | $display_line['color'] = $color; | ||||
} else { | } else { | ||||
$blame = $blame_dict[$rev]; | if ($commit) { | ||||
$epoch = $commit->getEpoch(); | |||||
} else { | |||||
$epoch = null; | |||||
} | |||||
if (!isset($blame['epoch'])) { | if (!$epoch) { | ||||
if (!$blame) { | |||||
$color = '#f6f6f6'; | |||||
} else { | |||||
$color = '#ffd'; // Render as warning. | $color = '#ffd'; // Render as warning. | ||||
} | |||||
} else { | } else { | ||||
$color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range; | $color_ratio = ($epoch - $epoch_min) / $epoch_range; | ||||
$color_value = 0xE6 * (1.0 - $color_ratio); | $color_value = 0xE6 * (1.0 - $color_ratio); | ||||
$color = sprintf( | $color = sprintf( | ||||
'#%02x%02x%02x', | '#%02x%02x%02x', | ||||
$color_value, | $color_value, | ||||
0xF6, | 0xF6, | ||||
$color_value); | $color_value); | ||||
} | } | ||||
$display_line['epoch'] = idx($blame, 'epoch'); | $display_line['epoch'] = $epoch; | ||||
$display_line['color'] = $color; | $display_line['color'] = $color; | ||||
$display_line['commit'] = $rev; | |||||
$author_phid = idx($blame, 'authorPHID'); | if ($commit) { | ||||
if ($author_phid && $handles[$author_phid]) { | $display_line['commit'] = $commit; | ||||
$author_link = $handles[$author_phid]->renderLink(); | |||||
} else { | } else { | ||||
$author_link = $blame['author']; | $display_line['commit'] = null; | ||||
} | } | ||||
$display_line['author'] = $author_link; | |||||
$last_rev = $rev; | $last_commit = $commit; | ||||
} | } | ||||
} | } | ||||
if ($line_arr) { | if ($line_arr) { | ||||
if ($line_number == $line_arr[0]['min']) { | if ($line_number == $line_arr[0]['min']) { | ||||
$display_line['target'] = true; | $display_line['target'] = true; | ||||
} | } | ||||
foreach ($line_arr as $range) { | foreach ($line_arr as $range) { | ||||
if ($line_number >= $range['min'] && | if ($line_number >= $range['min'] && | ||||
$line_number <= $range['max']) { | $line_number <= $range['max']) { | ||||
$display_line['highlighted'] = true; | $display_line['highlighted'] = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
$display[] = $display_line; | $display[] = $display_line; | ||||
++$line_number; | ++$line_number; | ||||
} | } | ||||
$request = $this->getRequest(); | $request = $this->getRequest(); | ||||
$viewer = $request->getUser(); | $viewer = $request->getUser(); | ||||
$commits = array_filter(ipull($display, 'commit')); | $commits = mpull($blame, null, 'getCommitIdentifier'); | ||||
if ($commits) { | |||||
$commits = id(new DiffusionCommitQuery()) | |||||
->setViewer($viewer) | |||||
->withRepository($drequest->getRepository()) | |||||
->withIdentifiers($commits) | |||||
->execute(); | |||||
$commits = mpull($commits, null, 'getCommitIdentifier'); | |||||
} | |||||
$revision_ids = id(new DifferentialRevision()) | $revision_ids = id(new DifferentialRevision()) | ||||
->loadIDsByCommitPHIDs(mpull($commits, 'getPHID')); | ->loadIDsByCommitPHIDs(mpull($commits, 'getPHID')); | ||||
$revisions = array(); | $revisions = array(); | ||||
if ($revision_ids) { | if ($revision_ids) { | ||||
$revisions = id(new DifferentialRevisionQuery()) | $revisions = id(new DifferentialRevisionQuery()) | ||||
->setViewer($viewer) | ->setViewer($viewer) | ||||
->withIDs($revision_ids) | ->withIDs($revision_ids) | ||||
->execute(); | ->execute(); | ||||
} | } | ||||
$phids = array(); | $phids = array(); | ||||
foreach ($commits as $commit) { | foreach ($commits as $blame_commit) { | ||||
if ($commit->getAuthorPHID()) { | if ($blame_commit->getAuthorPHID()) { | ||||
$phids[] = $commit->getAuthorPHID(); | $phids[] = $blame_commit->getAuthorPHID(); | ||||
} | } | ||||
} | } | ||||
foreach ($revisions as $revision) { | foreach ($revisions as $revision) { | ||||
if ($revision->getAuthorPHID()) { | if ($revision->getAuthorPHID()) { | ||||
$phids[] = $revision->getAuthorPHID(); | $phids[] = $revision->getAuthorPHID(); | ||||
} | } | ||||
} | } | ||||
$handles = $this->loadViewerHandles($phids); | $handles = $this->loadViewerHandles($phids); | ||||
Show All 26 Lines | private function buildDisplayRows( | ||||
$rows = $this->renderInlines( | $rows = $this->renderInlines( | ||||
idx($inlines, 0, array()), | idx($inlines, 0, array()), | ||||
$show_blame, | $show_blame, | ||||
(bool)$this->coverage, | (bool)$this->coverage, | ||||
$engine); | $engine); | ||||
foreach ($display as $line) { | foreach ($display as $line) { | ||||
$line_href = $drequest->generateURI( | $line_href = $drequest->generateURI( | ||||
array( | array( | ||||
'action' => 'browse', | 'action' => 'browse', | ||||
'line' => $line['line'], | 'line' => $line['line'], | ||||
'stable' => true, | 'stable' => true, | ||||
)); | )); | ||||
$blame = array(); | $blame = array(); | ||||
$style = null; | $style = null; | ||||
if (array_key_exists('color', $line)) { | if (array_key_exists('color', $line)) { | ||||
if ($line['color']) { | if ($line['color']) { | ||||
$style = 'background: '.$line['color'].';'; | $style = 'background: '.$line['color'].';'; | ||||
} | } | ||||
$before_link = null; | $before_link = null; | ||||
$commit_link = null; | $commit_link = null; | ||||
$revision_link = null; | $revision_link = null; | ||||
if (idx($line, 'commit')) { | if (idx($line, 'commit')) { | ||||
$commit = $line['commit']; | $commit = $line['commit']; | ||||
if (idx($commits, $commit)) { | if ($commit) { | ||||
$tooltip = $this->renderCommitTooltip( | $tooltip = $this->renderCommitTooltip( | ||||
$commits[$commit], | $commit, | ||||
$handles, | $handles, | ||||
$line['author']); | $commit->renderAuthorLink($handles)); | ||||
} else { | } else { | ||||
$tooltip = null; | $tooltip = null; | ||||
} | } | ||||
Javelin::initBehavior('phabricator-tooltips', array()); | Javelin::initBehavior('phabricator-tooltips', array()); | ||||
require_celerity_resource('aphront-tooltip-css'); | require_celerity_resource('aphront-tooltip-css'); | ||||
$commit_link = javelin_tag( | $commit_link = javelin_tag( | ||||
'a', | 'a', | ||||
array( | array( | ||||
'href' => $drequest->generateURI( | 'href' => $drequest->generateURI( | ||||
array( | array( | ||||
'action' => 'commit', | 'action' => 'commit', | ||||
'commit' => $line['commit'], | 'commit' => $commit->getCommitIdentifier(), | ||||
)), | )), | ||||
'sigil' => 'has-tooltip', | 'sigil' => 'has-tooltip', | ||||
'meta' => array( | 'meta' => array( | ||||
'tip' => $tooltip, | 'tip' => $tooltip, | ||||
'align' => 'E', | 'align' => 'E', | ||||
'size' => 600, | 'size' => 600, | ||||
), | ), | ||||
), | ), | ||||
id(new PhutilUTF8StringTruncator()) | $commit->getShortName()); | ||||
->setMaximumGlyphs(9) | |||||
->setTerminator('') | |||||
->truncateString($line['commit'])); | |||||
$revision_id = null; | $revision_id = null; | ||||
if (idx($commits, $commit)) { | if ($commit) { | ||||
$revision_id = idx($revision_ids, $commits[$commit]->getPHID()); | $revision_id = idx($revision_ids, $commit->getPHID()); | ||||
} | } | ||||
if ($revision_id) { | if ($revision_id) { | ||||
$revision = idx($revisions, $revision_id); | $revision = idx($revisions, $revision_id); | ||||
if ($revision) { | if ($revision) { | ||||
$tooltip = $this->renderRevisionTooltip($revision, $handles); | $tooltip = $this->renderRevisionTooltip($revision, $handles); | ||||
$revision_link = javelin_tag( | $revision_link = javelin_tag( | ||||
'a', | 'a', | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | foreach ($display as $line) { | ||||
} | } | ||||
} | } | ||||
return $rows; | return $rows; | ||||
} | } | ||||
private function renderInlines( | private function renderInlines( | ||||
array $inlines, | array $inlines, | ||||
$needs_blame, | $show_blame, | ||||
$has_coverage, | $has_coverage, | ||||
$engine) { | $engine) { | ||||
$rows = array(); | $rows = array(); | ||||
foreach ($inlines as $inline) { | foreach ($inlines as $inline) { | ||||
// TODO: This should use modern scaffolding code. | // TODO: This should use modern scaffolding code. | ||||
$inline_view = id(new PHUIDiffInlineCommentDetailView()) | $inline_view = id(new PHUIDiffInlineCommentDetailView()) | ||||
->setUser($this->getViewer()) | ->setUser($this->getViewer()) | ||||
->setMarkupEngine($engine) | ->setMarkupEngine($engine) | ||||
->setInlineComment($inline) | ->setInlineComment($inline) | ||||
->render(); | ->render(); | ||||
$row = array_fill(0, ($needs_blame ? 3 : 1), phutil_tag('th')); | $row = array_fill(0, ($show_blame ? 3 : 1), phutil_tag('th')); | ||||
$row[] = phutil_tag('td', array(), $inline_view); | $row[] = phutil_tag('td', array(), $inline_view); | ||||
if ($has_coverage) { | if ($has_coverage) { | ||||
$row[] = phutil_tag( | $row[] = phutil_tag( | ||||
'td', | 'td', | ||||
array( | array( | ||||
'class' => 'cov cov-I', | 'class' => 'cov cov-I', | ||||
▲ Show 20 Lines • Show All 483 Lines • ▼ Show 20 Lines | private function buildOpenRevisions() { | ||||
$phids = $view->getRequiredHandlePHIDs(); | $phids = $view->getRequiredHandlePHIDs(); | ||||
$handles = $this->loadViewerHandles($phids); | $handles = $this->loadViewerHandles($phids); | ||||
$view->setHandles($handles); | $view->setHandles($handles); | ||||
return $view; | return $view; | ||||
} | } | ||||
private function loadBlame($path, $commit) { | |||||
$blame = $this->callConduitWithDiffusionRequest( | |||||
'diffusion.blame', | |||||
array( | |||||
'commit' => $commit, | |||||
'paths' => array($path), | |||||
)); | |||||
$identifiers = idx($blame, $path, array()); | |||||
if ($identifiers) { | |||||
$viewer = $this->getViewer(); | |||||
$drequest = $this->getDiffusionRequest(); | |||||
$repository = $drequest->getRepository(); | |||||
$commits = id(new DiffusionCommitQuery()) | |||||
->setViewer($viewer) | |||||
->withRepository($repository) | |||||
->withIdentifiers($identifiers) | |||||
// TODO: We only fetch this to improve author display behavior, but | |||||
// shouldn't really need to? | |||||
->needCommitData(true) | |||||
->execute(); | |||||
$commits = mpull($commits, null, 'getCommitIdentifier'); | |||||
} else { | |||||
$commits = array(); | |||||
} | |||||
foreach ($identifiers as $key => $identifier) { | |||||
$commit = idx($commits, $identifier); | |||||
if ($commit) { | |||||
$identifiers[$key] = $commit; | |||||
} else { | |||||
$identifiers[$key] = null; | |||||
} | |||||
} | |||||
return $identifiers; | |||||
} | |||||
} | } |