private function buildDisplayRows(array $text_list, array $rev_list, array $blame_dict, $needs_blame, DiffusionRequest $drequest, DiffusionFileContentQuery $file_query, $selected) { if ($blame_dict) { $epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch'); $epoch_min = min($epoch_list); $epoch_max = max($epoch_list); $epoch_range = $epoch_max - $epoch_min + 1; } $line_arr = array(); $line_str = $drequest->getLine(); $ranges = explode(',', $line_str); foreach ($ranges as $range) { if (strpos($range, '-') !== false) { list($min, $max) = explode('-', $range, 2); $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max)); } else { if (strlen($range)) { $line_arr[] = array('min' => $range, 'max' => $range); } } } $display = array(); $line_number = 1; $last_rev = null; $color = null; foreach ($text_list as $k => $line) { $display_line = array('color' => null, 'epoch' => null, 'commit' => null, 'author' => null, 'target' => null, 'highlighted' => null, 'line' => $line_number, 'data' => $line); if ($needs_blame) { // 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 // is, the more saturated the color. // TODO: SVN doesn't always give us blame for the last line, if empty? // Bug with our stuff or with SVN? $rev = idx($rev_list, $k, $last_rev); if ($last_rev == $rev) { $display_line['color'] = $color; } else { $blame = $blame_dict[$rev]; if (!isset($blame['epoch'])) { $color = '#ffd'; // Render as warning. } else { $color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range; $color_value = 0xf6 * (1.0 - $color_ratio); $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value); } $display_line['epoch'] = idx($blame, 'epoch'); $display_line['color'] = $color; $display_line['commit'] = $rev; if (isset($blame['handle'])) { $author_link = $blame['handle']->renderLink(); } else { $author_link = phutil_render_tag('span', array(), phutil_escape_html($blame['author'])); } $display_line['author'] = $author_link; $last_rev = $rev; } } if ($line_arr) { if ($line_number == $line_arr[0]['min']) { $display_line['target'] = true; } foreach ($line_arr as $range) { if ($line_number >= $range['min'] && $line_number <= $range['max']) { $display_line['highlighted'] = true; } } } $display[] = $display_line; ++$line_number; } $commits = array_filter(ipull($display, 'commit')); if ($commits) { $commits = id(new PhabricatorAuditCommitQuery())->withIdentifiers($drequest->getRepository()->getID(), $commits)->needCommitData(true)->execute(); $commits = mpull($commits, null, 'getCommitIdentifier'); } $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(mpull($commits, 'getPHID')); $revisions = array(); if ($revision_ids) { $revisions = id(new DifferentialRevision())->loadAllWhere('id IN (%Ld)', $revision_ids); } $request = $this->getRequest(); $user = $request->getUser(); Javelin::initBehavior('phabricator-oncopy', array()); $rows = array(); foreach ($display as $line) { $line_href = $drequest->generateURI(array('action' => 'browse', 'line' => $line['line'], 'stable' => true)); $blame = array(); if ($line['color']) { $color = $line['color']; $before_link = null; $commit_link = null; $revision_link = null; if (idx($line, 'commit')) { $commit = $line['commit']; $summary = 'Unknown'; if (idx($commits, $commit)) { $summary = $commits[$commit]->getCommitData()->getSummary(); } $tooltip = phabricator_date($line['epoch'], $user) . " · " . $summary; Javelin::initBehavior('phabricator-tooltips', array()); require_celerity_resource('aphront-tooltip-css'); $commit_link = javelin_render_tag('a', array('href' => $drequest->generateURI(array('action' => 'commit', 'commit' => $line['commit'])), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), phutil_escape_html(phutil_utf8_shorten($line['commit'], 9, ''))); $revision_id = null; if (idx($commits, $commit)) { $revision_id = idx($revision_ids, $commits[$commit]->getPHID()); } if ($revision_id) { $revision = idx($revisions, $revision_id); if (!$revision) { $tooltip = '(Invalid revision)'; } else { $tooltip = phabricator_date($revision->getDateModified(), $user) . " · " . $revision->getTitle(); } $revision_link = javelin_render_tag('a', array('href' => '/D' . $revision_id, 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), 'D' . $revision_id); } $uri = $line_href->alter('before', $commit); $before_link = javelin_render_tag('a', array('href' => $uri->setQueryParam('view', 'blame'), 'sigil' => 'has-tooltip', 'meta' => array('tip' => 'Skip Past This Commit', 'align' => 'E', 'size' => 300)), "«"); } $blame[] = phutil_render_tag('th', array('class' => 'diffusion-blame-link', 'style' => 'background: ' . $color), $before_link); $blame[] = phutil_render_tag('th', array('class' => 'diffusion-rev-link', 'style' => 'background: ' . $color), $commit_link); $blame[] = phutil_render_tag('th', array('class' => 'diffusion-rev-link', 'style' => 'background: ' . $color), $revision_link); $blame[] = phutil_render_tag('th', array('class' => 'diffusion-author-link', 'style' => 'background: ' . $color), idx($line, 'author')); } $line_link = phutil_render_tag('a', array('href' => $line_href), phutil_escape_html($line['line'])); $blame[] = javelin_render_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'diffusion-line-link', 'style' => isset($color) ? 'background: ' . $color : null), $line_link); Javelin::initBehavior('diffusion-line-linker'); $blame = implode('', $blame); if ($line['target']) { Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target')); $anchor_text = '<a id="scroll_target"></a>'; } else { $anchor_text = null; } $line_text = phutil_render_tag('td', array(), $anchor_text . "" . $line['data']); $rows[] = phutil_render_tag('tr', array('class' => $line['highlighted'] ? 'highlighted' : null), $blame . $line_text); } return $rows; }
private function buildDisplayRows(array $text_list, array $rev_list, array $blame_dict, $needs_blame, DiffusionRequest $drequest, $show_blame, $show_color) { $handles = array(); if ($blame_dict) { $epoch_list = ipull(ifilter($blame_dict, 'epoch'), 'epoch'); $epoch_min = min($epoch_list); $epoch_max = max($epoch_list); $epoch_range = $epoch_max - $epoch_min + 1; $author_phids = ipull(ifilter($blame_dict, 'authorPHID'), 'authorPHID'); $handles = $this->loadViewerHandles($author_phids); } $line_arr = array(); $line_str = $drequest->getLine(); $ranges = explode(',', $line_str); foreach ($ranges as $range) { if (strpos($range, '-') !== false) { list($min, $max) = explode('-', $range, 2); $line_arr[] = array('min' => min($min, $max), 'max' => max($min, $max)); } else { if (strlen($range)) { $line_arr[] = array('min' => $range, 'max' => $range); } } } $display = array(); $line_number = 1; $last_rev = null; $color = null; foreach ($text_list as $k => $line) { $display_line = array('epoch' => null, 'commit' => null, 'author' => null, 'target' => null, 'highlighted' => null, 'line' => $line_number, 'data' => $line); if ($show_blame) { // 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 // is, the more saturated the color. $rev = idx($rev_list, $k, $last_rev); if ($last_rev == $rev) { $display_line['color'] = $color; } else { $blame = $blame_dict[$rev]; if (!isset($blame['epoch'])) { $color = '#ffd'; // Render as warning. } else { $color_ratio = ($blame['epoch'] - $epoch_min) / $epoch_range; $color_value = 0xe6 * (1.0 - $color_ratio); $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value); } $display_line['epoch'] = idx($blame, 'epoch'); $display_line['color'] = $color; $display_line['commit'] = $rev; $author_phid = idx($blame, 'authorPHID'); if ($author_phid && $handles[$author_phid]) { $author_link = $handles[$author_phid]->renderLink(); } else { $author_link = $blame['author']; } $display_line['author'] = $author_link; $last_rev = $rev; } } if ($line_arr) { if ($line_number == $line_arr[0]['min']) { $display_line['target'] = true; } foreach ($line_arr as $range) { if ($line_number >= $range['min'] && $line_number <= $range['max']) { $display_line['highlighted'] = true; } } } $display[] = $display_line; ++$line_number; } $request = $this->getRequest(); $viewer = $request->getUser(); $commits = array_filter(ipull($display, 'commit')); if ($commits) { $commits = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($drequest->getRepository())->withIdentifiers($commits)->execute(); $commits = mpull($commits, null, 'getCommitIdentifier'); } $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(mpull($commits, 'getPHID')); $revisions = array(); if ($revision_ids) { $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute(); } $phids = array(); foreach ($commits as $commit) { if ($commit->getAuthorPHID()) { $phids[] = $commit->getAuthorPHID(); } } foreach ($revisions as $revision) { if ($revision->getAuthorPHID()) { $phids[] = $revision->getAuthorPHID(); } } $handles = $this->loadViewerHandles($phids); Javelin::initBehavior('phabricator-oncopy', array()); $engine = null; $inlines = array(); if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) { $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); foreach ($this->lintMessages as $message) { $inline = id(new PhabricatorAuditInlineComment())->setSyntheticAuthor(ArcanistLintSeverity::getStringForSeverity($message['severity']) . ' ' . $message['code'] . ' (' . $message['name'] . ')')->setLineNumber($message['line'])->setContent($message['description']); $inlines[$message['line']][] = $inline; $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); } $engine->process(); require_celerity_resource('differential-changeset-view-css'); } $rows = $this->renderInlines(idx($inlines, 0, array()), $show_blame, (bool) $this->coverage, $engine); foreach ($display as $line) { $line_href = $drequest->generateURI(array('action' => 'browse', 'line' => $line['line'], 'stable' => true)); $blame = array(); $style = null; if (array_key_exists('color', $line)) { if ($line['color']) { $style = 'background: ' . $line['color'] . ';'; } $before_link = null; $commit_link = null; $revision_link = null; if (idx($line, 'commit')) { $commit = $line['commit']; if (idx($commits, $commit)) { $tooltip = $this->renderCommitTooltip($commits[$commit], $handles, $line['author']); } else { $tooltip = null; } Javelin::initBehavior('phabricator-tooltips', array()); require_celerity_resource('aphront-tooltip-css'); $commit_link = javelin_tag('a', array('href' => $drequest->generateURI(array('action' => 'commit', 'commit' => $line['commit'])), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(9)->setTerminator('')->truncateString($line['commit'])); $revision_id = null; if (idx($commits, $commit)) { $revision_id = idx($revision_ids, $commits[$commit]->getPHID()); } if ($revision_id) { $revision = idx($revisions, $revision_id); if ($revision) { $tooltip = $this->renderRevisionTooltip($revision, $handles); $revision_link = javelin_tag('a', array('href' => '/D' . $revision->getID(), 'sigil' => 'has-tooltip', 'meta' => array('tip' => $tooltip, 'align' => 'E', 'size' => 600)), 'D' . $revision->getID()); } } $uri = $line_href->alter('before', $commit); $before_link = javelin_tag('a', array('href' => $uri->setQueryParam('view', 'blame'), 'sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Skip Past This Commit'), 'align' => 'E', 'size' => 300)), "«"); } $blame[] = phutil_tag('th', array('class' => 'diffusion-blame-link'), $before_link); $object_links = array(); $object_links[] = $commit_link; if ($revision_link) { $object_links[] = phutil_tag('span', array(), '/'); $object_links[] = $revision_link; } $blame[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links); } $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line['line']); $blame[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link); Javelin::initBehavior('phabricator-line-linker'); if ($line['target']) { Javelin::initBehavior('diffusion-jump-to', array('target' => 'scroll_target')); $anchor_text = phutil_tag('a', array('id' => 'scroll_target'), ''); } else { $anchor_text = null; } $blame[] = phutil_tag('td', array(), array($anchor_text, "", phutil_safe_html(str_replace("\t", ' ', $line['data'])))); if ($this->coverage) { require_celerity_resource('differential-changeset-view-css'); $cov_index = $line['line'] - 1; if (isset($this->coverage[$cov_index])) { $cov_class = $this->coverage[$cov_index]; } else { $cov_class = 'N'; } $blame[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), ''); } $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $blame); $cur_inlines = $this->renderInlines(idx($inlines, $line['line'], array()), $show_blame, $this->coverage, $engine); foreach ($cur_inlines as $cur_inline) { $rows[] = $cur_inline; } } return $rows; }