public function renderLintResult(ArcanistLintResult $result)
 {
     $messages = $result->getMessages();
     $path = $result->getPath();
     $lines = explode("\n", $result->getData());
     $text = array();
     foreach ($messages as $message) {
         if (!$this->showAutofixPatches && $message->isAutofix()) {
             continue;
         }
         if ($message->isError()) {
             $color = 'red';
         } else {
             $color = 'yellow';
         }
         $severity = ArcanistLintSeverity::getStringForSeverity($message->getSeverity());
         $code = $message->getCode();
         $name = $message->getName();
         $description = phutil_console_wrap($message->getDescription(), 4);
         $text[] = phutil_console_format("  **<bg:{$color}> %s </bg>** (%s) __%s__\n%s\n", $severity, $code, $name, $description);
         if ($message->hasFileContext()) {
             $text[] = $this->renderContext($message, $lines);
         }
     }
     if ($text) {
         $prefix = phutil_console_format("**>>>** Lint for __%s__:\n\n\n", $path);
         return $prefix . implode("\n", $text);
     } else {
         return null;
     }
 }
 protected function processDiffusionRequest(AphrontRequest $request)
 {
     $limit = 500;
     $offset = $request->getInt('offset', 0);
     $drequest = $this->getDiffusionRequest();
     $branch = $drequest->loadBranch();
     $messages = $this->loadLintMessages($branch, $limit, $offset);
     $is_dir = substr('/' . $drequest->getPath(), -1) == '/';
     $authors = $this->loadViewerHandles(ipull($messages, 'authorPHID'));
     $rows = array();
     foreach ($messages as $message) {
         $path = phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'lint', 'path' => $message['path']))), substr($message['path'], strlen($drequest->getPath()) + 1));
         $line = phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'browse', 'path' => $message['path'], 'line' => $message['line'], 'commit' => $branch->getLintCommit()))), $message['line']);
         $author = $message['authorPHID'];
         if ($author && $authors[$author]) {
             $author = $authors[$author]->renderLink();
         }
         $rows[] = array($path, $line, $author, ArcanistLintSeverity::getStringForSeverity($message['severity']), $message['name'], $message['description']);
     }
     $table = id(new AphrontTableView($rows))->setHeaders(array(pht('Path'), pht('Line'), pht('Author'), pht('Severity'), pht('Name'), pht('Description')))->setColumnClasses(array('', 'n'))->setColumnVisibility(array($is_dir));
     $content = array();
     $pager = id(new AphrontPagerView())->setPageSize($limit)->setOffset($offset)->setHasMorePages(count($messages) >= $limit)->setURI($request->getRequestURI(), 'offset');
     $content[] = id(new PHUIObjectBoxView())->setHeaderText(pht('Lint Details'))->appendChild($table);
     $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'lint'));
     return $this->buildApplicationPage(array($crumbs, $content, $pager), array('title' => array(pht('Lint'), $drequest->getRepository()->getCallsign())));
 }
 public function renderLintResult(ArcanistLintResult $result)
 {
     $messages = $result->getMessages();
     $path = $result->getPath();
     $text = array();
     foreach ($messages as $message) {
         $name = $message->getName();
         $severity = ArcanistLintSeverity::getStringForSeverity($message->getSeverity());
         $line = $message->getLine();
         $text[] = "{$path}:{$line}:{$severity}: {$name}\n";
     }
     return implode('', $text);
 }
 public function renderLintResult(ArcanistLintResult $result)
 {
     $lines = array();
     $messages = $result->getMessages();
     $path = $result->getPath();
     foreach ($messages as $message) {
         $severity = ArcanistLintSeverity::getStringForSeverity($message->getSeverity());
         $line = $message->getLine();
         $code = $message->getCode();
         $description = $message->getDescription();
         $lines[] = sprintf("%s:%d:%s (%s) %s\n", $path, $line, $severity, $code, $description);
     }
     return implode('', $lines);
 }
 public function renderLintResult(ArcanistLintResult $result)
 {
     $this->writer->startElement('file');
     $this->writer->writeAttribute('name', $result->getPath());
     foreach ($result->getMessages() as $message) {
         $this->writer->startElement('error');
         $this->writer->writeAttribute('line', $message->getLine());
         $this->writer->writeAttribute('column', $message->getChar());
         $this->writer->writeAttribute('severity', ArcanistLintSeverity::getStringForSeverity($message->getSeverity()));
         $this->writer->writeAttribute('message', $message->getDescription());
         $this->writer->writeAttribute('source', $message->getCode());
         $this->writer->endElement();
     }
     $this->writer->endElement();
     return $this->writer->flush();
 }
 public function renderLintResult(ArcanistLintResult $result)
 {
     $messages = $result->getMessages();
     $path = $result->getPath();
     $lines = explode("\n", $result->getData());
     $text = array();
     foreach ($messages as $message) {
         if (!$this->showAutofixPatches && $message->isAutofix()) {
             continue;
         }
         if ($message->isError()) {
             $color = 'red';
         } else {
             $color = 'yellow';
         }
         $severity = ArcanistLintSeverity::getStringForSeverity($message->getSeverity());
         $code = $message->getCode();
         $name = $message->getName();
         $description = $message->getDescription();
         if ($message->getOtherLocations()) {
             $locations = array();
             foreach ($message->getOtherLocations() as $location) {
                 $locations[] = idx($location, 'path', $path) . (!empty($location['line']) ? ":{$location['line']}" : '');
             }
             $description .= "\n" . pht('Other locations: %s', implode(', ', $locations));
         }
         $text[] = phutil_console_format("  **<bg:{$color}> %s </bg>** (%s) __%s__\n%s\n", $severity, $code, $name, phutil_console_wrap($description, 4));
         if ($message->hasFileContext()) {
             $text[] = $this->renderContext($message, $lines);
         }
     }
     if ($text) {
         $prefix = phutil_console_format("**>>>** %s\n\n\n", pht('Lint for %s:', phutil_console_format('__%s__', $path)));
         return $prefix . implode("\n", $text);
     } else {
         return null;
     }
 }
 protected function processDiffusionRequest(AphrontRequest $request)
 {
     $user = $request->getUser();
     $drequest = $this->diffusionRequest;
     if ($request->getStr('lint') !== null) {
         $controller = new DiffusionLintDetailsController();
         $controller->setDiffusionRequest($drequest);
         $controller->setCurrentApplication($this->getCurrentApplication());
         return $this->delegateToController($controller);
     }
     $owners = array();
     if (!$drequest) {
         if (!$request->getArr('owner')) {
             $owners = array($user->getPHID());
         } else {
             $owners = array(head($request->getArr('owner')));
         }
     }
     $codes = $this->loadLintCodes($owners);
     if ($codes && !$drequest) {
         // TODO: Build some real Query classes for this stuff.
         $branches = id(new PhabricatorRepositoryBranch())->loadAllWhere('id IN (%Ld)', array_unique(ipull($codes, 'branchID')));
         $repositories = id(new PhabricatorRepositoryQuery())->setViewer($user)->withIDs(mpull($branches, 'getRepositoryID'))->execute();
         $drequests = array();
         foreach ($branches as $id => $branch) {
             if (empty($repositories[$branch->getRepositoryID()])) {
                 continue;
             }
             $drequests[$id] = DiffusionRequest::newFromDictionary(array('user' => $user, 'repository' => $repositories[$branch->getRepositoryID()], 'branch' => $branch->getName()));
         }
     }
     $rows = array();
     $total = 0;
     foreach ($codes as $code) {
         if (!$this->diffusionRequest) {
             $drequest = idx($drequests, $code['branchID']);
         }
         if (!$drequest) {
             continue;
         }
         $total += $code['n'];
         $href_lint = $drequest->generateURI(array('action' => 'lint', 'lint' => $code['code']));
         $href_browse = $drequest->generateURI(array('action' => 'browse', 'lint' => $code['code']));
         $href_repo = $drequest->generateURI(array('action' => 'lint'));
         $rows[] = array(phutil_tag('a', array('href' => $href_lint), $code['n']), phutil_tag('a', array('href' => $href_browse), $code['files']), phutil_tag('a', array('href' => $href_repo), $drequest->getRepository()->getDisplayName()), ArcanistLintSeverity::getStringForSeverity($code['maxSeverity']), $code['code'], $code['maxName'], $code['maxDescription']);
     }
     $table = id(new AphrontTableView($rows))->setHeaders(array(pht('Problems'), pht('Files'), pht('Repository'), pht('Severity'), pht('Code'), pht('Name'), pht('Example')))->setColumnVisibility(array(true, true, !$this->diffusionRequest))->setColumnClasses(array('n', 'n', '', '', 'pri', '', ''));
     $content = array();
     if (!$this->diffusionRequest) {
         $form = id(new AphrontFormView())->setUser($user)->setMethod('GET')->appendControl(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorPeopleDatasource())->setLimit(1)->setName('owner')->setLabel(pht('Owner'))->setValue($owners))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Filter')));
         $content[] = id(new AphrontListFilterView())->appendChild($form);
     }
     $content[] = id(new PHUIObjectBoxView())->setHeaderText(pht('Lint'))->setTable($table);
     $title = array('Lint');
     $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'lint'));
     if ($this->diffusionRequest) {
         $title[] = $drequest->getRepository()->getDisplayName();
     } else {
         $crumbs->addTextCrumb(pht('All Lint'));
     }
     if ($this->diffusionRequest) {
         $branch = $drequest->loadBranch();
         $header = id(new PHUIHeaderView())->setHeader($this->renderPathLinks($drequest, 'lint'))->setUser($user)->setPolicyObject($drequest->getRepository());
         $actions = $this->buildActionView($drequest);
         $properties = $this->buildPropertyView($drequest, $branch, $total, $actions);
         $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties);
     } else {
         $object_box = null;
     }
     return $this->buildApplicationPage(array($crumbs, $object_box, $content), array('title' => $title));
 }
 private function buildDisplayRows(array $lines, array $blame_list, array $blame_commits, $show_color, $show_blame)
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $revision_map = array();
     $revisions = array();
     if ($blame_commits) {
         $commit_map = mpull($blame_commits, 'getCommitIdentifier', 'getPHID');
         $revision_ids = id(new DifferentialRevision())->loadIDsByCommitPHIDs(array_keys($commit_map));
         if ($revision_ids) {
             $revisions = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs($revision_ids)->execute();
             $revisions = mpull($revisions, null, 'getID');
         }
         foreach ($revision_ids as $commit_phid => $revision_id) {
             $revision_map[$commit_map[$commit_phid]] = $revision_id;
         }
     }
     $phids = array();
     foreach ($blame_commits as $commit) {
         $author_phid = $commit->getAuthorPHID();
         if ($author_phid === null) {
             continue;
         }
         $phids[$author_phid] = $author_phid;
     }
     foreach ($revisions as $revision) {
         $author_phid = $revision->getAuthorPHID();
         if ($author_phid === null) {
             continue;
         }
         $phids[$author_phid] = $author_phid;
     }
     $handles = $viewer->loadHandles($phids);
     $colors = array();
     if ($blame_commits) {
         $epochs = array();
         foreach ($blame_commits as $identifier => $commit) {
             $epochs[$identifier] = $commit->getEpoch();
         }
         $epoch_list = array_filter($epochs);
         $epoch_list = array_unique($epoch_list);
         $epoch_list = array_values($epoch_list);
         $epoch_min = min($epoch_list);
         $epoch_max = max($epoch_list);
         $epoch_range = $epoch_max - $epoch_min + 1;
         foreach ($blame_commits as $identifier => $commit) {
             $epoch = $epochs[$identifier];
             if (!$epoch) {
                 $color = '#ffffdd';
                 // Warning color, missing data.
             } else {
                 $color_ratio = ($epoch - $epoch_min) / $epoch_range;
                 $color_value = 0xe6 * (1.0 - $color_ratio);
                 $color = sprintf('#%02x%02x%02x', $color_value, 0xf6, $color_value);
             }
             $colors[$identifier] = $color;
         }
     }
     $display = array();
     $last_identifier = null;
     $last_color = null;
     foreach ($lines as $line_index => $line) {
         $color = '#f6f6f6';
         $duplicate = false;
         if (isset($blame_list[$line_index])) {
             $identifier = $blame_list[$line_index];
             if (isset($colors[$identifier])) {
                 $color = $colors[$identifier];
             }
             if ($identifier === $last_identifier) {
                 $duplicate = true;
             } else {
                 $last_identifier = $identifier;
             }
         }
         $display[$line_index] = array('data' => $line, 'target' => false, 'highlighted' => false, 'color' => $color, 'duplicate' => $duplicate);
     }
     $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);
             }
         }
     }
     // Mark the first highlighted line as the target line.
     if ($line_arr) {
         $target_line = $line_arr[0]['min'];
         if (isset($display[$target_line - 1])) {
             $display[$target_line - 1]['target'] = true;
         }
     }
     // Mark all other highlighted lines as highlighted.
     foreach ($line_arr as $range) {
         for ($ii = $range['min']; $ii <= $range['max']; $ii++) {
             if (isset($display[$ii - 1])) {
                 $display[$ii - 1]['highlighted'] = true;
             }
         }
     }
     $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);
     // NOTE: We're doing this manually because rendering is otherwise
     // dominated by URI generation for very large files.
     $line_base = (string) $drequest->generateURI(array('action' => 'browse', 'stable' => true));
     require_celerity_resource('aphront-tooltip-css');
     Javelin::initBehavior('phabricator-oncopy');
     Javelin::initBehavior('phabricator-tooltips');
     Javelin::initBehavior('phabricator-line-linker');
     // Render these once, since they tend to get repeated many times in large
     // blame outputs.
     $commit_links = $this->renderCommitLinks($blame_commits, $handles);
     $revision_links = $this->renderRevisionLinks($revisions, $handles);
     $skip_text = pht('Skip Past This Commit');
     foreach ($display as $line_index => $line) {
         $row = array();
         $line_number = $line_index + 1;
         $line_href = $line_base . '$' . $line_number;
         if (isset($blame_list[$line_index])) {
             $identifier = $blame_list[$line_index];
         } else {
             $identifier = null;
         }
         $revision_link = null;
         $commit_link = null;
         $before_link = null;
         $style = 'background: ' . $line['color'] . ';';
         if ($identifier && !$line['duplicate']) {
             if (isset($commit_links[$identifier])) {
                 $commit_link = $commit_links[$identifier];
             }
             if (isset($revision_map[$identifier])) {
                 $revision_id = $revision_map[$identifier];
                 if (isset($revision_links[$revision_id])) {
                     $revision_link = $revision_links[$revision_id];
                 }
             }
             $skip_href = $line_href . '?before=' . $identifier . '&view=blame';
             $before_link = javelin_tag('a', array('href' => $skip_href, 'sigil' => 'has-tooltip', 'meta' => array('tip' => $skip_text, 'align' => 'E', 'size' => 300)), "«");
         }
         $row[] = 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;
         }
         $row[] = phutil_tag('th', array('class' => 'diffusion-rev-link'), $object_links);
         $line_link = phutil_tag('a', array('href' => $line_href, 'style' => $style), $line_number);
         $row[] = javelin_tag('th', array('class' => 'diffusion-line-link', 'sigil' => 'phabricator-source-line', 'style' => $style), $line_link);
         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;
         }
         $row[] = 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_index;
             if (isset($this->coverage[$cov_index])) {
                 $cov_class = $this->coverage[$cov_index];
             } else {
                 $cov_class = 'N';
             }
             $row[] = phutil_tag('td', array('class' => 'cov cov-' . $cov_class), '');
         }
         $rows[] = phutil_tag('tr', array('class' => $line['highlighted'] ? 'phabricator-source-highlight' : null), $row);
         $cur_inlines = $this->renderInlines(idx($inlines, $line_number, array()), $show_blame, $this->coverage, $engine);
         foreach ($cur_inlines as $cur_inline) {
             $rows[] = $cur_inline;
         }
     }
     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;
 }
 private function buildDetailsResponse()
 {
     $request = $this->getRequest();
     $limit = 500;
     $pager = id(new PHUIPagerView())->readFromRequest($request)->setPageSize($limit);
     $offset = $pager->getOffset();
     $drequest = $this->getDiffusionRequest();
     $branch = $drequest->loadBranch();
     $messages = $this->loadLintMessages($branch, $limit, $offset);
     $is_dir = substr('/' . $drequest->getPath(), -1) == '/';
     $pager->setHasMorePages(count($messages) >= $limit);
     $authors = $this->loadViewerHandles(ipull($messages, 'authorPHID'));
     $rows = array();
     foreach ($messages as $message) {
         $path = phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'lint', 'path' => $message['path']))), substr($message['path'], strlen($drequest->getPath()) + 1));
         $line = phutil_tag('a', array('href' => $drequest->generateURI(array('action' => 'browse', 'path' => $message['path'], 'line' => $message['line'], 'commit' => $branch->getLintCommit()))), $message['line']);
         $author = $message['authorPHID'];
         if ($author && $authors[$author]) {
             $author = $authors[$author]->renderLink();
         }
         $rows[] = array($path, $line, $author, ArcanistLintSeverity::getStringForSeverity($message['severity']), $message['name'], $message['description']);
     }
     $table = id(new AphrontTableView($rows))->setHeaders(array(pht('Path'), pht('Line'), pht('Author'), pht('Severity'), pht('Name'), pht('Description')))->setColumnClasses(array('', 'n'))->setColumnVisibility(array($is_dir));
     $content = array();
     $content[] = id(new PHUIObjectBoxView())->setHeaderText(pht('Lint Details'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setTable($table);
     $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'lint'));
     $pager_box = $this->renderTablePagerBox($pager);
     $header = id(new PHUIHeaderView())->setHeader(pht('Lint: %s', $drequest->getRepository()->getDisplayName()))->setHeaderIcon('fa-code');
     $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($content, $pager_box));
     return $this->newPage()->setTitle(array(pht('Lint'), $drequest->getRepository()->getDisplayName()))->setCrumbs($crumbs)->appendChild(array($view));
 }