Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14783830
D14942.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
90 KB
Referenced Files
None
Subscribers
None
D14942.id.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -533,12 +533,8 @@
'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php',
'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php',
'DiffusionBrowseController' => 'applications/diffusion/controller/DiffusionBrowseController.php',
- 'DiffusionBrowseDirectoryController' => 'applications/diffusion/controller/DiffusionBrowseDirectoryController.php',
- 'DiffusionBrowseFileController' => 'applications/diffusion/controller/DiffusionBrowseFileController.php',
- 'DiffusionBrowseMainController' => 'applications/diffusion/controller/DiffusionBrowseMainController.php',
'DiffusionBrowseQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php',
'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php',
- 'DiffusionBrowseSearchController' => 'applications/diffusion/controller/DiffusionBrowseSearchController.php',
'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php',
'DiffusionCachedResolveRefsQuery' => 'applications/diffusion/query/DiffusionCachedResolveRefsQuery.php',
'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php',
@@ -4501,12 +4497,8 @@
'DiffusionBranchTableController' => 'DiffusionController',
'DiffusionBranchTableView' => 'DiffusionView',
'DiffusionBrowseController' => 'DiffusionController',
- 'DiffusionBrowseDirectoryController' => 'DiffusionBrowseController',
- 'DiffusionBrowseFileController' => 'DiffusionBrowseController',
- 'DiffusionBrowseMainController' => 'DiffusionBrowseController',
'DiffusionBrowseQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionBrowseResultSet' => 'Phobject',
- 'DiffusionBrowseSearchController' => 'DiffusionBrowseController',
'DiffusionBrowseTableView' => 'DiffusionView',
'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery',
'DiffusionChangeController' => 'DiffusionController',
diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
--- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
+++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php
@@ -70,7 +70,7 @@
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
'change/(?P<dblob>.*)' => 'DiffusionChangeController',
'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
- 'browse/(?P<dblob>.*)' => 'DiffusionBrowseMainController',
+ 'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
'diff/' => 'DiffusionDiffController',
'tags/(?P<dblob>.*)' => 'DiffusionTagListController',
diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php
--- a/src/applications/diffusion/controller/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseController.php
@@ -1,11 +1,1485 @@
<?php
-abstract class DiffusionBrowseController extends DiffusionController {
+final class DiffusionBrowseController extends DiffusionController {
+
+ private $lintCommit;
+ private $lintMessages;
+ private $coverage;
public function shouldAllowPublic() {
return true;
}
+ public function handleRequest(AphrontRequest $request) {
+ $response = $this->loadDiffusionContext();
+ if ($response) {
+ return $response;
+ }
+
+ $drequest = $this->getDiffusionRequest();
+
+ // Figure out if we're browsing a directory, a file, or a search result
+ // list.
+
+ $grep = $request->getStr('grep');
+ $find = $request->getStr('find');
+ if (strlen($grep) || strlen($find)) {
+ return $this->browseSearch();
+ }
+
+ $results = DiffusionBrowseResultSet::newFromConduit(
+ $this->callConduitWithDiffusionRequest(
+ 'diffusion.browsequery',
+ array(
+ 'path' => $drequest->getPath(),
+ 'commit' => $drequest->getStableCommit(),
+ )));
+ $reason = $results->getReasonForEmptyResultSet();
+ $is_file = ($reason == DiffusionBrowseResultSet::REASON_IS_FILE);
+
+ if ($is_file) {
+ return $this->browseFile($results);
+ } else {
+ return $this->browseDirectory($results);
+ }
+ }
+
+ private function browseSearch() {
+ $drequest = $this->getDiffusionRequest();
+
+ $actions = $this->buildActionView($drequest);
+ $properties = $this->buildPropertyView($drequest, $actions);
+
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeader($this->buildHeaderView($drequest))
+ ->addPropertyList($properties);
+
+ $content = array();
+
+ $content[] = $object_box;
+ $content[] = $this->renderSearchForm($collapsed = false);
+ $content[] = $this->renderSearchResults();
+
+ $crumbs = $this->buildCrumbs(
+ array(
+ 'branch' => true,
+ 'path' => true,
+ 'view' => 'browse',
+ ));
+
+ return $this->newPage()
+ ->setTitle(
+ array(
+ nonempty(basename($drequest->getPath()), '/'),
+ $drequest->getRepository()->getDisplayName(),
+ ))
+ ->setCrumbs($crumbs)
+ ->appendChild($content);
+ }
+
+ private function browseFile() {
+ $viewer = $this->getViewer();
+ $request = $this->getRequest();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ $before = $request->getStr('before');
+ if ($before) {
+ return $this->buildBeforeResponse($before);
+ }
+
+ $path = $drequest->getPath();
+
+ $preferences = $viewer->loadPreferences();
+
+ $show_blame = $request->getBool(
+ 'blame',
+ $preferences->getPreference(
+ PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
+ false));
+ $show_color = $request->getBool(
+ 'color',
+ $preferences->getPreference(
+ PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
+ true));
+
+ $view = $request->getStr('view');
+ if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) {
+ $preferences->setPreference(
+ PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
+ $show_blame);
+ $preferences->setPreference(
+ PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
+ $show_color);
+ $preferences->save();
+
+ $uri = $request->getRequestURI()
+ ->alter('blame', null)
+ ->alter('color', null);
+
+ return id(new AphrontRedirectResponse())->setURI($uri);
+ }
+
+ // We need the blame information if blame is on and we're building plain
+ // text, or blame is on and this is an Ajax request. If blame is on and
+ // 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.
+ $needs_blame = ($show_blame && !$show_color) ||
+ ($show_blame && $request->isAjax());
+
+ $params = array(
+ 'commit' => $drequest->getCommit(),
+ 'path' => $drequest->getPath(),
+ 'needsBlame' => $needs_blame,
+ );
+
+ $byte_limit = null;
+ if ($view !== 'raw') {
+ $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
+ $time_limit = 10;
+
+ $params += array(
+ 'timeout' => $time_limit,
+ 'byteLimit' => $byte_limit,
+ );
+ }
+
+ $file_content = DiffusionFileContent::newFromConduit(
+ $this->callConduitWithDiffusionRequest(
+ 'diffusion.filecontentquery',
+ $params));
+ $data = $file_content->getCorpus();
+
+ if ($view === 'raw') {
+ return $this->buildRawResponse($path, $data);
+ }
+
+ $this->loadLintMessages();
+ $this->coverage = $drequest->loadCoverage();
+
+ if ($byte_limit && (strlen($data) == $byte_limit)) {
+ $corpus = $this->buildErrorCorpus(
+ pht(
+ 'This file is larger than %s byte(s), and too large to display '.
+ 'in the web UI.',
+ $byte_limit));
+ } else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
+ $file = $this->loadFileForData($path, $data);
+ $file_uri = $file->getBestURI();
+
+ if ($file->isViewableImage()) {
+ $corpus = $this->buildImageCorpus($file_uri);
+ } else {
+ $corpus = $this->buildBinaryCorpus($file_uri, $data);
+ }
+ } else {
+ // Build the content of the file.
+ $corpus = $this->buildCorpus(
+ $show_blame,
+ $show_color,
+ $file_content,
+ $needs_blame,
+ $drequest,
+ $path,
+ $data);
+ }
+
+ if ($request->isAjax()) {
+ return id(new AphrontAjaxResponse())->setContent($corpus);
+ }
+
+ require_celerity_resource('diffusion-source-css');
+
+ // Render the page.
+ $view = $this->buildActionView($drequest);
+ $action_list = $this->enrichActionView(
+ $view,
+ $drequest,
+ $show_blame,
+ $show_color);
+
+ $properties = $this->buildPropertyView($drequest, $action_list);
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeader($this->buildHeaderView($drequest))
+ ->addPropertyList($properties);
+
+ $content = array();
+ $content[] = $object_box;
+
+ $follow = $request->getStr('follow');
+ if ($follow) {
+ $notice = new PHUIInfoView();
+ $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
+ $notice->setTitle(pht('Unable to Continue'));
+ switch ($follow) {
+ case 'first':
+ $notice->appendChild(
+ pht(
+ 'Unable to continue tracing the history of this file because '.
+ 'this commit is the first commit in the repository.'));
+ break;
+ case 'created':
+ $notice->appendChild(
+ pht(
+ 'Unable to continue tracing the history of this file because '.
+ 'this commit created the file.'));
+ break;
+ }
+ $content[] = $notice;
+ }
+
+ $renamed = $request->getStr('renamed');
+ if ($renamed) {
+ $notice = new PHUIInfoView();
+ $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
+ $notice->setTitle(pht('File Renamed'));
+ $notice->appendChild(
+ pht(
+ 'File history passes through a rename from "%s" to "%s".',
+ $drequest->getPath(),
+ $renamed));
+ $content[] = $notice;
+ }
+
+ $content[] = $corpus;
+ $content[] = $this->buildOpenRevisions();
+
+ $crumbs = $this->buildCrumbs(
+ array(
+ 'branch' => true,
+ 'path' => true,
+ 'view' => 'browse',
+ ));
+
+ $basename = basename($this->getDiffusionRequest()->getPath());
+
+ return $this->newPage()
+ ->setTitle(
+ array(
+ $basename,
+ $repository->getDisplayName(),
+ ))
+ ->setCrumbs($crumbs)
+ ->appendChild($content);
+ }
+
+ public function browseDirectory(DiffusionBrowseResultSet $results) {
+ $request = $this->getRequest();
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+
+ $reason = $results->getReasonForEmptyResultSet();
+
+ $content = array();
+ $actions = $this->buildActionView($drequest);
+ $properties = $this->buildPropertyView($drequest, $actions);
+
+ $object_box = id(new PHUIObjectBoxView())
+ ->setHeader($this->buildHeaderView($drequest))
+ ->addPropertyList($properties);
+
+ $content[] = $object_box;
+ $content[] = $this->renderSearchForm($collapsed = true);
+
+ if (!$results->isValidResults()) {
+ $empty_result = new DiffusionEmptyResultView();
+ $empty_result->setDiffusionRequest($drequest);
+ $empty_result->setDiffusionBrowseResultSet($results);
+ $empty_result->setView($request->getStr('view'));
+ $content[] = $empty_result;
+ } else {
+ $phids = array();
+ foreach ($results->getPaths() as $result) {
+ $data = $result->getLastCommitData();
+ if ($data) {
+ if ($data->getCommitDetail('authorPHID')) {
+ $phids[$data->getCommitDetail('authorPHID')] = true;
+ }
+ }
+ }
+
+ $phids = array_keys($phids);
+ $handles = $this->loadViewerHandles($phids);
+
+ $browse_table = new DiffusionBrowseTableView();
+ $browse_table->setDiffusionRequest($drequest);
+ $browse_table->setHandles($handles);
+ $browse_table->setPaths($results->getPaths());
+ $browse_table->setUser($request->getUser());
+
+ $browse_panel = new PHUIObjectBoxView();
+ $browse_panel->setHeaderText($drequest->getPath(), '/');
+ $browse_panel->setTable($browse_table);
+
+ $content[] = $browse_panel;
+ }
+
+ $content[] = $this->buildOpenRevisions();
+
+
+ $readme_path = $results->getReadmePath();
+ if ($readme_path) {
+ $readme_content = $this->callConduitWithDiffusionRequest(
+ 'diffusion.filecontentquery',
+ array(
+ 'path' => $readme_path,
+ 'commit' => $drequest->getStableCommit(),
+ ));
+ if ($readme_content) {
+ $content[] = id(new DiffusionReadmeView())
+ ->setUser($this->getViewer())
+ ->setPath($readme_path)
+ ->setContent($readme_content['corpus']);
+ }
+ }
+
+ $crumbs = $this->buildCrumbs(
+ array(
+ 'branch' => true,
+ 'path' => true,
+ 'view' => 'browse',
+ ));
+
+ return $this->newPage()
+ ->setTitle(
+ array(
+ nonempty(basename($drequest->getPath()), '/'),
+ $repository->getDisplayName(),
+ ))
+ ->setCrumbs($crumbs)
+ ->appendChild($content);
+ }
+
+ private function renderSearchResults() {
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+ $results = array();
+
+ $limit = 100;
+ $page = $this->getRequest()->getInt('page', 0);
+ $pager = new PHUIPagerView();
+ $pager->setPageSize($limit);
+ $pager->setOffset($page);
+ $pager->setURI($this->getRequest()->getRequestURI(), 'page');
+
+ $search_mode = null;
+
+ switch ($repository->getVersionControlSystem()) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ $results = array();
+ break;
+ default:
+ if (strlen($this->getRequest()->getStr('grep'))) {
+ $search_mode = 'grep';
+ $query_string = $this->getRequest()->getStr('grep');
+ $results = $this->callConduitWithDiffusionRequest(
+ 'diffusion.searchquery',
+ array(
+ 'grep' => $query_string,
+ 'commit' => $drequest->getStableCommit(),
+ 'path' => $drequest->getPath(),
+ 'limit' => $limit + 1,
+ 'offset' => $page,
+ ));
+ } else { // Filename search.
+ $search_mode = 'find';
+ $query_string = $this->getRequest()->getStr('find');
+ $results = $this->callConduitWithDiffusionRequest(
+ 'diffusion.querypaths',
+ array(
+ 'pattern' => $query_string,
+ 'commit' => $drequest->getStableCommit(),
+ 'path' => $drequest->getPath(),
+ 'limit' => $limit + 1,
+ 'offset' => $page,
+ ));
+ }
+ break;
+ }
+
+ $results = $pager->sliceResults($results);
+
+ if ($search_mode == 'grep') {
+ $table = $this->renderGrepResults($results, $query_string);
+ $header = pht(
+ 'File content matching "%s" under "%s"',
+ $query_string,
+ nonempty($drequest->getPath(), '/'));
+ } else {
+ $table = $this->renderFindResults($results);
+ $header = pht(
+ 'Paths matching "%s" under "%s"',
+ $query_string,
+ nonempty($drequest->getPath(), '/'));
+ }
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText($header)
+ ->setTable($table);
+
+ $pager_box = $this->renderTablePagerBox($pager);
+
+ return array($box, $pager_box);
+ }
+
+ private function renderGrepResults(array $results, $pattern) {
+ $drequest = $this->getDiffusionRequest();
+
+ require_celerity_resource('phabricator-search-results-css');
+
+ $rows = array();
+ foreach ($results as $result) {
+ list($path, $line, $string) = $result;
+
+ $href = $drequest->generateURI(array(
+ 'action' => 'browse',
+ 'path' => $path,
+ 'line' => $line,
+ ));
+
+ $matches = null;
+ $count = @preg_match_all(
+ '('.$pattern.')u',
+ $string,
+ $matches,
+ PREG_OFFSET_CAPTURE);
+
+ if (!$count) {
+ $output = ltrim($string);
+ } else {
+ $output = array();
+ $cursor = 0;
+ $length = strlen($string);
+ foreach ($matches[0] as $match) {
+ $offset = $match[1];
+ if ($cursor != $offset) {
+ $output[] = array(
+ 'text' => substr($string, $cursor, $offset),
+ 'highlight' => false,
+ );
+ }
+ $output[] = array(
+ 'text' => $match[0],
+ 'highlight' => true,
+ );
+ $cursor = $offset + strlen($match[0]);
+ }
+ if ($cursor != $length) {
+ $output[] = array(
+ 'text' => substr($string, $cursor),
+ 'highlight' => false,
+ );
+ }
+
+ if ($output) {
+ $output[0]['text'] = ltrim($output[0]['text']);
+ }
+
+ foreach ($output as $key => $segment) {
+ if ($segment['highlight']) {
+ $output[$key] = phutil_tag('strong', array(), $segment['text']);
+ } else {
+ $output[$key] = $segment['text'];
+ }
+ }
+ }
+
+ $string = phutil_tag(
+ 'pre',
+ array('class' => 'PhabricatorMonospaced phui-source-fragment'),
+ $output);
+
+ $path = Filesystem::readablePath($path, $drequest->getPath());
+
+ $rows[] = array(
+ phutil_tag('a', array('href' => $href), $path),
+ $line,
+ $string,
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setClassName('remarkup-code')
+ ->setHeaders(array(pht('Path'), pht('Line'), pht('String')))
+ ->setColumnClasses(array('', 'n', 'wide'))
+ ->setNoDataString(
+ pht(
+ 'The pattern you searched for was not found in the content of any '.
+ 'files.'));
+
+ return $table;
+ }
+
+ private function renderFindResults(array $results) {
+ $drequest = $this->getDiffusionRequest();
+
+ $rows = array();
+ foreach ($results as $result) {
+ $href = $drequest->generateURI(array(
+ 'action' => 'browse',
+ 'path' => $result,
+ ));
+
+ $readable = Filesystem::readablePath($result, $drequest->getPath());
+
+ $rows[] = array(
+ phutil_tag('a', array('href' => $href), $readable),
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setHeaders(array(pht('Path')))
+ ->setColumnClasses(array('wide'))
+ ->setNoDataString(
+ pht(
+ 'The pattern you searched for did not match the names of any '.
+ 'files.'));
+
+ return $table;
+ }
+
+ private function loadLintMessages() {
+ $drequest = $this->getDiffusionRequest();
+ $branch = $drequest->loadBranch();
+
+ if (!$branch || !$branch->getLintCommit()) {
+ return;
+ }
+
+ $this->lintCommit = $branch->getLintCommit();
+
+ $conn = id(new PhabricatorRepository())->establishConnection('r');
+
+ $where = '';
+ if ($drequest->getLint()) {
+ $where = qsprintf(
+ $conn,
+ 'AND code = %s',
+ $drequest->getLint());
+ }
+
+ $this->lintMessages = queryfx_all(
+ $conn,
+ 'SELECT * FROM %T WHERE branchID = %d %Q AND path = %s',
+ PhabricatorRepository::TABLE_LINTMESSAGE,
+ $branch->getID(),
+ $where,
+ '/'.$drequest->getPath());
+ }
+
+ private function buildCorpus(
+ $show_blame,
+ $show_color,
+ DiffusionFileContent $file_content,
+ $needs_blame,
+ DiffusionRequest $drequest,
+ $path,
+ $data) {
+
+ if (!$show_color) {
+ $style =
+ 'border: none; width: 100%; height: 80em; font-family: monospace';
+ if (!$show_blame) {
+ $corpus = phutil_tag(
+ 'textarea',
+ array(
+ 'style' => $style,
+ ),
+ $file_content->getCorpus());
+ } else {
+ $text_list = $file_content->getTextList();
+ $rev_list = $file_content->getRevList();
+ $blame_dict = $file_content->getBlameDict();
+
+ $rows = array();
+ foreach ($text_list as $k => $line) {
+ $rev = $rev_list[$k];
+ $author = $blame_dict[$rev]['author'];
+ $rows[] =
+ sprintf('%-10s %-20s %s', substr($rev, 0, 7), $author, $line);
+ }
+
+ $corpus = phutil_tag(
+ 'textarea',
+ array(
+ 'style' => $style,
+ ),
+ implode("\n", $rows));
+ }
+ } else {
+ 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);
+ $text_list = PhabricatorSyntaxHighlighter::highlightWithFilename(
+ $path,
+ $text_list);
+ $text_list = explode("\n", $text_list);
+
+ $rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict,
+ $needs_blame, $drequest, $show_blame, $show_color);
+
+ $corpus_table = javelin_tag(
+ 'table',
+ array(
+ 'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
+ 'sigil' => 'phabricator-source',
+ ),
+ $rows);
+
+ if ($this->getRequest()->isAjax()) {
+ return $corpus_table;
+ }
+
+ $id = celerity_generate_unique_node_id();
+
+ $repo = $drequest->getRepository();
+ $symbol_repos = nonempty($repo->getSymbolSources(), array());
+ $symbol_repos[] = $repo->getPHID();
+
+ $lang = last(explode('.', $drequest->getPath()));
+ $repo_languages = $repo->getSymbolLanguages();
+ $repo_languages = nonempty($repo_languages, array());
+ $repo_languages = array_fill_keys($repo_languages, true);
+
+ $needs_symbols = true;
+ if ($repo_languages && $symbol_repos) {
+ $have_symbols = id(new DiffusionSymbolQuery())
+ ->existsSymbolsInRepository($repo->getPHID());
+ if (!$have_symbols) {
+ $needs_symbols = false;
+ }
+ }
+
+ if ($needs_symbols && $repo_languages) {
+ $needs_symbols = isset($repo_languages[$lang]);
+ }
+
+ if ($needs_symbols) {
+ Javelin::initBehavior(
+ 'repository-crossreference',
+ array(
+ 'container' => $id,
+ 'lang' => $lang,
+ 'repositories' => $symbol_repos,
+ ));
+ }
+
+ $corpus = phutil_tag(
+ 'div',
+ array(
+ 'id' => $id,
+ ),
+ $corpus_table);
+
+ Javelin::initBehavior('load-blame', array('id' => $id));
+ }
+
+ $edit = $this->renderEditButton();
+ $file = $this->renderFileButton();
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('File Contents'))
+ ->addActionLink($edit)
+ ->addActionLink($file);
+
+ $corpus = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($corpus)
+ ->setCollapsed(true);
+
+ return $corpus;
+ }
+
+ private function enrichActionView(
+ PhabricatorActionListView $view,
+ DiffusionRequest $drequest,
+ $show_blame,
+ $show_color) {
+
+ $viewer = $this->getRequest()->getUser();
+ $base_uri = $this->getRequest()->getRequestURI();
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Show Last Change'))
+ ->setHref(
+ $drequest->generateURI(
+ array(
+ 'action' => 'change',
+ )))
+ ->setIcon('fa-backward'));
+
+ if ($show_blame) {
+ $blame_text = pht('Disable Blame');
+ $blame_icon = 'fa-exclamation-circle lightgreytext';
+ $blame_value = 0;
+ } else {
+ $blame_text = pht('Enable Blame');
+ $blame_icon = 'fa-exclamation-circle';
+ $blame_value = 1;
+ }
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName($blame_text)
+ ->setHref($base_uri->alter('blame', $blame_value))
+ ->setIcon($blame_icon)
+ ->setUser($viewer)
+ ->setRenderAsForm($viewer->isLoggedIn()));
+
+ if ($show_color) {
+ $highlight_text = pht('Disable Highlighting');
+ $highlight_icon = 'fa-star-o grey';
+ $highlight_value = 0;
+ } else {
+ $highlight_text = pht('Enable Highlighting');
+ $highlight_icon = 'fa-star';
+ $highlight_value = 1;
+ }
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName($highlight_text)
+ ->setHref($base_uri->alter('color', $highlight_value))
+ ->setIcon($highlight_icon)
+ ->setUser($viewer)
+ ->setRenderAsForm($viewer->isLoggedIn()));
+
+ $href = null;
+ if ($this->getRequest()->getStr('lint') !== null) {
+ $lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
+ $href = $base_uri->alter('lint', null);
+
+ } else if ($this->lintCommit === null) {
+ $lint_text = pht('Lint not Available');
+ } else {
+ $lint_text = pht(
+ 'Show %d Lint Message(s)',
+ count($this->lintMessages));
+ $href = $this->getDiffusionRequest()->generateURI(array(
+ 'action' => 'browse',
+ 'commit' => $this->lintCommit,
+ ))->alter('lint', '');
+ }
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName($lint_text)
+ ->setHref($href)
+ ->setIcon('fa-exclamation-triangle')
+ ->setDisabled(!$href));
+
+ return $view;
+ }
+
+ private function renderEditButton() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $drequest = $this->getDiffusionRequest();
+
+ $repository = $drequest->getRepository();
+ $path = $drequest->getPath();
+ $line = nonempty((int)$drequest->getLine(), 1);
+
+ $editor_link = $user->loadEditorLink($path, $line, $repository);
+ $template = $user->loadEditorLink($path, '%l', $repository);
+
+ $icon_edit = id(new PHUIIconView())
+ ->setIconFont('fa-pencil');
+ $button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText(pht('Open in Editor'))
+ ->setHref($editor_link)
+ ->setIcon($icon_edit)
+ ->setID('editor_link')
+ ->setMetadata(array('link_template' => $template))
+ ->setDisabled(!$editor_link);
+
+ return $button;
+ }
+
+ private function renderFileButton($file_uri = null) {
+
+ $base_uri = $this->getRequest()->getRequestURI();
+
+ if ($file_uri) {
+ $text = pht('Download Raw File');
+ $href = $file_uri;
+ $icon = 'fa-download';
+ } else {
+ $text = pht('View Raw File');
+ $href = $base_uri->alter('view', 'raw');
+ $icon = 'fa-file-text';
+ }
+
+ $iconview = id(new PHUIIconView())
+ ->setIconFont($icon);
+ $button = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setText($text)
+ ->setHref($href)
+ ->setIcon($iconview);
+
+ return $button;
+ }
+
+
+ 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,
+ ),
+ ),
+ "\xC2\xAB");
+ }
+
+ $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,
+
+ // NOTE: See phabricator-oncopy behavior.
+ "\xE2\x80\x8B",
+
+ // TODO: [HTML] Not ideal.
+ 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 renderInlines(
+ array $inlines,
+ $needs_blame,
+ $has_coverage,
+ $engine) {
+
+ $rows = array();
+ foreach ($inlines as $inline) {
+
+ // TODO: This should use modern scaffolding code.
+
+ $inline_view = id(new PHUIDiffInlineCommentDetailView())
+ ->setUser($this->getViewer())
+ ->setMarkupEngine($engine)
+ ->setInlineComment($inline)
+ ->render();
+
+ $row = array_fill(0, ($needs_blame ? 3 : 1), phutil_tag('th'));
+
+ $row[] = phutil_tag('td', array(), $inline_view);
+
+ if ($has_coverage) {
+ $row[] = phutil_tag(
+ 'td',
+ array(
+ 'class' => 'cov cov-I',
+ ));
+ }
+
+ $rows[] = phutil_tag('tr', array('class' => 'inline'), $row);
+ }
+
+ return $rows;
+ }
+
+ private function loadFileForData($path, $data) {
+ $file = PhabricatorFile::buildFromFileDataOrHash(
+ $data,
+ array(
+ 'name' => basename($path),
+ 'ttl' => time() + 60 * 60 * 24,
+ 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
+ ));
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $file->attachToObject(
+ $this->getDiffusionRequest()->getRepository()->getPHID());
+ unset($unguarded);
+
+ return $file;
+ }
+
+ private function buildRawResponse($path, $data) {
+ $file = $this->loadFileForData($path, $data);
+ return $file->getRedirectResponse();
+ }
+
+ private function buildImageCorpus($file_uri) {
+ $properties = new PHUIPropertyListView();
+
+ $properties->addImageContent(
+ phutil_tag(
+ 'img',
+ array(
+ 'src' => $file_uri,
+ )));
+
+ $file = $this->renderFileButton($file_uri);
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Image'))
+ ->addActionLink($file);
+
+ return id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->addPropertyList($properties);
+ }
+
+ private function buildBinaryCorpus($file_uri, $data) {
+
+ $size = new PhutilNumber(strlen($data));
+ $text = pht('This is a binary file. It is %s byte(s) in length.', $size);
+ $text = id(new PHUIBoxView())
+ ->addPadding(PHUI::PADDING_LARGE)
+ ->appendChild($text);
+
+ $file = $this->renderFileButton($file_uri);
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Details'))
+ ->addActionLink($file);
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($text);
+
+ return $box;
+ }
+
+ private function buildErrorCorpus($message) {
+ $text = id(new PHUIBoxView())
+ ->addPadding(PHUI::PADDING_LARGE)
+ ->appendChild($message);
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Details'));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeader($header)
+ ->appendChild($text);
+
+ return $box;
+ }
+
+ private function buildBeforeResponse($before) {
+ $request = $this->getRequest();
+ $drequest = $this->getDiffusionRequest();
+
+ // NOTE: We need to get the grandparent so we can capture filename changes
+ // in the parent.
+
+ $parent = $this->loadParentCommitOf($before);
+ $old_filename = null;
+ $was_created = false;
+ if ($parent) {
+ $grandparent = $this->loadParentCommitOf($parent);
+
+ if ($grandparent) {
+ $rename_query = new DiffusionRenameHistoryQuery();
+ $rename_query->setRequest($drequest);
+ $rename_query->setOldCommit($grandparent);
+ $rename_query->setViewer($request->getUser());
+ $old_filename = $rename_query->loadOldFilename();
+ $was_created = $rename_query->getWasCreated();
+ }
+ }
+
+ $follow = null;
+ if ($was_created) {
+ // If the file was created in history, that means older commits won't
+ // have it. Since we know it existed at 'before', it must have been
+ // created then; jump there.
+ $target_commit = $before;
+ $follow = 'created';
+ } else if ($parent) {
+ // If we found a parent, jump to it. This is the normal case.
+ $target_commit = $parent;
+ } else {
+ // If there's no parent, this was probably created in the initial commit?
+ // And the "was_created" check will fail because we can't identify the
+ // grandparent. Keep the user at 'before'.
+ $target_commit = $before;
+ $follow = 'first';
+ }
+
+ $path = $drequest->getPath();
+ $renamed = null;
+ if ($old_filename !== null &&
+ $old_filename !== '/'.$path) {
+ $renamed = $path;
+ $path = $old_filename;
+ }
+
+ $line = null;
+ // If there's a follow error, drop the line so the user sees the message.
+ if (!$follow) {
+ $line = $this->getBeforeLineNumber($target_commit);
+ }
+
+ $before_uri = $drequest->generateURI(
+ array(
+ 'action' => 'browse',
+ 'commit' => $target_commit,
+ 'line' => $line,
+ 'path' => $path,
+ ));
+
+ $before_uri->setQueryParams($request->getRequestURI()->getQueryParams());
+ $before_uri = $before_uri->alter('before', null);
+ $before_uri = $before_uri->alter('renamed', $renamed);
+ $before_uri = $before_uri->alter('follow', $follow);
+
+ return id(new AphrontRedirectResponse())->setURI($before_uri);
+ }
+
+ private function getBeforeLineNumber($target_commit) {
+ $drequest = $this->getDiffusionRequest();
+
+ $line = $drequest->getLine();
+ if (!$line) {
+ return null;
+ }
+
+ $raw_diff = $this->callConduitWithDiffusionRequest(
+ 'diffusion.rawdiffquery',
+ array(
+ 'commit' => $drequest->getCommit(),
+ 'path' => $drequest->getPath(),
+ 'againstCommit' => $target_commit,
+ ));
+ $old_line = 0;
+ $new_line = 0;
+
+ foreach (explode("\n", $raw_diff) as $text) {
+ if ($text[0] == '-' || $text[0] == ' ') {
+ $old_line++;
+ }
+ if ($text[0] == '+' || $text[0] == ' ') {
+ $new_line++;
+ }
+ if ($new_line == $line) {
+ return $old_line;
+ }
+ }
+
+ // We didn't find the target line.
+ return $line;
+ }
+
+ private function loadParentCommitOf($commit) {
+ $drequest = $this->getDiffusionRequest();
+ $user = $this->getRequest()->getUser();
+
+ $before_req = DiffusionRequest::newFromDictionary(
+ array(
+ 'user' => $user,
+ 'repository' => $drequest->getRepository(),
+ 'commit' => $commit,
+ ));
+
+ $parents = DiffusionQuery::callConduitWithDiffusionRequest(
+ $user,
+ $before_req,
+ 'diffusion.commitparentsquery',
+ array(
+ 'commit' => $commit,
+ ));
+
+ return head($parents);
+ }
+
+ private function renderRevisionTooltip(
+ DifferentialRevision $revision,
+ array $handles) {
+ $viewer = $this->getRequest()->getUser();
+
+ $date = phabricator_date($revision->getDateModified(), $viewer);
+ $id = $revision->getID();
+ $title = $revision->getTitle();
+ $header = "D{$id} {$title}";
+
+ $author = $handles[$revision->getAuthorPHID()]->getName();
+
+ return "{$header}\n{$date} \xC2\xB7 {$author}";
+ }
+
+ private function renderCommitTooltip(
+ PhabricatorRepositoryCommit $commit,
+ array $handles,
+ $author) {
+
+ $viewer = $this->getRequest()->getUser();
+
+ $date = phabricator_date($commit->getEpoch(), $viewer);
+ $summary = trim($commit->getSummary());
+
+ if ($commit->getAuthorPHID()) {
+ $author = $handles[$commit->getAuthorPHID()]->getName();
+ }
+
+ return "{$summary}\n{$date} \xC2\xB7 {$author}";
+ }
+
protected function renderSearchForm($collapsed) {
$drequest = $this->getDiffusionRequest();
@@ -204,8 +1678,8 @@
return $view;
}
- protected function buildOpenRevisions() {
- $user = $this->getRequest()->getUser();
+ private function buildOpenRevisions() {
+ $viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
@@ -220,7 +1694,7 @@
$recent = (PhabricatorTime::getNow() - phutil_units('30 days in seconds'));
$revisions = id(new DifferentialRevisionQuery())
- ->setViewer($user)
+ ->setViewer($viewer)
->withPath($repository->getID(), $path_id)
->withStatus(DifferentialRevisionQuery::STATUS_OPEN)
->withUpdatedEpochBetween($recent, null)
@@ -243,7 +1717,7 @@
$view = id(new DifferentialRevisionListView())
->setHeader($header)
->setRevisions($revisions)
- ->setUser($user);
+ ->setUser($viewer);
$phids = $view->getRequiredHandlePHIDs();
$handles = $this->loadViewerHandles($phids);
diff --git a/src/applications/diffusion/controller/DiffusionBrowseDirectoryController.php b/src/applications/diffusion/controller/DiffusionBrowseDirectoryController.php
deleted file mode 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseDirectoryController.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-final class DiffusionBrowseDirectoryController
- extends DiffusionBrowseController {
-
- private $browseQueryResults;
-
- public function setBrowseQueryResults(DiffusionBrowseResultSet $results) {
- $this->browseQueryResults = $results;
- return $this;
- }
-
- public function getBrowseQueryResults() {
- return $this->browseQueryResults;
- }
-
- protected function processDiffusionRequest(AphrontRequest $request) {
- $drequest = $this->diffusionRequest;
-
- $results = $this->getBrowseQueryResults();
- $reason = $results->getReasonForEmptyResultSet();
-
- $content = array();
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
-
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
-
- $content[] = $object_box;
- $content[] = $this->renderSearchForm($collapsed = true);
-
- if (!$results->isValidResults()) {
- $empty_result = new DiffusionEmptyResultView();
- $empty_result->setDiffusionRequest($drequest);
- $empty_result->setDiffusionBrowseResultSet($results);
- $empty_result->setView($request->getStr('view'));
- $content[] = $empty_result;
- } else {
- $phids = array();
- foreach ($results->getPaths() as $result) {
- $data = $result->getLastCommitData();
- if ($data) {
- if ($data->getCommitDetail('authorPHID')) {
- $phids[$data->getCommitDetail('authorPHID')] = true;
- }
- }
- }
-
- $phids = array_keys($phids);
- $handles = $this->loadViewerHandles($phids);
-
- $browse_table = new DiffusionBrowseTableView();
- $browse_table->setDiffusionRequest($drequest);
- $browse_table->setHandles($handles);
- $browse_table->setPaths($results->getPaths());
- $browse_table->setUser($request->getUser());
-
- $browse_panel = new PHUIObjectBoxView();
- $browse_panel->setHeaderText($drequest->getPath(), '/');
- $browse_panel->setTable($browse_table);
-
- $content[] = $browse_panel;
- }
-
- $content[] = $this->buildOpenRevisions();
-
-
- $readme_path = $results->getReadmePath();
- if ($readme_path) {
- $readme_content = $this->callConduitWithDiffusionRequest(
- 'diffusion.filecontentquery',
- array(
- 'path' => $readme_path,
- 'commit' => $drequest->getStableCommit(),
- ));
- if ($readme_content) {
- $content[] = id(new DiffusionReadmeView())
- ->setUser($this->getViewer())
- ->setPath($readme_path)
- ->setContent($readme_content['corpus']);
- }
- }
-
- $crumbs = $this->buildCrumbs(
- array(
- 'branch' => true,
- 'path' => true,
- 'view' => 'browse',
- ));
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $content,
- ),
- array(
- 'title' => array(
- nonempty(basename($drequest->getPath()), '/'),
- $drequest->getRepository()->getDisplayName(),
- ),
- ));
- }
-
-}
diff --git a/src/applications/diffusion/controller/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/DiffusionBrowseFileController.php
deleted file mode 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseFileController.php
+++ /dev/null
@@ -1,1134 +0,0 @@
-<?php
-
-final class DiffusionBrowseFileController extends DiffusionBrowseController {
-
- private $lintCommit;
- private $lintMessages;
- private $coverage;
-
- protected function processDiffusionRequest(AphrontRequest $request) {
- $drequest = $this->getDiffusionRequest();
- $viewer = $request->getUser();
-
- $before = $request->getStr('before');
- if ($before) {
- return $this->buildBeforeResponse($before);
- }
-
- $path = $drequest->getPath();
-
- $preferences = $viewer->loadPreferences();
-
- $show_blame = $request->getBool(
- 'blame',
- $preferences->getPreference(
- PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
- false));
- $show_color = $request->getBool(
- 'color',
- $preferences->getPreference(
- PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
- true));
-
- $view = $request->getStr('view');
- if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) {
- $preferences->setPreference(
- PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME,
- $show_blame);
- $preferences->setPreference(
- PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR,
- $show_color);
- $preferences->save();
-
- $uri = $request->getRequestURI()
- ->alter('blame', null)
- ->alter('color', null);
-
- return id(new AphrontRedirectResponse())->setURI($uri);
- }
-
- // We need the blame information if blame is on and we're building plain
- // text, or blame is on and this is an Ajax request. If blame is on and
- // 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.
- $needs_blame = ($show_blame && !$show_color) ||
- ($show_blame && $request->isAjax());
-
- $params = array(
- 'commit' => $drequest->getCommit(),
- 'path' => $drequest->getPath(),
- 'needsBlame' => $needs_blame,
- );
-
- $byte_limit = null;
- if ($view !== 'raw') {
- $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold();
- $time_limit = 10;
-
- $params += array(
- 'timeout' => $time_limit,
- 'byteLimit' => $byte_limit,
- );
- }
-
- $file_content = DiffusionFileContent::newFromConduit(
- $this->callConduitWithDiffusionRequest(
- 'diffusion.filecontentquery',
- $params));
- $data = $file_content->getCorpus();
-
- if ($view === 'raw') {
- return $this->buildRawResponse($path, $data);
- }
-
- $this->loadLintMessages();
- $this->coverage = $drequest->loadCoverage();
-
- if ($byte_limit && (strlen($data) == $byte_limit)) {
- $corpus = $this->buildErrorCorpus(
- pht(
- 'This file is larger than %s byte(s), and too large to display '.
- 'in the web UI.',
- $byte_limit));
- } else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
- $file = $this->loadFileForData($path, $data);
- $file_uri = $file->getBestURI();
-
- if ($file->isViewableImage()) {
- $corpus = $this->buildImageCorpus($file_uri);
- } else {
- $corpus = $this->buildBinaryCorpus($file_uri, $data);
- }
- } else {
- // Build the content of the file.
- $corpus = $this->buildCorpus(
- $show_blame,
- $show_color,
- $file_content,
- $needs_blame,
- $drequest,
- $path,
- $data);
- }
-
- if ($request->isAjax()) {
- return id(new AphrontAjaxResponse())->setContent($corpus);
- }
-
- require_celerity_resource('diffusion-source-css');
-
- // Render the page.
- $view = $this->buildActionView($drequest);
- $action_list = $this->enrichActionView(
- $view,
- $drequest,
- $show_blame,
- $show_color);
-
- $properties = $this->buildPropertyView($drequest, $action_list);
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
-
- $content = array();
- $content[] = $object_box;
-
- $follow = $request->getStr('follow');
- if ($follow) {
- $notice = new PHUIInfoView();
- $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING);
- $notice->setTitle(pht('Unable to Continue'));
- switch ($follow) {
- case 'first':
- $notice->appendChild(
- pht(
- 'Unable to continue tracing the history of this file because '.
- 'this commit is the first commit in the repository.'));
- break;
- case 'created':
- $notice->appendChild(
- pht(
- 'Unable to continue tracing the history of this file because '.
- 'this commit created the file.'));
- break;
- }
- $content[] = $notice;
- }
-
- $renamed = $request->getStr('renamed');
- if ($renamed) {
- $notice = new PHUIInfoView();
- $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
- $notice->setTitle(pht('File Renamed'));
- $notice->appendChild(
- pht(
- "File history passes through a rename from '%s' to '%s'.",
- $drequest->getPath(), $renamed));
- $content[] = $notice;
- }
-
- $content[] = $corpus;
- $content[] = $this->buildOpenRevisions();
-
- $crumbs = $this->buildCrumbs(
- array(
- 'branch' => true,
- 'path' => true,
- 'view' => 'browse',
- ));
-
- $basename = basename($this->getDiffusionRequest()->getPath());
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $content,
- ),
- array(
- 'title' => $basename,
- ));
- }
-
- private function loadLintMessages() {
- $drequest = $this->getDiffusionRequest();
- $branch = $drequest->loadBranch();
-
- if (!$branch || !$branch->getLintCommit()) {
- return;
- }
-
- $this->lintCommit = $branch->getLintCommit();
-
- $conn = id(new PhabricatorRepository())->establishConnection('r');
-
- $where = '';
- if ($drequest->getLint()) {
- $where = qsprintf(
- $conn,
- 'AND code = %s',
- $drequest->getLint());
- }
-
- $this->lintMessages = queryfx_all(
- $conn,
- 'SELECT * FROM %T WHERE branchID = %d %Q AND path = %s',
- PhabricatorRepository::TABLE_LINTMESSAGE,
- $branch->getID(),
- $where,
- '/'.$drequest->getPath());
- }
-
- private function buildCorpus(
- $show_blame,
- $show_color,
- DiffusionFileContent $file_content,
- $needs_blame,
- DiffusionRequest $drequest,
- $path,
- $data) {
-
- if (!$show_color) {
- $style =
- 'border: none; width: 100%; height: 80em; font-family: monospace';
- if (!$show_blame) {
- $corpus = phutil_tag(
- 'textarea',
- array(
- 'style' => $style,
- ),
- $file_content->getCorpus());
- } else {
- $text_list = $file_content->getTextList();
- $rev_list = $file_content->getRevList();
- $blame_dict = $file_content->getBlameDict();
-
- $rows = array();
- foreach ($text_list as $k => $line) {
- $rev = $rev_list[$k];
- $author = $blame_dict[$rev]['author'];
- $rows[] =
- sprintf('%-10s %-20s %s', substr($rev, 0, 7), $author, $line);
- }
-
- $corpus = phutil_tag(
- 'textarea',
- array(
- 'style' => $style,
- ),
- implode("\n", $rows));
- }
- } else {
- 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);
- $text_list = PhabricatorSyntaxHighlighter::highlightWithFilename(
- $path,
- $text_list);
- $text_list = explode("\n", $text_list);
-
- $rows = $this->buildDisplayRows($text_list, $rev_list, $blame_dict,
- $needs_blame, $drequest, $show_blame, $show_color);
-
- $corpus_table = javelin_tag(
- 'table',
- array(
- 'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
- 'sigil' => 'phabricator-source',
- ),
- $rows);
-
- if ($this->getRequest()->isAjax()) {
- return $corpus_table;
- }
-
- $id = celerity_generate_unique_node_id();
-
- $repo = $drequest->getRepository();
- $symbol_repos = nonempty($repo->getSymbolSources(), array());
- $symbol_repos[] = $repo->getPHID();
-
- $lang = last(explode('.', $drequest->getPath()));
- $repo_languages = $repo->getSymbolLanguages();
- $repo_languages = nonempty($repo_languages, array());
- $repo_languages = array_fill_keys($repo_languages, true);
-
- $needs_symbols = true;
- if ($repo_languages && $symbol_repos) {
- $have_symbols = id(new DiffusionSymbolQuery())
- ->existsSymbolsInRepository($repo->getPHID());
- if (!$have_symbols) {
- $needs_symbols = false;
- }
- }
-
- if ($needs_symbols && $repo_languages) {
- $needs_symbols = isset($repo_languages[$lang]);
- }
-
- if ($needs_symbols) {
- Javelin::initBehavior(
- 'repository-crossreference',
- array(
- 'container' => $id,
- 'lang' => $lang,
- 'repositories' => $symbol_repos,
- ));
- }
-
- $corpus = phutil_tag(
- 'div',
- array(
- 'id' => $id,
- ),
- $corpus_table);
-
- Javelin::initBehavior('load-blame', array('id' => $id));
- }
-
- $edit = $this->renderEditButton();
- $file = $this->renderFileButton();
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('File Contents'))
- ->addActionLink($edit)
- ->addActionLink($file);
-
- $corpus = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->appendChild($corpus)
- ->setCollapsed(true);
-
- return $corpus;
- }
-
- private function enrichActionView(
- PhabricatorActionListView $view,
- DiffusionRequest $drequest,
- $show_blame,
- $show_color) {
-
- $viewer = $this->getRequest()->getUser();
- $base_uri = $this->getRequest()->getRequestURI();
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Show Last Change'))
- ->setHref(
- $drequest->generateURI(
- array(
- 'action' => 'change',
- )))
- ->setIcon('fa-backward'));
-
- if ($show_blame) {
- $blame_text = pht('Disable Blame');
- $blame_icon = 'fa-exclamation-circle lightgreytext';
- $blame_value = 0;
- } else {
- $blame_text = pht('Enable Blame');
- $blame_icon = 'fa-exclamation-circle';
- $blame_value = 1;
- }
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName($blame_text)
- ->setHref($base_uri->alter('blame', $blame_value))
- ->setIcon($blame_icon)
- ->setUser($viewer)
- ->setRenderAsForm($viewer->isLoggedIn()));
-
- if ($show_color) {
- $highlight_text = pht('Disable Highlighting');
- $highlight_icon = 'fa-star-o grey';
- $highlight_value = 0;
- } else {
- $highlight_text = pht('Enable Highlighting');
- $highlight_icon = 'fa-star';
- $highlight_value = 1;
- }
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName($highlight_text)
- ->setHref($base_uri->alter('color', $highlight_value))
- ->setIcon($highlight_icon)
- ->setUser($viewer)
- ->setRenderAsForm($viewer->isLoggedIn()));
-
- $href = null;
- if ($this->getRequest()->getStr('lint') !== null) {
- $lint_text = pht('Hide %d Lint Message(s)', count($this->lintMessages));
- $href = $base_uri->alter('lint', null);
-
- } else if ($this->lintCommit === null) {
- $lint_text = pht('Lint not Available');
- } else {
- $lint_text = pht(
- 'Show %d Lint Message(s)',
- count($this->lintMessages));
- $href = $this->getDiffusionRequest()->generateURI(array(
- 'action' => 'browse',
- 'commit' => $this->lintCommit,
- ))->alter('lint', '');
- }
-
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName($lint_text)
- ->setHref($href)
- ->setIcon('fa-exclamation-triangle')
- ->setDisabled(!$href));
-
- return $view;
- }
-
- private function renderEditButton() {
- $request = $this->getRequest();
- $user = $request->getUser();
-
- $drequest = $this->getDiffusionRequest();
-
- $repository = $drequest->getRepository();
- $path = $drequest->getPath();
- $line = nonempty((int)$drequest->getLine(), 1);
-
- $editor_link = $user->loadEditorLink($path, $line, $repository);
- $template = $user->loadEditorLink($path, '%l', $repository);
-
- $icon_edit = id(new PHUIIconView())
- ->setIconFont('fa-pencil');
- $button = id(new PHUIButtonView())
- ->setTag('a')
- ->setText(pht('Open in Editor'))
- ->setHref($editor_link)
- ->setIcon($icon_edit)
- ->setID('editor_link')
- ->setMetadata(array('link_template' => $template))
- ->setDisabled(!$editor_link);
-
- return $button;
- }
-
- private function renderFileButton($file_uri = null) {
-
- $base_uri = $this->getRequest()->getRequestURI();
-
- if ($file_uri) {
- $text = pht('Download Raw File');
- $href = $file_uri;
- $icon = 'fa-download';
- } else {
- $text = pht('View Raw File');
- $href = $base_uri->alter('view', 'raw');
- $icon = 'fa-file-text';
- }
-
- $iconview = id(new PHUIIconView())
- ->setIconFont($icon);
- $button = id(new PHUIButtonView())
- ->setTag('a')
- ->setText($text)
- ->setHref($href)
- ->setIcon($iconview);
-
- return $button;
- }
-
-
- 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,
- ),
- ),
- "\xC2\xAB");
- }
-
- $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,
-
- // NOTE: See phabricator-oncopy behavior.
- "\xE2\x80\x8B",
-
- // TODO: [HTML] Not ideal.
- 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 renderInlines(
- array $inlines,
- $needs_blame,
- $has_coverage,
- $engine) {
-
- $rows = array();
- foreach ($inlines as $inline) {
-
- // TODO: This should use modern scaffolding code.
-
- $inline_view = id(new PHUIDiffInlineCommentDetailView())
- ->setUser($this->getViewer())
- ->setMarkupEngine($engine)
- ->setInlineComment($inline)
- ->render();
-
- $row = array_fill(0, ($needs_blame ? 3 : 1), phutil_tag('th'));
-
- $row[] = phutil_tag('td', array(), $inline_view);
-
- if ($has_coverage) {
- $row[] = phutil_tag(
- 'td',
- array(
- 'class' => 'cov cov-I',
- ));
- }
-
- $rows[] = phutil_tag('tr', array('class' => 'inline'), $row);
- }
-
- return $rows;
- }
-
- private function loadFileForData($path, $data) {
- $file = PhabricatorFile::buildFromFileDataOrHash(
- $data,
- array(
- 'name' => basename($path),
- 'ttl' => time() + 60 * 60 * 24,
- 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
- ));
-
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
- $file->attachToObject(
- $this->getDiffusionRequest()->getRepository()->getPHID());
- unset($unguarded);
-
- return $file;
- }
-
- private function buildRawResponse($path, $data) {
- $file = $this->loadFileForData($path, $data);
- return $file->getRedirectResponse();
- }
-
- private function buildImageCorpus($file_uri) {
- $properties = new PHUIPropertyListView();
-
- $properties->addImageContent(
- phutil_tag(
- 'img',
- array(
- 'src' => $file_uri,
- )));
-
- $file = $this->renderFileButton($file_uri);
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('Image'))
- ->addActionLink($file);
-
- return id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($properties);
- }
-
- private function buildBinaryCorpus($file_uri, $data) {
-
- $size = new PhutilNumber(strlen($data));
- $text = pht('This is a binary file. It is %s byte(s) in length.', $size);
- $text = id(new PHUIBoxView())
- ->addPadding(PHUI::PADDING_LARGE)
- ->appendChild($text);
-
- $file = $this->renderFileButton($file_uri);
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('Details'))
- ->addActionLink($file);
-
- $box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->appendChild($text);
-
- return $box;
- }
-
- private function buildErrorCorpus($message) {
- $text = id(new PHUIBoxView())
- ->addPadding(PHUI::PADDING_LARGE)
- ->appendChild($message);
-
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('Details'));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->appendChild($text);
-
- return $box;
- }
-
- private function buildBeforeResponse($before) {
- $request = $this->getRequest();
- $drequest = $this->getDiffusionRequest();
-
- // NOTE: We need to get the grandparent so we can capture filename changes
- // in the parent.
-
- $parent = $this->loadParentCommitOf($before);
- $old_filename = null;
- $was_created = false;
- if ($parent) {
- $grandparent = $this->loadParentCommitOf($parent);
-
- if ($grandparent) {
- $rename_query = new DiffusionRenameHistoryQuery();
- $rename_query->setRequest($drequest);
- $rename_query->setOldCommit($grandparent);
- $rename_query->setViewer($request->getUser());
- $old_filename = $rename_query->loadOldFilename();
- $was_created = $rename_query->getWasCreated();
- }
- }
-
- $follow = null;
- if ($was_created) {
- // If the file was created in history, that means older commits won't
- // have it. Since we know it existed at 'before', it must have been
- // created then; jump there.
- $target_commit = $before;
- $follow = 'created';
- } else if ($parent) {
- // If we found a parent, jump to it. This is the normal case.
- $target_commit = $parent;
- } else {
- // If there's no parent, this was probably created in the initial commit?
- // And the "was_created" check will fail because we can't identify the
- // grandparent. Keep the user at 'before'.
- $target_commit = $before;
- $follow = 'first';
- }
-
- $path = $drequest->getPath();
- $renamed = null;
- if ($old_filename !== null &&
- $old_filename !== '/'.$path) {
- $renamed = $path;
- $path = $old_filename;
- }
-
- $line = null;
- // If there's a follow error, drop the line so the user sees the message.
- if (!$follow) {
- $line = $this->getBeforeLineNumber($target_commit);
- }
-
- $before_uri = $drequest->generateURI(
- array(
- 'action' => 'browse',
- 'commit' => $target_commit,
- 'line' => $line,
- 'path' => $path,
- ));
-
- $before_uri->setQueryParams($request->getRequestURI()->getQueryParams());
- $before_uri = $before_uri->alter('before', null);
- $before_uri = $before_uri->alter('renamed', $renamed);
- $before_uri = $before_uri->alter('follow', $follow);
-
- return id(new AphrontRedirectResponse())->setURI($before_uri);
- }
-
- private function getBeforeLineNumber($target_commit) {
- $drequest = $this->getDiffusionRequest();
-
- $line = $drequest->getLine();
- if (!$line) {
- return null;
- }
-
- $raw_diff = $this->callConduitWithDiffusionRequest(
- 'diffusion.rawdiffquery',
- array(
- 'commit' => $drequest->getCommit(),
- 'path' => $drequest->getPath(),
- 'againstCommit' => $target_commit,
- ));
- $old_line = 0;
- $new_line = 0;
-
- foreach (explode("\n", $raw_diff) as $text) {
- if ($text[0] == '-' || $text[0] == ' ') {
- $old_line++;
- }
- if ($text[0] == '+' || $text[0] == ' ') {
- $new_line++;
- }
- if ($new_line == $line) {
- return $old_line;
- }
- }
-
- // We didn't find the target line.
- return $line;
- }
-
- private function loadParentCommitOf($commit) {
- $drequest = $this->getDiffusionRequest();
- $user = $this->getRequest()->getUser();
-
- $before_req = DiffusionRequest::newFromDictionary(
- array(
- 'user' => $user,
- 'repository' => $drequest->getRepository(),
- 'commit' => $commit,
- ));
-
- $parents = DiffusionQuery::callConduitWithDiffusionRequest(
- $user,
- $before_req,
- 'diffusion.commitparentsquery',
- array(
- 'commit' => $commit,
- ));
-
- return head($parents);
- }
-
- private function renderRevisionTooltip(
- DifferentialRevision $revision,
- array $handles) {
- $viewer = $this->getRequest()->getUser();
-
- $date = phabricator_date($revision->getDateModified(), $viewer);
- $id = $revision->getID();
- $title = $revision->getTitle();
- $header = "D{$id} {$title}";
-
- $author = $handles[$revision->getAuthorPHID()]->getName();
-
- return "{$header}\n{$date} \xC2\xB7 {$author}";
- }
-
- private function renderCommitTooltip(
- PhabricatorRepositoryCommit $commit,
- array $handles,
- $author) {
-
- $viewer = $this->getRequest()->getUser();
-
- $date = phabricator_date($commit->getEpoch(), $viewer);
- $summary = trim($commit->getSummary());
-
- if ($commit->getAuthorPHID()) {
- $author = $handles[$commit->getAuthorPHID()]->getName();
- }
-
- return "{$summary}\n{$date} \xC2\xB7 {$author}";
- }
-
-}
diff --git a/src/applications/diffusion/controller/DiffusionBrowseMainController.php b/src/applications/diffusion/controller/DiffusionBrowseMainController.php
deleted file mode 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseMainController.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-final class DiffusionBrowseMainController extends DiffusionBrowseController {
-
- protected function processDiffusionRequest(AphrontRequest $request) {
- $drequest = $this->diffusionRequest;
-
- // Figure out if we're browsing a directory, a file, or a search result
- // list. Then delegate to the appropriate controller.
-
- $grep = $request->getStr('grep');
- $find = $request->getStr('find');
- if (strlen($grep) || strlen($find)) {
- $controller = new DiffusionBrowseSearchController();
- } else {
- $results = DiffusionBrowseResultSet::newFromConduit(
- $this->callConduitWithDiffusionRequest(
- 'diffusion.browsequery',
- array(
- 'path' => $drequest->getPath(),
- 'commit' => $drequest->getStableCommit(),
- )));
- $reason = $results->getReasonForEmptyResultSet();
- $is_file = ($reason == DiffusionBrowseResultSet::REASON_IS_FILE);
-
- if ($is_file) {
- $controller = new DiffusionBrowseFileController($request);
- } else {
- $controller = new DiffusionBrowseDirectoryController($request);
- $controller->setBrowseQueryResults($results);
- }
- }
-
- $controller->setDiffusionRequest($drequest);
- $controller->setCurrentApplication($this->getCurrentApplication());
- return $this->delegateToController($controller);
- }
-
-}
diff --git a/src/applications/diffusion/controller/DiffusionBrowseSearchController.php b/src/applications/diffusion/controller/DiffusionBrowseSearchController.php
deleted file mode 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseSearchController.php
+++ /dev/null
@@ -1,231 +0,0 @@
-<?php
-
-final class DiffusionBrowseSearchController extends DiffusionBrowseController {
-
- protected function processDiffusionRequest(AphrontRequest $request) {
- $drequest = $this->diffusionRequest;
-
- $actions = $this->buildActionView($drequest);
- $properties = $this->buildPropertyView($drequest, $actions);
-
- $object_box = id(new PHUIObjectBoxView())
- ->setHeader($this->buildHeaderView($drequest))
- ->addPropertyList($properties);
-
- $content = array();
-
- $content[] = $object_box;
- $content[] = $this->renderSearchForm($collapsed = false);
- $content[] = $this->renderSearchResults();
-
- $crumbs = $this->buildCrumbs(
- array(
- 'branch' => true,
- 'path' => true,
- 'view' => 'browse',
- ));
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $content,
- ),
- array(
- 'title' => array(
- nonempty(basename($drequest->getPath()), '/'),
- $drequest->getRepository()->getDisplayName(),
- ),
- ));
- }
-
- private function renderSearchResults() {
- $drequest = $this->getDiffusionRequest();
- $repository = $drequest->getRepository();
- $results = array();
-
- $limit = 100;
- $page = $this->getRequest()->getInt('page', 0);
- $pager = new PHUIPagerView();
- $pager->setPageSize($limit);
- $pager->setOffset($page);
- $pager->setURI($this->getRequest()->getRequestURI(), 'page');
-
- $search_mode = null;
-
- switch ($repository->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $results = array();
- break;
- default:
- if (strlen($this->getRequest()->getStr('grep'))) {
- $search_mode = 'grep';
- $query_string = $this->getRequest()->getStr('grep');
- $results = $this->callConduitWithDiffusionRequest(
- 'diffusion.searchquery',
- array(
- 'grep' => $query_string,
- 'commit' => $drequest->getStableCommit(),
- 'path' => $drequest->getPath(),
- 'limit' => $limit + 1,
- 'offset' => $page,
- ));
- } else { // Filename search.
- $search_mode = 'find';
- $query_string = $this->getRequest()->getStr('find');
- $results = $this->callConduitWithDiffusionRequest(
- 'diffusion.querypaths',
- array(
- 'pattern' => $query_string,
- 'commit' => $drequest->getStableCommit(),
- 'path' => $drequest->getPath(),
- 'limit' => $limit + 1,
- 'offset' => $page,
- ));
- }
- break;
- }
-
- $results = $pager->sliceResults($results);
-
- if ($search_mode == 'grep') {
- $table = $this->renderGrepResults($results, $query_string);
- $header = pht(
- 'File content matching "%s" under "%s"',
- $query_string,
- nonempty($drequest->getPath(), '/'));
- } else {
- $table = $this->renderFindResults($results);
- $header = pht(
- 'Paths matching "%s" under "%s"',
- $query_string,
- nonempty($drequest->getPath(), '/'));
- }
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText($header)
- ->setTable($table);
-
- $pager_box = id(new PHUIBoxView())
- ->addMargin(PHUI::MARGIN_LARGE)
- ->appendChild($pager);
-
- return array($box, $pager_box);
- }
-
- private function renderGrepResults(array $results, $pattern) {
- $drequest = $this->getDiffusionRequest();
-
- require_celerity_resource('phabricator-search-results-css');
-
- $rows = array();
- foreach ($results as $result) {
- list($path, $line, $string) = $result;
-
- $href = $drequest->generateURI(array(
- 'action' => 'browse',
- 'path' => $path,
- 'line' => $line,
- ));
-
- $matches = null;
- $count = @preg_match_all(
- '('.$pattern.')u',
- $string,
- $matches,
- PREG_OFFSET_CAPTURE);
-
- if (!$count) {
- $output = ltrim($string);
- } else {
- $output = array();
- $cursor = 0;
- $length = strlen($string);
- foreach ($matches[0] as $match) {
- $offset = $match[1];
- if ($cursor != $offset) {
- $output[] = array(
- 'text' => substr($string, $cursor, $offset),
- 'highlight' => false,
- );
- }
- $output[] = array(
- 'text' => $match[0],
- 'highlight' => true,
- );
- $cursor = $offset + strlen($match[0]);
- }
- if ($cursor != $length) {
- $output[] = array(
- 'text' => substr($string, $cursor),
- 'highlight' => false,
- );
- }
-
- if ($output) {
- $output[0]['text'] = ltrim($output[0]['text']);
- }
-
- foreach ($output as $key => $segment) {
- if ($segment['highlight']) {
- $output[$key] = phutil_tag('strong', array(), $segment['text']);
- } else {
- $output[$key] = $segment['text'];
- }
- }
- }
-
- $string = phutil_tag(
- 'pre',
- array('class' => 'PhabricatorMonospaced phui-source-fragment'),
- $output);
-
- $path = Filesystem::readablePath($path, $drequest->getPath());
-
- $rows[] = array(
- phutil_tag('a', array('href' => $href), $path),
- $line,
- $string,
- );
- }
-
- $table = id(new AphrontTableView($rows))
- ->setClassName('remarkup-code')
- ->setHeaders(array(pht('Path'), pht('Line'), pht('String')))
- ->setColumnClasses(array('', 'n', 'wide'))
- ->setNoDataString(
- pht(
- 'The pattern you searched for was not found in the content of any '.
- 'files.'));
-
- return $table;
- }
-
- private function renderFindResults(array $results) {
- $drequest = $this->getDiffusionRequest();
-
- $rows = array();
- foreach ($results as $result) {
- $href = $drequest->generateURI(array(
- 'action' => 'browse',
- 'path' => $result,
- ));
-
- $readable = Filesystem::readablePath($result, $drequest->getPath());
-
- $rows[] = array(
- phutil_tag('a', array('href' => $href), $readable),
- );
- }
-
- $table = id(new AphrontTableView($rows))
- ->setHeaders(array(pht('Path')))
- ->setColumnClasses(array('wide'))
- ->setNoDataString(
- pht(
- 'The pattern you searched for did not match the names of any '.
- 'files.'));
-
- return $table;
- }
-
-}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 25, 10:54 AM (11 h, 13 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7049873
Default Alt Text
D14942.id.diff (90 KB)
Attached To
Mode
D14942: Merge and modernize Browse controllers in Diffusion
Attached
Detach File
Event Timeline
Log In to Comment