Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/infrastructure/diff/view/PHUIDiffGraphView.php
12242 views
1
<?php
2
3
final class PHUIDiffGraphView extends Phobject {
4
5
private $isHead = true;
6
private $isTail = true;
7
private $height;
8
9
public function setIsHead($is_head) {
10
$this->isHead = $is_head;
11
return $this;
12
}
13
14
public function getIsHead() {
15
return $this->isHead;
16
}
17
18
public function setIsTail($is_tail) {
19
$this->isTail = $is_tail;
20
return $this;
21
}
22
23
public function getIsTail() {
24
return $this->isTail;
25
}
26
27
public function setHeight($height) {
28
$this->height = $height;
29
return $this;
30
}
31
32
public function getHeight() {
33
return $this->height;
34
}
35
36
public function renderRawGraph(array $parents) {
37
// This keeps our accumulated information about each line of the
38
// merge/branch graph.
39
$graph = array();
40
41
// This holds the next commit we're looking for in each column of the
42
// graph.
43
$threads = array();
44
45
// This is the largest number of columns any row has, i.e. the width of
46
// the graph.
47
$count = 0;
48
49
foreach ($parents as $cursor => $parent_list) {
50
$joins = array();
51
$splits = array();
52
53
// Look for some thread which has this commit as the next commit. If
54
// we find one, this commit goes on that thread. Otherwise, this commit
55
// goes on a new thread.
56
57
$line = '';
58
$found = false;
59
$pos = count($threads);
60
61
$thread_count = $pos;
62
for ($n = 0; $n < $thread_count; $n++) {
63
if (empty($threads[$n])) {
64
$line .= ' ';
65
continue;
66
}
67
68
if ($threads[$n] == $cursor) {
69
if ($found) {
70
$line .= ' ';
71
$joins[] = $n;
72
$threads[$n] = false;
73
} else {
74
$line .= 'o';
75
$found = true;
76
$pos = $n;
77
}
78
} else {
79
80
// We render a "|" for any threads which have a commit that we haven't
81
// seen yet, this is later drawn as a vertical line.
82
$line .= '|';
83
}
84
}
85
86
// If we didn't find the thread this commit goes on, start a new thread.
87
// We use "o" to mark the commit for the rendering engine, or "^" to
88
// indicate that there's nothing after it so the line from the commit
89
// upward should not be drawn.
90
91
if (!$found) {
92
if ($this->getIsHead()) {
93
$line .= '^';
94
} else {
95
$line .= 'o';
96
foreach ($graph as $k => $meta) {
97
// Go back across all the lines we've already drawn and add a
98
// "|" to the end, since this is connected to some future commit
99
// we don't know about.
100
for ($jj = strlen($meta['line']); $jj <= $count; $jj++) {
101
$graph[$k]['line'] .= '|';
102
}
103
}
104
}
105
}
106
107
// Update the next commit on this thread to the commit's first parent.
108
// This might have the effect of making a new thread.
109
$threads[$pos] = head($parent_list);
110
111
// If we made a new thread, increase the thread count.
112
$count = max($pos + 1, $count);
113
114
// Now, deal with splits (merges). I picked this terms opposite to the
115
// underlying repository term to confuse you.
116
foreach (array_slice($parent_list, 1) as $parent) {
117
$found = false;
118
119
// Try to find the other parent(s) in our existing threads. If we find
120
// them, split to that thread.
121
122
foreach ($threads as $idx => $thread_commit) {
123
if ($thread_commit == $parent) {
124
$found = true;
125
$splits[] = $idx;
126
break;
127
}
128
}
129
130
// If we didn't find the parent, we don't know about it yet. Find the
131
// first free thread and add it as the "next" commit in that thread.
132
// This might create a new thread.
133
134
if (!$found) {
135
for ($n = 0; $n < $count; $n++) {
136
if (empty($threads[$n])) {
137
break;
138
}
139
}
140
$threads[$n] = $parent;
141
$splits[] = $n;
142
$count = max($n + 1, $count);
143
}
144
}
145
146
$graph[] = array(
147
'line' => $line,
148
'split' => $splits,
149
'join' => $joins,
150
);
151
}
152
153
// If this is the last page in history, replace any "o" characters at the
154
// bottom of columns with "x" characters so we do not draw a connecting
155
// line downward, and replace "^" with an "X" for repositories with
156
// exactly one commit.
157
if ($this->getIsTail() && $graph) {
158
$terminated = array();
159
foreach (array_reverse(array_keys($graph)) as $key) {
160
$line = $graph[$key]['line'];
161
$len = strlen($line);
162
for ($ii = 0; $ii < $len; $ii++) {
163
$c = $line[$ii];
164
if ($c == 'o') {
165
// If we've already terminated this thread, we don't need to add
166
// a terminator.
167
if (isset($terminated[$ii])) {
168
continue;
169
}
170
171
$terminated[$ii] = true;
172
173
// If this thread is joining some other node here, we don't want
174
// to terminate it.
175
if (isset($graph[$key + 1])) {
176
$joins = $graph[$key + 1]['join'];
177
if (in_array($ii, $joins)) {
178
continue;
179
}
180
}
181
182
$graph[$key]['line'][$ii] = 'x';
183
} else if ($c != ' ') {
184
$terminated[$ii] = true;
185
} else {
186
unset($terminated[$ii]);
187
}
188
}
189
}
190
191
$last = array_pop($graph);
192
$last['line'] = str_replace('^', 'X', $last['line']);
193
$graph[] = $last;
194
}
195
196
return array($graph, $count);
197
}
198
199
public function renderGraph(array $parents) {
200
list($graph, $count) = $this->renderRawGraph($parents);
201
202
// Render into tags for the behavior.
203
204
foreach ($graph as $k => $meta) {
205
$graph[$k] = javelin_tag(
206
'div',
207
array(
208
'sigil' => 'commit-graph',
209
'meta' => $meta,
210
),
211
'');
212
}
213
214
Javelin::initBehavior(
215
'diffusion-commit-graph',
216
array(
217
'count' => $count,
218
'height' => $this->getHeight(),
219
));
220
221
return $graph;
222
}
223
224
}
225
226