Path: blob/master/src/infrastructure/diff/view/PHUIDiffGraphView.php
12242 views
<?php12final class PHUIDiffGraphView extends Phobject {34private $isHead = true;5private $isTail = true;6private $height;78public function setIsHead($is_head) {9$this->isHead = $is_head;10return $this;11}1213public function getIsHead() {14return $this->isHead;15}1617public function setIsTail($is_tail) {18$this->isTail = $is_tail;19return $this;20}2122public function getIsTail() {23return $this->isTail;24}2526public function setHeight($height) {27$this->height = $height;28return $this;29}3031public function getHeight() {32return $this->height;33}3435public function renderRawGraph(array $parents) {36// This keeps our accumulated information about each line of the37// merge/branch graph.38$graph = array();3940// This holds the next commit we're looking for in each column of the41// graph.42$threads = array();4344// This is the largest number of columns any row has, i.e. the width of45// the graph.46$count = 0;4748foreach ($parents as $cursor => $parent_list) {49$joins = array();50$splits = array();5152// Look for some thread which has this commit as the next commit. If53// we find one, this commit goes on that thread. Otherwise, this commit54// goes on a new thread.5556$line = '';57$found = false;58$pos = count($threads);5960$thread_count = $pos;61for ($n = 0; $n < $thread_count; $n++) {62if (empty($threads[$n])) {63$line .= ' ';64continue;65}6667if ($threads[$n] == $cursor) {68if ($found) {69$line .= ' ';70$joins[] = $n;71$threads[$n] = false;72} else {73$line .= 'o';74$found = true;75$pos = $n;76}77} else {7879// We render a "|" for any threads which have a commit that we haven't80// seen yet, this is later drawn as a vertical line.81$line .= '|';82}83}8485// If we didn't find the thread this commit goes on, start a new thread.86// We use "o" to mark the commit for the rendering engine, or "^" to87// indicate that there's nothing after it so the line from the commit88// upward should not be drawn.8990if (!$found) {91if ($this->getIsHead()) {92$line .= '^';93} else {94$line .= 'o';95foreach ($graph as $k => $meta) {96// Go back across all the lines we've already drawn and add a97// "|" to the end, since this is connected to some future commit98// we don't know about.99for ($jj = strlen($meta['line']); $jj <= $count; $jj++) {100$graph[$k]['line'] .= '|';101}102}103}104}105106// Update the next commit on this thread to the commit's first parent.107// This might have the effect of making a new thread.108$threads[$pos] = head($parent_list);109110// If we made a new thread, increase the thread count.111$count = max($pos + 1, $count);112113// Now, deal with splits (merges). I picked this terms opposite to the114// underlying repository term to confuse you.115foreach (array_slice($parent_list, 1) as $parent) {116$found = false;117118// Try to find the other parent(s) in our existing threads. If we find119// them, split to that thread.120121foreach ($threads as $idx => $thread_commit) {122if ($thread_commit == $parent) {123$found = true;124$splits[] = $idx;125break;126}127}128129// If we didn't find the parent, we don't know about it yet. Find the130// first free thread and add it as the "next" commit in that thread.131// This might create a new thread.132133if (!$found) {134for ($n = 0; $n < $count; $n++) {135if (empty($threads[$n])) {136break;137}138}139$threads[$n] = $parent;140$splits[] = $n;141$count = max($n + 1, $count);142}143}144145$graph[] = array(146'line' => $line,147'split' => $splits,148'join' => $joins,149);150}151152// If this is the last page in history, replace any "o" characters at the153// bottom of columns with "x" characters so we do not draw a connecting154// line downward, and replace "^" with an "X" for repositories with155// exactly one commit.156if ($this->getIsTail() && $graph) {157$terminated = array();158foreach (array_reverse(array_keys($graph)) as $key) {159$line = $graph[$key]['line'];160$len = strlen($line);161for ($ii = 0; $ii < $len; $ii++) {162$c = $line[$ii];163if ($c == 'o') {164// If we've already terminated this thread, we don't need to add165// a terminator.166if (isset($terminated[$ii])) {167continue;168}169170$terminated[$ii] = true;171172// If this thread is joining some other node here, we don't want173// to terminate it.174if (isset($graph[$key + 1])) {175$joins = $graph[$key + 1]['join'];176if (in_array($ii, $joins)) {177continue;178}179}180181$graph[$key]['line'][$ii] = 'x';182} else if ($c != ' ') {183$terminated[$ii] = true;184} else {185unset($terminated[$ii]);186}187}188}189190$last = array_pop($graph);191$last['line'] = str_replace('^', 'X', $last['line']);192$graph[] = $last;193}194195return array($graph, $count);196}197198public function renderGraph(array $parents) {199list($graph, $count) = $this->renderRawGraph($parents);200201// Render into tags for the behavior.202203foreach ($graph as $k => $meta) {204$graph[$k] = javelin_tag(205'div',206array(207'sigil' => 'commit-graph',208'meta' => $meta,209),210'');211}212213Javelin::initBehavior(214'diffusion-commit-graph',215array(216'count' => $count,217'height' => $this->getHeight(),218));219220return $graph;221}222223}224225226