@theia/scm 1.75.0-next.8 → 1.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/lib/browser/decorations/scm-navigator-decorator.d.ts.map +1 -1
  2. package/lib/browser/decorations/scm-navigator-decorator.js +1 -0
  3. package/lib/browser/decorations/scm-navigator-decorator.js.map +1 -1
  4. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js +7 -10
  5. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js.map +1 -1
  6. package/lib/browser/scm-action-button-widget.js +10 -15
  7. package/lib/browser/scm-action-button-widget.js.map +1 -1
  8. package/lib/browser/scm-amend-component.js +24 -57
  9. package/lib/browser/scm-amend-component.js.map +1 -1
  10. package/lib/browser/scm-commit-widget.d.ts +1 -1
  11. package/lib/browser/scm-commit-widget.d.ts.map +1 -1
  12. package/lib/browser/scm-commit-widget.js +9 -10
  13. package/lib/browser/scm-commit-widget.js.map +1 -1
  14. package/lib/browser/scm-context-key-service.d.ts +2 -0
  15. package/lib/browser/scm-context-key-service.d.ts.map +1 -1
  16. package/lib/browser/scm-context-key-service.js +4 -0
  17. package/lib/browser/scm-context-key-service.js.map +1 -1
  18. package/lib/browser/scm-context-key-service.spec.js +7 -0
  19. package/lib/browser/scm-context-key-service.spec.js.map +1 -1
  20. package/lib/browser/scm-frontend-module.d.ts.map +1 -1
  21. package/lib/browser/scm-frontend-module.js +6 -0
  22. package/lib/browser/scm-frontend-module.js.map +1 -1
  23. package/lib/browser/scm-history-graph-contribution.d.ts +49 -0
  24. package/lib/browser/scm-history-graph-contribution.d.ts.map +1 -0
  25. package/lib/browser/scm-history-graph-contribution.js +280 -0
  26. package/lib/browser/scm-history-graph-contribution.js.map +1 -0
  27. package/lib/browser/scm-history-graph-contribution.spec.d.ts +2 -0
  28. package/lib/browser/scm-history-graph-contribution.spec.d.ts.map +1 -0
  29. package/lib/browser/scm-history-graph-contribution.spec.js +119 -0
  30. package/lib/browser/scm-history-graph-contribution.spec.js.map +1 -0
  31. package/lib/browser/scm-history-graph-helpers.d.ts +59 -6
  32. package/lib/browser/scm-history-graph-helpers.d.ts.map +1 -1
  33. package/lib/browser/scm-history-graph-helpers.js +129 -5
  34. package/lib/browser/scm-history-graph-helpers.js.map +1 -1
  35. package/lib/browser/scm-history-graph-helpers.spec.d.ts +2 -0
  36. package/lib/browser/scm-history-graph-helpers.spec.d.ts.map +1 -0
  37. package/lib/browser/scm-history-graph-helpers.spec.js +154 -0
  38. package/lib/browser/scm-history-graph-helpers.spec.js.map +1 -0
  39. package/lib/browser/scm-history-graph-lanes.d.ts +19 -5
  40. package/lib/browser/scm-history-graph-lanes.d.ts.map +1 -1
  41. package/lib/browser/scm-history-graph-lanes.js +25 -9
  42. package/lib/browser/scm-history-graph-lanes.js.map +1 -1
  43. package/lib/browser/scm-history-graph-lanes.spec.js +62 -25
  44. package/lib/browser/scm-history-graph-lanes.spec.js.map +1 -1
  45. package/lib/browser/scm-history-graph-model.d.ts +75 -6
  46. package/lib/browser/scm-history-graph-model.d.ts.map +1 -1
  47. package/lib/browser/scm-history-graph-model.js +155 -10
  48. package/lib/browser/scm-history-graph-model.js.map +1 -1
  49. package/lib/browser/scm-history-graph-model.spec.js +299 -4
  50. package/lib/browser/scm-history-graph-model.spec.js.map +1 -1
  51. package/lib/browser/scm-history-graph-tooltip.d.ts +27 -2
  52. package/lib/browser/scm-history-graph-tooltip.d.ts.map +1 -1
  53. package/lib/browser/scm-history-graph-tooltip.js +113 -22
  54. package/lib/browser/scm-history-graph-tooltip.js.map +1 -1
  55. package/lib/browser/scm-history-graph-tooltip.spec.d.ts +2 -0
  56. package/lib/browser/scm-history-graph-tooltip.spec.d.ts.map +1 -0
  57. package/lib/browser/scm-history-graph-tooltip.spec.js +213 -0
  58. package/lib/browser/scm-history-graph-tooltip.spec.js.map +1 -0
  59. package/lib/browser/scm-history-graph-widget.d.ts +36 -2
  60. package/lib/browser/scm-history-graph-widget.d.ts.map +1 -1
  61. package/lib/browser/scm-history-graph-widget.js +174 -67
  62. package/lib/browser/scm-history-graph-widget.js.map +1 -1
  63. package/lib/browser/scm-history-graph-widget.spec.d.ts +2 -0
  64. package/lib/browser/scm-history-graph-widget.spec.d.ts.map +1 -0
  65. package/lib/browser/scm-history-graph-widget.spec.js +273 -0
  66. package/lib/browser/scm-history-graph-widget.spec.js.map +1 -0
  67. package/lib/browser/scm-provider.d.ts +9 -1
  68. package/lib/browser/scm-provider.d.ts.map +1 -1
  69. package/lib/browser/scm-provider.js.map +1 -1
  70. package/lib/browser/scm-repositories-widget.js +12 -21
  71. package/lib/browser/scm-repositories-widget.js.map +1 -1
  72. package/lib/browser/scm-tree-widget.js +35 -53
  73. package/lib/browser/scm-tree-widget.js.map +1 -1
  74. package/lib/common/scm-preferences.d.ts +3 -0
  75. package/lib/common/scm-preferences.d.ts.map +1 -1
  76. package/lib/common/scm-preferences.js +24 -0
  77. package/lib/common/scm-preferences.js.map +1 -1
  78. package/package.json +7 -7
  79. package/src/browser/decorations/scm-navigator-decorator.ts +3 -2
  80. package/src/browser/scm-context-key-service.spec.ts +9 -0
  81. package/src/browser/scm-context-key-service.ts +6 -0
  82. package/src/browser/scm-frontend-module.ts +7 -1
  83. package/src/browser/scm-history-graph-contribution.spec.ts +148 -0
  84. package/src/browser/scm-history-graph-contribution.ts +273 -0
  85. package/src/browser/scm-history-graph-helpers.spec.ts +193 -0
  86. package/src/browser/scm-history-graph-helpers.ts +180 -6
  87. package/src/browser/scm-history-graph-lanes.spec.ts +70 -25
  88. package/src/browser/scm-history-graph-lanes.ts +48 -11
  89. package/src/browser/scm-history-graph-model.spec.ts +378 -12
  90. package/src/browser/scm-history-graph-model.ts +181 -13
  91. package/src/browser/scm-history-graph-tooltip.spec.ts +254 -0
  92. package/src/browser/scm-history-graph-tooltip.ts +144 -24
  93. package/src/browser/scm-history-graph-widget.spec.ts +322 -0
  94. package/src/browser/scm-history-graph-widget.tsx +199 -39
  95. package/src/browser/scm-provider.ts +9 -1
  96. package/src/browser/style/scm-history-graph.css +53 -2
  97. package/src/common/scm-preferences.ts +27 -0
@@ -37,9 +37,14 @@ describe('computeGraphRows', () => {
37
37
  expect(lanes(commits)).to.deep.equal([0, 0, 0]);
38
38
  });
39
39
 
40
- it('colors are all 0', () => {
40
+ it('colors default to the first rotation color (foreground1 = index 3)', () => {
41
41
  const rows = computeGraphRows(commits);
42
- expect(rows.map(r => r.color)).to.deep.equal([0, 0, 0]);
42
+ expect(rows.map(r => r.color)).to.deep.equal([3, 3, 3]);
43
+ });
44
+
45
+ it('topColor equals color when no ref color overrides the lane', () => {
46
+ const rows = computeGraphRows(commits);
47
+ rows.forEach(r => expect(r.topColor).to.equal(r.color));
43
48
  });
44
49
 
45
50
  it('first parent same-lane continuation emits no separate edge (handled by commit line)', () => {
@@ -201,9 +206,13 @@ describe('computeGraphRows', () => {
201
206
  expect(mergeIn.length).to.equal(0);
202
207
  });
203
208
 
204
- it('lane colors are correct modulo 8', () => {
209
+ it('lane colors rotate through the default registry (indices 3-7)', () => {
205
210
  const rows = computeGraphRows(commits);
206
- rows.forEach(r => expect(r.color).to.equal(r.lane % 8));
211
+ // O and P1 share lane 0 → first rotation color; P2/P3 opened new lanes
212
+ expect(rows[0].color).to.equal(3);
213
+ expect(rows[1].color).to.equal(3);
214
+ expect(rows[2].color).to.not.equal(rows[3].color);
215
+ rows.forEach(r => expect(r.color).to.be.within(3, 7));
207
216
  });
208
217
  });
209
218
 
@@ -387,25 +396,14 @@ describe('computeGraphRows', () => {
387
396
  });
388
397
 
389
398
  // -------------------------------------------------------------------------
390
- // Lane color wraps at 8
399
+ // Default color rotation (VS Code cycles scmGraph.foreground1-5)
391
400
  // -------------------------------------------------------------------------
392
- describe('color wrapping', () => {
393
- it('lane color is always lane % 8', () => {
394
- // 4 parallel chains so we have lanes 0, 1, 2, 3 occupied at once.
395
- // Chain structure: X0→X1→X2, Y0→Y1→Y2, etc., interleaved.
396
- const commits = [
397
- { id: 'X0', parentIds: ['X1'] },
398
- { id: 'Y0', parentIds: ['Y1'] },
399
- { id: 'Z0', parentIds: ['Z1'] },
400
- { id: 'W0', parentIds: ['W1'] },
401
- { id: 'X1', parentIds: [] },
402
- { id: 'Y1', parentIds: [] },
403
- { id: 'Z1', parentIds: [] },
404
- { id: 'W1', parentIds: [] },
405
- ];
401
+ describe('default color rotation', () => {
402
+ it('cycles through indices 3-7 and wraps', () => {
403
+ // 6 independent tips 6 lanes; the sixth wraps back to the first color
404
+ const commits = ['A', 'B', 'C', 'D', 'E', 'F'].map(id => ({ id, parentIds: [id.toLowerCase()] }));
406
405
  const rows = computeGraphRows(commits);
407
- // Every row's color must equal lane % 8
408
- rows.forEach(r => expect(r.color).to.equal(r.lane % 8));
406
+ expect(rows.map(r => r.color)).to.deep.equal([3, 4, 5, 6, 7, 3]);
409
407
  });
410
408
 
411
409
  it('assigns distinct lanes to 8 simultaneous branches', () => {
@@ -423,10 +421,57 @@ describe('computeGraphRows', () => {
423
421
  const rows = computeGraphRows(commits);
424
422
  const laneSet = new Set(rows.map(r => r.lane));
425
423
  expect(laneSet.size).to.equal(8); // all distinct lanes
426
- // Color of lane 7 is 7, lane 0 is 0
427
- const lane7 = rows.find(r => r.lane === 7);
428
- expect(lane7).to.not.be.undefined;
429
- expect(lane7!.color).to.equal(7);
424
+ // Default colors never use the reserved ref color indices 0-2
425
+ rows.forEach(r => expect(r.color).to.be.within(3, 7));
426
+ });
427
+ });
428
+
429
+ // -------------------------------------------------------------------------
430
+ // Ref-based colors (VS Code colorMap: current=0, remote=1, base=2)
431
+ // -------------------------------------------------------------------------
432
+ describe('ref-based colors', () => {
433
+ // Remote is one commit ahead: R (origin/main) → L (main = HEAD) → A
434
+ const behindCommits = [
435
+ { id: 'R', parentIds: ['L'], colorIndex: 1 },
436
+ { id: 'L', parentIds: ['A'], colorIndex: 0 },
437
+ { id: 'A', parentIds: [] },
438
+ ];
439
+
440
+ it('a tip with a color index colors its row', () => {
441
+ const rows = computeGraphRows(behindCommits);
442
+ expect(rows[0].color).to.equal(1);
443
+ });
444
+
445
+ it('an overriding commit recolors the chain from its row downward', () => {
446
+ const rows = computeGraphRows(behindCommits);
447
+ expect(rows[1].color).to.equal(0);
448
+ expect(rows[2].color).to.equal(0);
449
+ });
450
+
451
+ it('topColor keeps the inherited color for the segment above an overriding commit', () => {
452
+ const rows = computeGraphRows(behindCommits);
453
+ expect(rows[0].topColor).to.equal(1);
454
+ expect(rows[1].topColor).to.equal(1);
455
+ expect(rows[2].topColor).to.equal(0);
456
+ });
457
+
458
+ // Diverged: L (main = HEAD) and R (origin/main) both branched off A
459
+ const divergedCommits = [
460
+ { id: 'L', parentIds: ['A'], colorIndex: 0 },
461
+ { id: 'R', parentIds: ['A'], colorIndex: 1 },
462
+ { id: 'A', parentIds: [] },
463
+ ];
464
+
465
+ it('pass-through edges use the propagated ref color', () => {
466
+ const rows = computeGraphRows(divergedCommits);
467
+ const pass = rows[1].edges.find(e => e.type === 'pass-through');
468
+ expect(pass?.color).to.equal(0);
469
+ });
470
+
471
+ it('merge-in edges from a ref-colored lane keep that color', () => {
472
+ const rows = computeGraphRows(divergedCommits);
473
+ const mergeIn = rows[2].edges.find(e => e.type === 'merge-in');
474
+ expect(mergeIn?.color).to.equal(1);
430
475
  });
431
476
  });
432
477
 
@@ -47,8 +47,14 @@ export interface GraphEdge {
47
47
  export interface GraphRow {
48
48
  /** Lane index where the commit node is rendered. */
49
49
  readonly lane: number;
50
- /** Color index for the commit node dot. */
50
+ /** Color index for the commit node dot and the lane segment below it. */
51
51
  readonly color: number;
52
+ /**
53
+ * Color index for the lane segment above the commit node. Differs from
54
+ * `color` when this commit's ref color overrides the color inherited from
55
+ * the chain above (e.g. the current branch tip below remote-only commits).
56
+ */
57
+ readonly topColor: number;
52
58
  /** Edges crossing or originating on this row. */
53
59
  readonly edges: readonly GraphEdge[];
54
60
  /**
@@ -71,11 +77,29 @@ export interface GraphRow {
71
77
  interface MutableGraphRow {
72
78
  lane: number;
73
79
  color: number;
80
+ topColor: number;
74
81
  edges: GraphEdge[];
75
82
  hasContinuation: boolean;
76
83
  hasTopLine: boolean;
77
84
  }
78
85
 
86
+ export interface GraphCommitInput {
87
+ id: string;
88
+ parentIds?: readonly string[];
89
+ /**
90
+ * Ref-based color index resolved from the commit's references
91
+ * (0 = current ref, 1 = remote ref, 2 = base ref). When set, it colors
92
+ * this row and propagates down the first-parent chain, mirroring
93
+ * VS Code's scm graph color map.
94
+ */
95
+ colorIndex?: number;
96
+ }
97
+
98
+ /** First color index of the default rotation (`scmGraph.foreground1`). */
99
+ const DEFAULT_COLOR_FIRST = 3;
100
+ /** Number of default rotation colors (`scmGraph.foreground1-5`). */
101
+ const DEFAULT_COLOR_COUNT = 5;
102
+
79
103
  /**
80
104
  * Compute graph rows for an ordered list of commits (topological order,
81
105
  * newest first). Each commit must supply its own `id` and `parentIds`.
@@ -84,14 +108,22 @@ interface MutableGraphRow {
84
108
  * @returns One `GraphRow` per commit in the same order.
85
109
  */
86
110
  export function computeGraphRows(
87
- commits: ReadonlyArray<{ id: string; parentIds?: readonly string[] }>
111
+ commits: ReadonlyArray<GraphCommitInput>
88
112
  ): GraphRow[] {
89
113
  // lanes[i] = id of commit that "owns" lane i (i.e. we are waiting for this
90
114
  // commit to appear in the list so we can close the lane).
91
115
  const lanes: (string | undefined)[] = [];
92
- // laneColors[i] = the color index permanently assigned to lane i
116
+ // laneColors[i] = the color index currently assigned to lane i
93
117
  const laneColors: (number | undefined)[] = [];
94
118
 
119
+ // Default lane colors rotate through foreground1-5, like VS Code's
120
+ // color registry; indices 0-2 are reserved for ref-based colors.
121
+ let rotation = -1;
122
+ const nextDefaultColor = (): number => {
123
+ rotation = (rotation + 1) % DEFAULT_COLOR_COUNT;
124
+ return DEFAULT_COLOR_FIRST + rotation;
125
+ };
126
+
95
127
  const rows: MutableGraphRow[] = [];
96
128
 
97
129
  for (const commit of commits) {
@@ -106,10 +138,15 @@ export function computeGraphRows(
106
138
  // Not yet tracked → open a new lane
107
139
  myLane = firstFreeLane(lanes);
108
140
  lanes[myLane] = commit.id;
109
- laneColors[myLane] = myLane % 8;
141
+ laneColors[myLane] = commit.colorIndex ?? nextDefaultColor();
110
142
  }
111
143
 
112
- const myColor = laneColors[myLane] ?? myLane % 8;
144
+ // The segment above the commit keeps the color inherited from the
145
+ // chain above; the commit's own ref color (if any) takes over from
146
+ // this row downward.
147
+ const topColor = laneColors[myLane] ?? DEFAULT_COLOR_FIRST;
148
+ const myColor = commit.colorIndex ?? topColor;
149
+ laneColors[myLane] = myColor;
113
150
 
114
151
  // Collect any duplicate lane occupants: other lanes that were kept
115
152
  // alive pointing at this same commit (sibling branch tips whose lane
@@ -120,7 +157,7 @@ export function computeGraphRows(
120
157
  if (hasTopLine) {
121
158
  for (let li = 0; li < lanes.length; li++) {
122
159
  if (lanes[li] === commit.id && li !== myLane) {
123
- duplicateLanes.push({ lane: li, color: laneColors[li] ?? li % 8 });
160
+ duplicateLanes.push({ lane: li, color: laneColors[li] ?? DEFAULT_COLOR_FIRST });
124
161
  lanes[li] = undefined;
125
162
  laneColors[li] = undefined;
126
163
  }
@@ -170,7 +207,7 @@ export function computeGraphRows(
170
207
  // Additional parents get new lanes — branch-out
171
208
  const newLane = firstFreeLane(lanes);
172
209
  lanes[newLane] = pid;
173
- laneColors[newLane] = newLane % 8;
210
+ laneColors[newLane] = nextDefaultColor();
174
211
  parentLanes.push(newLane);
175
212
  parentIsExisting.push(false);
176
213
  }
@@ -206,7 +243,7 @@ export function computeGraphRows(
206
243
  if (!occupant || occupant === commit.id) {
207
244
  continue;
208
245
  }
209
- const color = laneColors[li] ?? li % 8;
246
+ const color = laneColors[li] ?? DEFAULT_COLOR_FIRST;
210
247
  edges.push({ fromLane: li, toLane: li, color, type: 'pass-through' });
211
248
  }
212
249
 
@@ -225,11 +262,11 @@ export function computeGraphRows(
225
262
  if (isExisting) {
226
263
  // Merge-in: an existing lane at the top of the row curves into
227
264
  // the commit position at mid-row.
228
- const color = laneColors[toLane] ?? toLane % 8;
265
+ const color = laneColors[toLane] ?? DEFAULT_COLOR_FIRST;
229
266
  edges.push({ fromLane: toLane, toLane: myLane, color, type: 'merge-in' });
230
267
  } else {
231
268
  // Branch-out: the commit spawns a new lane below mid-row.
232
- const color = laneColors[toLane] ?? toLane % 8;
269
+ const color = laneColors[toLane] ?? DEFAULT_COLOR_FIRST;
233
270
  edges.push({ fromLane: myLane, toLane, color, type: 'branch-out' });
234
271
  }
235
272
  }
@@ -245,7 +282,7 @@ export function computeGraphRows(
245
282
  // at the parent) so it persists as a pass-through to the parent row.
246
283
  const hasContinuation = parentIds.length > 0 && (parentLanes[0] === myLane || lanes[myLane] === parentIds[0]);
247
284
 
248
- rows.push({ lane: myLane, color: myColor, edges, hasContinuation, hasTopLine });
285
+ rows.push({ lane: myLane, color: myColor, topColor, edges, hasContinuation, hasTopLine });
249
286
  }
250
287
 
251
288
  return rows;