Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/diff/view/PHUIDiffGraphView.php
- This file was added.
<?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; | |||||
} | |||||
} |