Build that thing someone posted a screenshot of on Facebook
Summary: Seemed kinda cool.
Test Plan: {F1707244}
Reviewers: chad
Reviewed By: chad
Differential Revision: https://secure.phabricator.com/D16210
This commit is contained in:
171
src/infrastructure/diff/view/PHUIDiffGraphView.php
Normal file
171
src/infrastructure/diff/view/PHUIDiffGraphView.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
final class PHUIDiffGraphView extends Phobject {
|
||||
|
||||
private $isHead = true;
|
||||
private $isTail = true;
|
||||
|
||||
public function setIsHead($is_head) {
|
||||
$this->isHead = $is_head;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsHead() {
|
||||
return $this->isHead;
|
||||
}
|
||||
|
||||
public function setIsTail($is_tail) {
|
||||
$this->isTail = $is_tail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsTail() {
|
||||
return $this->isTail;
|
||||
}
|
||||
|
||||
public function renderGraph(array $parents) {
|
||||
// This keeps our accumulated information about each line of the
|
||||
// merge/branch graph.
|
||||
$graph = array();
|
||||
|
||||
// This holds the next commit we're looking for in each column of the
|
||||
// graph.
|
||||
$threads = array();
|
||||
|
||||
// This is the largest number of columns any row has, i.e. the width of
|
||||
// the graph.
|
||||
$count = 0;
|
||||
|
||||
foreach ($parents as $cursor => $parent_list) {
|
||||
$joins = array();
|
||||
$splits = array();
|
||||
|
||||
// Look for some thread which has this commit as the next commit. If
|
||||
// we find one, this commit goes on that thread. Otherwise, this commit
|
||||
// goes on a new thread.
|
||||
|
||||
$line = '';
|
||||
$found = false;
|
||||
$pos = count($threads);
|
||||
for ($n = 0; $n < $count; $n++) {
|
||||
if (empty($threads[$n])) {
|
||||
$line .= ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($threads[$n] == $cursor) {
|
||||
if ($found) {
|
||||
$line .= ' ';
|
||||
$joins[] = $n;
|
||||
unset($threads[$n]);
|
||||
} else {
|
||||
$line .= 'o';
|
||||
$found = true;
|
||||
$pos = $n;
|
||||
}
|
||||
} else {
|
||||
|
||||
// We render a "|" for any threads which have a commit that we haven't
|
||||
// seen yet, this is later drawn as a vertical line.
|
||||
$line .= '|';
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find the thread this commit goes on, start a new thread.
|
||||
// We use "o" to mark the commit for the rendering engine, or "^" to
|
||||
// indicate that there's nothing after it so the line from the commit
|
||||
// upward should not be drawn.
|
||||
|
||||
if (!$found) {
|
||||
if ($this->getIsHead()) {
|
||||
$line .= '^';
|
||||
} else {
|
||||
$line .= 'o';
|
||||
foreach ($graph as $k => $meta) {
|
||||
// Go back across all the lines we've already drawn and add a
|
||||
// "|" to the end, since this is connected to some future commit
|
||||
// we don't know about.
|
||||
for ($jj = strlen($meta['line']); $jj <= $count; $jj++) {
|
||||
$graph[$k]['line'] .= '|';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the next commit on this thread to the commit's first parent.
|
||||
// This might have the effect of making a new thread.
|
||||
$threads[$pos] = head($parent_list);
|
||||
|
||||
// If we made a new thread, increase the thread count.
|
||||
$count = max($pos + 1, $count);
|
||||
|
||||
// Now, deal with splits (merges). I picked this terms opposite to the
|
||||
// underlying repository term to confuse you.
|
||||
foreach (array_slice($parent_list, 1) as $parent) {
|
||||
$found = false;
|
||||
|
||||
// Try to find the other parent(s) in our existing threads. If we find
|
||||
// them, split to that thread.
|
||||
|
||||
foreach ($threads as $idx => $thread_commit) {
|
||||
if ($thread_commit == $parent) {
|
||||
$found = true;
|
||||
$splits[] = $idx;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find the parent, we don't know about it yet. Find the
|
||||
// first free thread and add it as the "next" commit in that thread.
|
||||
// This might create a new thread.
|
||||
|
||||
if (!$found) {
|
||||
for ($n = 0; $n < $count; $n++) {
|
||||
if (empty($threads[$n])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$threads[$n] = $parent;
|
||||
$splits[] = $n;
|
||||
$count = max($n + 1, $count);
|
||||
}
|
||||
}
|
||||
|
||||
$graph[] = array(
|
||||
'line' => $line,
|
||||
'split' => $splits,
|
||||
'join' => $joins,
|
||||
);
|
||||
}
|
||||
|
||||
// If this is the last page in history, replace the "o" with an "x" so we
|
||||
// do not draw a connecting line downward, and replace "^" with an "X" for
|
||||
// repositories with exactly one commit.
|
||||
if ($this->getIsTail() && $graph) {
|
||||
$last = array_pop($graph);
|
||||
$last['line'] = str_replace('o', 'x', $last['line']);
|
||||
$last['line'] = str_replace('^', 'X', $last['line']);
|
||||
$graph[] = $last;
|
||||
}
|
||||
|
||||
// Render into tags for the behavior.
|
||||
|
||||
foreach ($graph as $k => $meta) {
|
||||
$graph[$k] = javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
'sigil' => 'commit-graph',
|
||||
'meta' => $meta,
|
||||
),
|
||||
'');
|
||||
}
|
||||
|
||||
Javelin::initBehavior(
|
||||
'diffusion-commit-graph',
|
||||
array(
|
||||
'count' => $count,
|
||||
));
|
||||
|
||||
return $graph;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user