phorge/src/infrastructure/diff/view/PHUIDiffGraphView.php9bd6a3705559master
phorge/src/infrastructure/diff/view/PHUIDiffGraphView.php
9bd6a3705559master
PHUIDiffGraphView.php
PHUIDiffGraphView.php
dc37789d530f | <?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; | |||
} | |||
7b5e84282fc6 | public function renderRawGraph(array $parents) { | ||
dc37789d530f | // 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); | |||
7b5e84282fc6 | |||
$thread_count = $pos; | |||
for ($n = 0; $n < $thread_count; $n++) { | |||
dc37789d530f | if (empty($threads[$n])) { | ||
$line .= ' '; | |||
continue; | |||
} | |||
if ($threads[$n] == $cursor) { | |||
if ($found) { | |||
$line .= ' '; | |||
$joins[] = $n; | |||
48187cdbbe99 | $threads[$n] = false; | ||
dc37789d530f | } 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; | |||
48187cdbbe99 | break; | ||
dc37789d530f | } | ||
} | |||
// 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, | |||
); | |||
} | |||
0a132e468fc4 | // If this is the last page in history, replace any "o" characters at the | ||
// bottom of columns with "x" characters so we do not draw a connecting | |||
// line downward, and replace "^" with an "X" for repositories with | |||
// exactly one commit. | |||
dc37789d530f | if ($this->getIsTail() && $graph) { | ||
0a132e468fc4 | $terminated = array(); | ||
foreach (array_reverse(array_keys($graph)) as $key) { | |||
$line = $graph[$key]['line']; | |||
$len = strlen($line); | |||
for ($ii = 0; $ii < $len; $ii++) { | |||
$c = $line[$ii]; | |||
if ($c == 'o') { | |||
7b5e84282fc6 | // If we've already terminated this thread, we don't need to add | ||
// a terminator. | |||
if (isset($terminated[$ii])) { | |||
continue; | |||
} | |||
0a132e468fc4 | $terminated[$ii] = true; | ||
7b5e84282fc6 | |||
9bd6a3705559 | // If this thread is joining some other node here, we don't want | ||
7b5e84282fc6 | // to terminate it. | ||
if (isset($graph[$key + 1])) { | |||
$joins = $graph[$key + 1]['join']; | |||
if (in_array($ii, $joins)) { | |||
continue; | |||
} | |||
} | |||
0a132e468fc4 | $graph[$key]['line'][$ii] = 'x'; | ||
} else if ($c != ' ') { | |||
$terminated[$ii] = true; | |||
7b5e84282fc6 | } else { | ||
unset($terminated[$ii]); | |||
0a132e468fc4 | } | ||
} | |||
} | |||
dc37789d530f | $last = array_pop($graph); | ||
$last['line'] = str_replace('^', 'X', $last['line']); | |||
$graph[] = $last; | |||
} | |||
7b5e84282fc6 | return array($graph, $count); | ||
} | |||
public function renderGraph(array $parents) { | |||
list($graph, $count) = $this->renderRawGraph($parents); | |||
dc37789d530f | // 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; | |||
} | |||
} |
Owner Packages
Owner Packages
- No Owners