Something went wrong. Try again.
@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
Something went wrong. Try again.
6.2 kB · 227 lines
PHP
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228<?php
final class PHUIDiffGraphView extends Phobject {
private $isHead = true; private $isTail = true; private $height;
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 setHeight($height) { $this->height = $height; return $this; }
public function getHeight() { return $this->height; }
public function renderRawGraph(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);
$thread_count = $pos; for ($n = 0; $n < $thread_count; $n++) { if (empty($threads[$n])) { $line .= ' '; continue; }
if ($threads[$n] == $cursor) { if ($found) { $line .= ' '; $joins[] = $n; $threads[$n] = false; } 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; break; } }
// 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 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. if ($this->getIsTail() && $graph) { $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') { // If we've already terminated this thread, we don't need to add // a terminator. if (isset($terminated[$ii])) { continue; }
$terminated[$ii] = true;
// If this thread is joining some other node here, we don't want // to terminate it. if (isset($graph[$key + 1])) { $joins = $graph[$key + 1]['join']; if (in_array($ii, $joins)) { continue; } }
$graph[$key]['line'][$ii] = 'x'; } else if ($c != ' ') { $terminated[$ii] = true; } else { unset($terminated[$ii]); } } }
$last = array_pop($graph); $last['line'] = str_replace('^', 'X', $last['line']); $graph[] = $last; }
return array($graph, $count); }
/** * @return array<PhutilSafeHTML> */ public function renderGraph(array $parents) { list($graph, $count) = $this->renderRawGraph($parents);
// 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, 'height' => $this->getHeight(), ));
return $graph; }
}