public function render()
 {
     $old = $this->oldText;
     $new = $this->newText;
     // TODO: On mobile, or perhaps by default, we should switch to 1-up once
     // that is built.
     if (strlen($old)) {
         $old = phutil_utf8_hard_wrap($old, 80);
         $old = implode("\n", $old) . "\n";
     }
     if (strlen($new)) {
         $new = phutil_utf8_hard_wrap($new, 80);
         $new = implode("\n", $new) . "\n";
     }
     try {
         $engine = new PhabricatorDifferenceEngine();
         $changeset = $engine->generateChangesetFromFileContent($old, $new);
         $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL;
         $markup_engine = new PhabricatorMarkupEngine();
         $markup_engine->setViewer($this->getUser());
         $parser = new DifferentialChangesetParser();
         $parser->setUser($this->getUser());
         $parser->setChangeset($changeset);
         $parser->setMarkupEngine($markup_engine);
         $parser->setWhitespaceMode($whitespace_mode);
         return $parser->render(0, PHP_INT_MAX, array());
     } catch (Exception $ex) {
         return $ex->getMessage();
     }
 }
 public function processRequest()
 {
     $drequest = $this->getDiffusionRequest();
     $request = $this->getRequest();
     $user = $request->getUser();
     if (!$request->isAjax()) {
         // This request came out of the dropdown menu, either "View Standalone"
         // or "View Raw File".
         $view = $request->getStr('view');
         if ($view == 'r') {
             $uri = $drequest->generateURI(array('action' => 'browse', 'params' => array('view' => 'raw')));
         } else {
             $uri = $drequest->generateURI(array('action' => 'change'));
         }
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     $diff_query = DiffusionDiffQuery::newFromDiffusionRequest($drequest);
     $changeset = $diff_query->loadChangeset();
     if (!$changeset) {
         return new Aphront404Response();
     }
     $parser = new DifferentialChangesetParser();
     $parser->setUser($user);
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($diff_query->getRenderingReference());
     $parser->setMarkupEngine(PhabricatorMarkupEngine::newDiffusionMarkupEngine());
     $pquery = new DiffusionPathIDQuery(array($changeset->getFilename()));
     $ids = $pquery->loadPathIDs();
     $path_id = $ids[$changeset->getFilename()];
     $parser->setLeftSideCommentMapping($path_id, false);
     $parser->setRightSideCommentMapping($path_id, true);
     $parser->setWhitespaceMode(DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
     $inlines = id(new PhabricatorAuditInlineComment())->loadAllWhere('commitPHID = %s AND pathID = %d AND
     (authorPHID = %s OR auditCommentID IS NOT NULL)', $drequest->loadCommit()->getPHID(), $path_id, $user->getPHID());
     if ($inlines) {
         foreach ($inlines as $inline) {
             $parser->parseInlineComment($inline);
         }
         $phids = mpull($inlines, 'getAuthorPHID');
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $parser->setHandles($handles);
     }
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $output = $parser->render($range_s, $range_e, $mask);
     return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output);
 }
 public function processRequest()
 {
     $drequest = $this->getDiffusionRequest();
     $request = $this->getRequest();
     $diff_query = DiffusionDiffQuery::newFromDiffusionRequest($drequest);
     $changeset = $diff_query->loadChangeset();
     if (!$changeset) {
         return new Aphront404Response();
     }
     $parser = new DifferentialChangesetParser();
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($diff_query->getRenderingReference());
     $parser->setWhitespaceMode(DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $output = $parser->render($range_s, $range_e, $mask);
     return id(new AphrontAjaxResponse())->setContent($output);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->id))->needContent(true)->executeOne();
     if (!$document) {
         return new Aphront404Response();
     }
     $current = $document->getContent();
     $l = $request->getInt('l');
     $r = $request->getInt('r');
     $ref = $request->getStr('ref');
     if ($ref) {
         list($l, $r) = explode(',', $ref);
     }
     $content = id(new PhrictionContent())->loadAllWhere('documentID = %d AND version IN (%Ld)', $document->getID(), array($l, $r));
     $content = mpull($content, null, 'getVersion');
     $content_l = idx($content, $l, null);
     $content_r = idx($content, $r, null);
     if (!$content_l || !$content_r) {
         return new Aphront404Response();
     }
     $text_l = $content_l->getContent();
     $text_r = $content_r->getContent();
     $text_l = phutil_utf8_hard_wrap($text_l, 80);
     $text_l = implode("\n", $text_l);
     $text_r = phutil_utf8_hard_wrap($text_r, 80);
     $text_r = implode("\n", $text_r);
     $engine = new PhabricatorDifferenceEngine();
     $changeset = $engine->generateChangesetFromFileContent($text_l, $text_r);
     $changeset->setOldProperties(array('Title' => $content_l->getTitle()));
     $changeset->setNewProperties(array('Title' => $content_r->getTitle()));
     $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL;
     $parser = new DifferentialChangesetParser();
     $parser->setChangeset($changeset);
     $parser->setRenderingReference("{$l},{$r}");
     $parser->setWhitespaceMode($whitespace_mode);
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($user);
     $engine->process();
     $parser->setMarkupEngine($engine);
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $output = $parser->render($range_s, $range_e, $mask);
     if ($request->isAjax()) {
         return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output);
     }
     require_celerity_resource('differential-changeset-view-css');
     require_celerity_resource('syntax-highlighting-css');
     require_celerity_resource('phriction-document-css');
     Javelin::initBehavior('differential-show-more', array('uri' => '/phriction/diff/' . $document->getID() . '/', 'whitespace' => $whitespace_mode));
     $slug = $document->getSlug();
     $revert_l = $this->renderRevertButton($content_l, $current);
     $revert_r = $this->renderRevertButton($content_r, $current);
     $crumbs = $this->buildApplicationCrumbs();
     $crumb_views = $this->renderBreadcrumbs($slug);
     foreach ($crumb_views as $view) {
         $crumbs->addCrumb($view);
     }
     $crumbs->addTextCrumb(pht('History'), PhrictionDocument::getSlugURI($slug, 'history'));
     $title = pht('Version %s vs %s', $l, $r);
     $header = id(new PHUIHeaderView())->setHeader($title);
     $crumbs->addTextCrumb($title, $request->getRequestURI());
     $comparison_table = $this->renderComparisonTable(array($content_r, $content_l));
     $navigation_table = null;
     if ($l + 1 == $r) {
         $nav_l = $l > 1;
         $nav_r = $r != $current->getVersion();
         $uri = $request->getRequestURI();
         if ($nav_l) {
             $link_l = phutil_tag('a', array('href' => $uri->alter('l', $l - 1)->alter('r', $r - 1), 'class' => 'button'), pht("« Previous Change"));
         } else {
             $link_l = phutil_tag('a', array('href' => '#', 'class' => 'button grey disabled'), pht('Original Change'));
         }
         $link_r = null;
         if ($nav_r) {
             $link_r = phutil_tag('a', array('href' => $uri->alter('l', $l + 1)->alter('r', $r + 1), 'class' => 'button'), pht("Next Change »"));
         } else {
             $link_r = phutil_tag('a', array('href' => '#', 'class' => 'button grey disabled'), pht('Most Recent Change'));
         }
         $navigation_table = phutil_tag('table', array('class' => 'phriction-history-nav-table'), phutil_tag('tr', array(), array(phutil_tag('td', array('class' => 'nav-prev'), $link_l), phutil_tag('td', array('class' => 'nav-next'), $link_r))));
     }
     $output = hsprintf('<div class="phriction-document-history-diff">' . '%s%s' . '<table class="phriction-revert-table">' . '<tr><td>%s</td><td>%s</td>' . '</table>' . '%s' . '</div>', $comparison_table->render(), $navigation_table, $revert_l, $revert_r, $output);
     $object_box = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($output);
     return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => pht('Document History')));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $author_phid = $request->getUser()->getPHID();
     $rendering_reference = $request->getStr('ref');
     $parts = explode('/', $rendering_reference);
     if (count($parts) == 2) {
         list($id, $vs) = $parts;
     } else {
         $id = $parts[0];
         $vs = 0;
     }
     $id = (int) $id;
     $vs = (int) $vs;
     $changeset = id(new DifferentialChangeset())->load($id);
     if (!$changeset) {
         return new Aphront404Response();
     }
     $view = $request->getStr('view');
     if ($view) {
         $changeset->attachHunks($changeset->loadHunks());
         switch ($view) {
             case 'new':
                 return $this->buildRawFileResponse($changeset->makeNewFile());
             case 'old':
                 return $this->buildRawFileResponse($changeset->makeOldFile());
             default:
                 return new Aphront400Response();
         }
     }
     if ($vs && $vs != -1) {
         $vs_changeset = id(new DifferentialChangeset())->load($vs);
         if (!$vs_changeset) {
             return new Aphront404Response();
         }
     }
     if (!$vs) {
         $right = $changeset;
         $left = null;
         $right_source = $right->getID();
         $right_new = true;
         $left_source = $right->getID();
         $left_new = false;
         $render_cache_key = $right->getID();
     } else {
         if ($vs == -1) {
             $right = null;
             $left = $changeset;
             $right_source = $left->getID();
             $right_new = false;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         } else {
             $right = $changeset;
             $left = $vs_changeset;
             $right_source = $right->getID();
             $right_new = true;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         }
     }
     if ($left) {
         $left->attachHunks($left->loadHunks());
     }
     if ($right) {
         $right->attachHunks($right->loadHunks());
     }
     if ($left) {
         $left_data = $left->makeNewFile();
         if ($right) {
             $right_data = $right->makeNewFile();
         } else {
             $right_data = $left->makeOldFile();
         }
         $engine = new PhabricatorDifferenceEngine();
         $synthetic = $engine->generateChangesetFromFileContent($left_data, $right_data);
         $choice = nonempty($left, $right);
         $choice->attachHunks($synthetic->getHunks());
         $changeset = $choice;
         $changeset->setID(null);
     }
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $parser = new DifferentialChangesetParser();
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($rendering_reference);
     $parser->setRenderCacheKey($render_cache_key);
     $parser->setRightSideCommentMapping($right_source, $right_new);
     $parser->setLeftSideCommentMapping($left_source, $left_new);
     $parser->setWhitespaceMode($request->getStr('whitespace'));
     // Load both left-side and right-side inline comments.
     $inlines = $this->loadInlineComments(array($left_source, $right_source), $author_phid);
     $phids = array();
     foreach ($inlines as $inline) {
         $parser->parseInlineComment($inline);
         $phids[$inline->getAuthorPHID()] = true;
     }
     $phids = array_keys($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $parser->setHandles($handles);
     $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
     $parser->setMarkupEngine($engine);
     if ($request->isAjax()) {
         // TODO: This is sort of lazy, the effect is just to not render "Edit"
         // links on the "standalone view".
         $parser->setUser($request->getUser());
     }
     $output = $parser->render($range_s, $range_e, $mask);
     if ($request->isAjax()) {
         return id(new AphrontAjaxResponse())->setContent($output);
     }
     Javelin::initBehavior('differential-show-more', array('uri' => '/differential/changeset/', 'whitespace' => $request->getStr('whitespace')));
     Javelin::initBehavior('differential-comment-jump', array());
     $detail = new DifferentialChangesetDetailView();
     $detail->setChangeset($changeset);
     $detail->appendChild($output);
     if (!$vs) {
         $detail->addButton(phutil_render_tag('a', array('href' => $request->getRequestURI()->alter('view', 'old'), 'class' => 'grey button small'), 'View Raw File (Old Version)'));
         $detail->addButton(phutil_render_tag('a', array('href' => $request->getRequestURI()->alter('view', 'new'), 'class' => 'grey button small'), 'View Raw File (New Version)'));
     }
     $detail->setRevisionID($request->getInt('revision_id'));
     $output = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets(array($changeset))->appendChild('<div class="differential-review-stage" ' . 'id="differential-review-stage">' . $detail->render() . '</div>');
     return $this->buildStandardPageResponse(array($output), array('title' => 'Changeset View'));
 }
 private function renderFullSummary($transaction)
 {
     switch ($transaction->getTransactionType()) {
         case ManiphestTransactionType::TYPE_DESCRIPTION:
             $id = $transaction->getID();
             $old_text = wordwrap($transaction->getOldValue(), 80);
             $new_text = wordwrap($transaction->getNewValue(), 80);
             $engine = new PhabricatorDifferenceEngine();
             $changeset = $engine->generateChangesetFromFileContent($old_text, $new_text);
             $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL;
             $parser = new DifferentialChangesetParser();
             $parser->setChangeset($changeset);
             $parser->setRenderingReference($id);
             $parser->setWhitespaceMode($whitespace_mode);
             $spec = $this->getRangeSpecification();
             list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
             $output = $parser->render($range_s, $range_e, $mask);
             return $output;
     }
     return null;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $document = id(new PhrictionDocument())->load($this->id);
     if (!$document) {
         return new Aphront404Response();
     }
     $current = id(new PhrictionContent())->load($document->getContentID());
     $l = $request->getInt('l');
     $r = $request->getInt('r');
     $ref = $request->getStr('ref');
     if ($ref) {
         list($l, $r) = explode(',', $ref);
     }
     $content = id(new PhrictionContent())->loadAllWhere('documentID = %d AND version IN (%Ld)', $document->getID(), array($l, $r));
     $content = mpull($content, null, 'getVersion');
     $content_l = idx($content, $l, null);
     $content_r = idx($content, $r, null);
     if (!$content_l || !$content_r) {
         return new Aphront404Response();
     }
     $text_l = $content_l->getContent();
     $text_r = $content_r->getContent();
     $text_l = wordwrap($text_l, 80);
     $text_r = wordwrap($text_r, 80);
     $engine = new PhabricatorDifferenceEngine();
     $changeset = $engine->generateChangesetFromFileContent($text_l, $text_r);
     $changeset->setOldProperties(array('Title' => $content_l->getTitle()));
     $changeset->setNewProperties(array('Title' => $content_r->getTitle()));
     $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL;
     $parser = new DifferentialChangesetParser();
     $parser->setChangeset($changeset);
     $parser->setRenderingReference("{$l},{$r}");
     $parser->setWhitespaceMode($whitespace_mode);
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $output = $parser->render($range_s, $range_e, $mask);
     if ($request->isAjax()) {
         return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output);
     }
     require_celerity_resource('differential-changeset-view-css');
     require_celerity_resource('syntax-highlighting-css');
     require_celerity_resource('phriction-document-css');
     Javelin::initBehavior('differential-show-more', array('uri' => '/phriction/diff/' . $document->getID() . '/', 'whitespace' => $whitespace_mode));
     $slug = $document->getSlug();
     $revert_l = $this->renderRevertButton($content_l, $current);
     $revert_r = $this->renderRevertButton($content_r, $current);
     $crumbs = new AphrontCrumbsView();
     $crumbs->setCrumbs(array('Phriction', phutil_render_tag('a', array('href' => PhrictionDocument::getSlugURI($slug)), phutil_escape_html($current->getTitle())), phutil_render_tag('a', array('href' => '/phriction/history/' . $document->getSlug() . '/'), 'History'), phutil_escape_html("Changes Between Version {$l} and Version {$r}")));
     $comparison_table = $this->renderComparisonTable(array($content_r, $content_l));
     $navigation_table = null;
     if ($l + 1 == $r) {
         $nav_l = $l > 1;
         $nav_r = $r != $current->getVersion();
         $uri = $request->getRequestURI();
         if ($nav_l) {
             $link_l = phutil_render_tag('a', array('href' => $uri->alter('l', $l - 1)->alter('r', $r - 1)), "« Previous Change");
         } else {
             $link_l = 'Original Change';
         }
         $link_r = null;
         if ($nav_r) {
             $link_r = phutil_render_tag('a', array('href' => $uri->alter('l', $l + 1)->alter('r', $r + 1)), "Next Change »");
         } else {
             $link_r = 'Most Recent Change';
         }
         $navigation_table = '<table class="phriction-history-nav-table">
       <tr>
         <td class="nav-prev">' . $link_l . '</td>
         <td class="nav-next">' . $link_r . '</td>
       </tr>
     </table>';
     }
     $output = '<div class="phriction-document-history-diff">' . $comparison_table->render() . '<br />' . '<br />' . $navigation_table . '<table class="phriction-revert-table">' . '<tr><td>' . $revert_l . '</td><td>' . $revert_r . '</td>' . '</table>' . $output . '</div>';
     return $this->buildStandardPageResponse(array($crumbs, $output), array('title' => 'Document History'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $author_phid = $request->getUser()->getPHID();
     $rendering_reference = $request->getStr('ref');
     $parts = explode('/', $rendering_reference);
     if (count($parts) == 2) {
         list($id, $vs) = $parts;
     } else {
         $id = $parts[0];
         $vs = 0;
     }
     $id = (int) $id;
     $vs = (int) $vs;
     $changeset = id(new DifferentialChangeset())->load($id);
     if (!$changeset) {
         return new Aphront404Response();
     }
     $view = $request->getStr('view');
     if ($view) {
         $changeset->attachHunks($changeset->loadHunks());
         $phid = idx($changeset->getMetadata(), "{$view}:binary-phid");
         if ($phid) {
             return id(new AphrontRedirectResponse())->setURI("/file/info/{$phid}/");
         }
         switch ($view) {
             case 'new':
                 return $this->buildRawFileResponse($changeset, $is_new = true);
             case 'old':
                 if ($vs && $vs != -1) {
                     $vs_changeset = id(new DifferentialChangeset())->load($vs);
                     if ($vs_changeset) {
                         $vs_changeset->attachHunks($vs_changeset->loadHunks());
                         return $this->buildRawFileResponse($vs_changeset, $is_new = true);
                     }
                 }
                 return $this->buildRawFileResponse($changeset, $is_new = false);
             default:
                 return new Aphront400Response();
         }
     }
     if ($vs && $vs != -1) {
         $vs_changeset = id(new DifferentialChangeset())->load($vs);
         if (!$vs_changeset) {
             return new Aphront404Response();
         }
     }
     if (!$vs) {
         $right = $changeset;
         $left = null;
         $right_source = $right->getID();
         $right_new = true;
         $left_source = $right->getID();
         $left_new = false;
         $render_cache_key = $right->getID();
     } else {
         if ($vs == -1) {
             $right = null;
             $left = $changeset;
             $right_source = $left->getID();
             $right_new = false;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         } else {
             $right = $changeset;
             $left = $vs_changeset;
             $right_source = $right->getID();
             $right_new = true;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         }
     }
     if ($left) {
         $left->attachHunks($left->loadHunks());
     }
     if ($right) {
         $right->attachHunks($right->loadHunks());
     }
     if ($left) {
         $left_data = $left->makeNewFile();
         if ($right) {
             $right_data = $right->makeNewFile();
         } else {
             $right_data = $left->makeOldFile();
         }
         $engine = new PhabricatorDifferenceEngine();
         $synthetic = $engine->generateChangesetFromFileContent($left_data, $right_data);
         $choice = clone nonempty($left, $right);
         $choice->attachHunks($synthetic->getHunks());
         $changeset = $choice;
     }
     $coverage = null;
     if ($right && $right->getDiffID()) {
         $unit = id(new DifferentialDiffProperty())->loadOneWhere('diffID = %d AND name = %s', $right->getDiffID(), 'arc:unit');
         if ($unit) {
             $coverage = array();
             foreach ($unit->getData() as $result) {
                 $result_coverage = idx($result, 'coverage');
                 if (!$result_coverage) {
                     continue;
                 }
                 $file_coverage = idx($result_coverage, $right->getFileName());
                 if (!$file_coverage) {
                     continue;
                 }
                 $coverage[] = $file_coverage;
             }
             $coverage = ArcanistUnitTestResult::mergeCoverage($coverage);
         }
     }
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $parser = new DifferentialChangesetParser();
     $parser->setCoverage($coverage);
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($rendering_reference);
     $parser->setRenderCacheKey($render_cache_key);
     $parser->setRightSideCommentMapping($right_source, $right_new);
     $parser->setLeftSideCommentMapping($left_source, $left_new);
     $parser->setWhitespaceMode($request->getStr('whitespace'));
     if ($left && $right) {
         $parser->setOriginals($left, $right);
     }
     // Load both left-side and right-side inline comments.
     $inlines = $this->loadInlineComments(array($left_source, $right_source), $author_phid);
     if ($left_new) {
         $inlines = array_merge($inlines, $this->buildLintInlineComments($left));
     }
     if ($right_new) {
         $inlines = array_merge($inlines, $this->buildLintInlineComments($right));
     }
     $phids = array();
     foreach ($inlines as $inline) {
         $parser->parseInlineComment($inline);
         if ($inline->getAuthorPHID()) {
             $phids[$inline->getAuthorPHID()] = true;
         }
     }
     $phids = array_keys($phids);
     $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
     $parser->setHandles($handles);
     $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
     $parser->setMarkupEngine($engine);
     if ($request->isAjax()) {
         // TODO: This is sort of lazy, the effect is just to not render "Edit"
         // and "Reply" links on the "standalone view".
         $parser->setUser($request->getUser());
     }
     $output = $parser->render($range_s, $range_e, $mask);
     $mcov = $parser->renderModifiedCoverage();
     if ($request->isAjax()) {
         $coverage = array('differential-mcoverage-' . md5($changeset->getFilename()) => $mcov);
         return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output)->setCoverage($coverage);
     }
     Javelin::initBehavior('differential-show-more', array('uri' => '/differential/changeset/', 'whitespace' => $request->getStr('whitespace')));
     Javelin::initBehavior('differential-comment-jump', array());
     $detail = new DifferentialChangesetDetailView();
     $detail->setChangeset($changeset);
     $detail->appendChild($output);
     $detail->setVsChangesetID($left_source);
     $output = id(new DifferentialPrimaryPaneView())->setLineWidthFromChangesets(array($changeset))->appendChild('<div class="differential-review-stage" ' . 'id="differential-review-stage">' . $detail->render() . '</div>');
     return $this->buildStandardPageResponse(array($output), array('title' => 'Changeset View'));
 }
 public function handleRequest(AphrontRequest $request)
 {
     $response = $this->loadDiffusionContext();
     if ($response) {
         return $response;
     }
     $viewer = $this->getViewer();
     $drequest = $this->getDiffusionRequest();
     if (!$request->isAjax()) {
         // This request came out of the dropdown menu, either "View Standalone"
         // or "View Raw File".
         $view = $request->getStr('view');
         if ($view == 'r') {
             $uri = $drequest->generateURI(array('action' => 'browse', 'params' => array('view' => 'raw')));
         } else {
             $uri = $drequest->generateURI(array('action' => 'change'));
         }
         return id(new AphrontRedirectResponse())->setURI($uri);
     }
     $data = $this->callConduitWithDiffusionRequest('diffusion.diffquery', array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath()));
     $drequest->updateSymbolicCommit($data['effectiveCommit']);
     $raw_changes = ArcanistDiffChange::newFromConduit($data['changes']);
     $diff = DifferentialDiff::newEphemeralFromRawChanges($raw_changes);
     $changesets = $diff->getChangesets();
     $changeset = reset($changesets);
     if (!$changeset) {
         return new Aphront404Response();
     }
     $parser = new DifferentialChangesetParser();
     $parser->setUser($viewer);
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($drequest->generateURI(array('action' => 'rendering-ref')));
     $parser->readParametersFromRequest($request);
     $coverage = $drequest->loadCoverage();
     if ($coverage) {
         $parser->setCoverage($coverage);
     }
     $commit = $drequest->loadCommit();
     $pquery = new DiffusionPathIDQuery(array($changeset->getFilename()));
     $ids = $pquery->loadPathIDs();
     $path_id = $ids[$changeset->getFilename()];
     $parser->setLeftSideCommentMapping($path_id, false);
     $parser->setRightSideCommentMapping($path_id, true);
     $parser->setCanMarkDone($commit->getAuthorPHID() && $viewer->getPHID() == $commit->getAuthorPHID());
     $parser->setObjectOwnerPHID($commit->getAuthorPHID());
     $parser->setWhitespaceMode(DifferentialChangesetParser::WHITESPACE_SHOW_ALL);
     $inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments($viewer, $commit->getPHID(), $path_id);
     if ($inlines) {
         foreach ($inlines as $inline) {
             $parser->parseInlineComment($inline);
         }
         $phids = mpull($inlines, 'getAuthorPHID');
         $handles = $this->loadViewerHandles($phids);
         $parser->setHandles($handles);
     }
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($viewer);
     foreach ($inlines as $inline) {
         $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
     }
     $engine->process();
     $parser->setMarkupEngine($engine);
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $parser->setRange($range_s, $range_e);
     $parser->setMask($mask);
     return id(new PhabricatorChangesetResponse())->setRenderedChangeset($parser->renderChangeset())->setUndoTemplates($parser->getRenderer()->renderUndoTemplates());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $author_phid = $request->getUser()->getPHID();
     $rendering_reference = $request->getStr('ref');
     $parts = explode('/', $rendering_reference);
     if (count($parts) == 2) {
         list($id, $vs) = $parts;
     } else {
         $id = $parts[0];
         $vs = 0;
     }
     $id = (int) $id;
     $vs = (int) $vs;
     $load_ids = array($id);
     if ($vs && $vs != -1) {
         $load_ids[] = $vs;
     }
     $changesets = id(new DifferentialChangesetQuery())->setViewer($request->getUser())->withIDs($load_ids)->needHunks(true)->execute();
     $changesets = mpull($changesets, null, 'getID');
     $changeset = idx($changesets, $id);
     if (!$changeset) {
         return new Aphront404Response();
     }
     $vs_changeset = null;
     if ($vs && $vs != -1) {
         $vs_changeset = idx($changesets, $vs);
         if (!$vs_changeset) {
             return new Aphront404Response();
         }
     }
     $view = $request->getStr('view');
     if ($view) {
         $phid = idx($changeset->getMetadata(), "{$view}:binary-phid");
         if ($phid) {
             return id(new AphrontRedirectResponse())->setURI("/file/info/{$phid}/");
         }
         switch ($view) {
             case 'new':
                 return $this->buildRawFileResponse($changeset, $is_new = true);
             case 'old':
                 if ($vs_changeset) {
                     return $this->buildRawFileResponse($vs_changeset, $is_new = true);
                 }
                 return $this->buildRawFileResponse($changeset, $is_new = false);
             default:
                 return new Aphront400Response();
         }
     }
     if (!$vs) {
         $right = $changeset;
         $left = null;
         $right_source = $right->getID();
         $right_new = true;
         $left_source = $right->getID();
         $left_new = false;
         $render_cache_key = $right->getID();
     } else {
         if ($vs == -1) {
             $right = null;
             $left = $changeset;
             $right_source = $left->getID();
             $right_new = false;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         } else {
             $right = $changeset;
             $left = $vs_changeset;
             $right_source = $right->getID();
             $right_new = true;
             $left_source = $left->getID();
             $left_new = true;
             $render_cache_key = null;
         }
     }
     if ($left) {
         $left_data = $left->makeNewFile();
         if ($right) {
             $right_data = $right->makeNewFile();
         } else {
             $right_data = $left->makeOldFile();
         }
         $engine = new PhabricatorDifferenceEngine();
         $synthetic = $engine->generateChangesetFromFileContent($left_data, $right_data);
         $choice = clone nonempty($left, $right);
         $choice->attachHunks($synthetic->getHunks());
         $changeset = $choice;
     }
     $coverage = null;
     if ($right && $right->getDiffID()) {
         $unit = id(new DifferentialDiffProperty())->loadOneWhere('diffID = %d AND name = %s', $right->getDiffID(), 'arc:unit');
         if ($unit) {
             $coverage = array();
             foreach ($unit->getData() as $result) {
                 $result_coverage = idx($result, 'coverage');
                 if (!$result_coverage) {
                     continue;
                 }
                 $file_coverage = idx($result_coverage, $right->getFileName());
                 if (!$file_coverage) {
                     continue;
                 }
                 $coverage[] = $file_coverage;
             }
             $coverage = ArcanistUnitTestResult::mergeCoverage($coverage);
         }
     }
     $spec = $request->getStr('range');
     list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec);
     $parser = new DifferentialChangesetParser();
     $parser->setCoverage($coverage);
     $parser->setChangeset($changeset);
     $parser->setRenderingReference($rendering_reference);
     $parser->setRenderCacheKey($render_cache_key);
     $parser->setRightSideCommentMapping($right_source, $right_new);
     $parser->setLeftSideCommentMapping($left_source, $left_new);
     $parser->setWhitespaceMode($request->getStr('whitespace'));
     $parser->setCharacterEncoding($request->getStr('encoding'));
     $parser->setHighlightAs($request->getStr('highlight'));
     if ($request->getStr('renderer') == '1up') {
         $parser->setRenderer(new DifferentialChangesetOneUpRenderer());
     }
     if ($left && $right) {
         $parser->setOriginals($left, $right);
     }
     // Load both left-side and right-side inline comments.
     $inlines = $this->loadInlineComments(array($left_source, $right_source), $author_phid);
     if ($left_new) {
         $inlines = array_merge($inlines, $this->buildLintInlineComments($left));
     }
     if ($right_new) {
         $inlines = array_merge($inlines, $this->buildLintInlineComments($right));
     }
     $phids = array();
     foreach ($inlines as $inline) {
         $parser->parseInlineComment($inline);
         if ($inline->getAuthorPHID()) {
             $phids[$inline->getAuthorPHID()] = true;
         }
     }
     $phids = array_keys($phids);
     $handles = $this->loadViewerHandles($phids);
     $parser->setHandles($handles);
     $engine = new PhabricatorMarkupEngine();
     $engine->setViewer($request->getUser());
     foreach ($inlines as $inline) {
         $engine->addObject($inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
     }
     $engine->process();
     $parser->setMarkupEngine($engine);
     if ($request->isAjax()) {
         // TODO: This is sort of lazy, the effect is just to not render "Edit"
         // and "Reply" links on the "standalone view".
         $parser->setUser($request->getUser());
     }
     $output = $parser->render($range_s, $range_e, $mask);
     $mcov = $parser->renderModifiedCoverage();
     if ($request->isAjax()) {
         $coverage = array('differential-mcoverage-' . md5($changeset->getFilename()) => $mcov);
         return id(new PhabricatorChangesetResponse())->setRenderedChangeset($output)->setCoverage($coverage);
     }
     Javelin::initBehavior('differential-show-more', array('uri' => '/differential/changeset/', 'whitespace' => $request->getStr('whitespace')));
     Javelin::initBehavior('differential-comment-jump', array());
     // TODO: [HTML] Clean up DifferentialChangesetParser output, but it's
     // undergoing like six kinds of refactoring anyway.
     $output = phutil_safe_html($output);
     $detail = new DifferentialChangesetDetailView();
     $detail->setChangeset($changeset);
     $detail->appendChild($output);
     $detail->setVsChangesetID($left_source);
     $panel = new DifferentialPrimaryPaneView();
     $panel->appendChild(phutil_tag('div', array('class' => 'differential-review-stage', 'id' => 'differential-review-stage'), $detail->render()));
     $crumbs = $this->buildApplicationCrumbs();
     $revision_id = $changeset->getDiff()->getRevisionID();
     if ($revision_id) {
         $crumbs->addTextCrumb('D' . $revision_id, '/D' . $revision_id);
     }
     $diff_id = $changeset->getDiff()->getID();
     if ($diff_id) {
         $crumbs->addTextCrumb(pht('Diff %d', $diff_id), $this->getApplicationURI('diff/' . $diff_id));
     }
     $crumbs->addTextCrumb($changeset->getDisplayFilename());
     $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Standalone View'))->appendChild($panel);
     return $this->buildApplicationPage(array($crumbs, $box), array('title' => pht('Changeset View'), 'device' => false));
 }