@theia/scm 1.64.0-next.28 → 1.64.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 (125) hide show
  1. package/lib/browser/decorations/scm-decorations-service.d.ts.map +1 -1
  2. package/lib/browser/decorations/scm-decorations-service.js +19 -1
  3. package/lib/browser/decorations/scm-decorations-service.js.map +1 -1
  4. package/lib/browser/merge-editor/merge-editor-contribution.d.ts +34 -0
  5. package/lib/browser/merge-editor/merge-editor-contribution.d.ts.map +1 -0
  6. package/lib/browser/merge-editor/merge-editor-contribution.js +335 -0
  7. package/lib/browser/merge-editor/merge-editor-contribution.js.map +1 -0
  8. package/lib/browser/merge-editor/merge-editor-dev-contribution.d.ts +31 -0
  9. package/lib/browser/merge-editor/merge-editor-dev-contribution.d.ts.map +1 -0
  10. package/lib/browser/merge-editor/merge-editor-dev-contribution.js +151 -0
  11. package/lib/browser/merge-editor/merge-editor-dev-contribution.js.map +1 -0
  12. package/lib/browser/merge-editor/merge-editor-module.d.ts +24 -0
  13. package/lib/browser/merge-editor/merge-editor-module.d.ts.map +1 -0
  14. package/lib/browser/merge-editor/merge-editor-module.js +109 -0
  15. package/lib/browser/merge-editor/merge-editor-module.js.map +1 -0
  16. package/lib/browser/merge-editor/merge-editor.d.ts +122 -0
  17. package/lib/browser/merge-editor/merge-editor.d.ts.map +1 -0
  18. package/lib/browser/merge-editor/merge-editor.js +560 -0
  19. package/lib/browser/merge-editor/merge-editor.js.map +1 -0
  20. package/lib/browser/merge-editor/model/line-range.d.ts +37 -0
  21. package/lib/browser/merge-editor/model/line-range.d.ts.map +1 -0
  22. package/lib/browser/merge-editor/model/line-range.js +111 -0
  23. package/lib/browser/merge-editor/model/line-range.js.map +1 -0
  24. package/lib/browser/merge-editor/model/live-diff.d.ts +26 -0
  25. package/lib/browser/merge-editor/model/live-diff.d.ts.map +1 -0
  26. package/lib/browser/merge-editor/model/live-diff.js +85 -0
  27. package/lib/browser/merge-editor/model/live-diff.js.map +1 -0
  28. package/lib/browser/merge-editor/model/merge-editor-model.d.ts +116 -0
  29. package/lib/browser/merge-editor/model/merge-editor-model.d.ts.map +1 -0
  30. package/lib/browser/merge-editor/model/merge-editor-model.js +507 -0
  31. package/lib/browser/merge-editor/model/merge-editor-model.js.map +1 -0
  32. package/lib/browser/merge-editor/model/merge-range.d.ts +50 -0
  33. package/lib/browser/merge-editor/model/merge-range.d.ts.map +1 -0
  34. package/lib/browser/merge-editor/model/merge-range.js +215 -0
  35. package/lib/browser/merge-editor/model/merge-range.js.map +1 -0
  36. package/lib/browser/merge-editor/model/range-editing.d.ts +21 -0
  37. package/lib/browser/merge-editor/model/range-editing.d.ts.map +1 -0
  38. package/lib/browser/merge-editor/model/range-editing.js +68 -0
  39. package/lib/browser/merge-editor/model/range-editing.js.map +1 -0
  40. package/lib/browser/merge-editor/model/range-mapping.d.ts +106 -0
  41. package/lib/browser/merge-editor/model/range-mapping.d.ts.map +1 -0
  42. package/lib/browser/merge-editor/model/range-mapping.js +252 -0
  43. package/lib/browser/merge-editor/model/range-mapping.js.map +1 -0
  44. package/lib/browser/merge-editor/model/range-mapping.spec.d.ts +2 -0
  45. package/lib/browser/merge-editor/model/range-mapping.spec.d.ts.map +1 -0
  46. package/lib/browser/merge-editor/model/range-mapping.spec.js +48 -0
  47. package/lib/browser/merge-editor/model/range-mapping.spec.js.map +1 -0
  48. package/lib/browser/merge-editor/model/range-utils.d.ts +25 -0
  49. package/lib/browser/merge-editor/model/range-utils.d.ts.map +1 -0
  50. package/lib/browser/merge-editor/model/range-utils.js +118 -0
  51. package/lib/browser/merge-editor/model/range-utils.js.map +1 -0
  52. package/lib/browser/merge-editor/view/diff-spacers.d.ts +50 -0
  53. package/lib/browser/merge-editor/view/diff-spacers.d.ts.map +1 -0
  54. package/lib/browser/merge-editor/view/diff-spacers.js +133 -0
  55. package/lib/browser/merge-editor/view/diff-spacers.js.map +1 -0
  56. package/lib/browser/merge-editor/view/merge-editor-panes/index.d.ts +6 -0
  57. package/lib/browser/merge-editor/view/merge-editor-panes/index.d.ts.map +1 -0
  58. package/lib/browser/merge-editor/view/merge-editor-panes/index.js +24 -0
  59. package/lib/browser/merge-editor/view/merge-editor-panes/index.js.map +1 -0
  60. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.d.ts +12 -0
  61. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.d.ts.map +1 -0
  62. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.js +65 -0
  63. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.js.map +1 -0
  64. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.d.ts +30 -0
  65. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.d.ts.map +1 -0
  66. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js +102 -0
  67. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js.map +1 -0
  68. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.d.ts +49 -0
  69. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.d.ts.map +1 -0
  70. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.js +214 -0
  71. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.js.map +1 -0
  72. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.d.ts +16 -0
  73. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.d.ts.map +1 -0
  74. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.js +107 -0
  75. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.js.map +1 -0
  76. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.d.ts +27 -0
  77. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.d.ts.map +1 -0
  78. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.js +135 -0
  79. package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.js.map +1 -0
  80. package/lib/browser/merge-editor/view/merge-editor-scroll-sync.d.ts +20 -0
  81. package/lib/browser/merge-editor/view/merge-editor-scroll-sync.d.ts.map +1 -0
  82. package/lib/browser/merge-editor/view/merge-editor-scroll-sync.js +218 -0
  83. package/lib/browser/merge-editor/view/merge-editor-scroll-sync.js.map +1 -0
  84. package/lib/browser/merge-editor/view/merge-editor-view-zones.d.ts +57 -0
  85. package/lib/browser/merge-editor/view/merge-editor-view-zones.d.ts.map +1 -0
  86. package/lib/browser/merge-editor/view/merge-editor-view-zones.js +218 -0
  87. package/lib/browser/merge-editor/view/merge-editor-view-zones.js.map +1 -0
  88. package/lib/browser/merge-editor/view/merge-range-actions.d.ts +23 -0
  89. package/lib/browser/merge-editor/view/merge-range-actions.d.ts.map +1 -0
  90. package/lib/browser/merge-editor/view/merge-range-actions.js +142 -0
  91. package/lib/browser/merge-editor/view/merge-range-actions.js.map +1 -0
  92. package/lib/browser/scm-colors.d.ts +2 -0
  93. package/lib/browser/scm-colors.d.ts.map +1 -1
  94. package/lib/browser/scm-colors.js +2 -0
  95. package/lib/browser/scm-colors.js.map +1 -1
  96. package/lib/browser/scm-frontend-module.d.ts.map +1 -1
  97. package/lib/browser/scm-frontend-module.js +2 -0
  98. package/lib/browser/scm-frontend-module.js.map +1 -1
  99. package/package.json +7 -7
  100. package/src/browser/decorations/scm-decorations-service.ts +18 -1
  101. package/src/browser/merge-editor/merge-editor-contribution.ts +346 -0
  102. package/src/browser/merge-editor/merge-editor-dev-contribution.ts +154 -0
  103. package/src/browser/merge-editor/merge-editor-module.ts +134 -0
  104. package/src/browser/merge-editor/merge-editor.ts +643 -0
  105. package/src/browser/merge-editor/model/line-range.ts +128 -0
  106. package/src/browser/merge-editor/model/live-diff.ts +111 -0
  107. package/src/browser/merge-editor/model/merge-editor-model.ts +623 -0
  108. package/src/browser/merge-editor/model/merge-range.ts +268 -0
  109. package/src/browser/merge-editor/model/range-editing.ts +81 -0
  110. package/src/browser/merge-editor/model/range-mapping.spec.ts +52 -0
  111. package/src/browser/merge-editor/model/range-mapping.ts +396 -0
  112. package/src/browser/merge-editor/model/range-utils.ts +115 -0
  113. package/src/browser/merge-editor/view/diff-spacers.ts +160 -0
  114. package/src/browser/merge-editor/view/merge-editor-panes/index.ts +21 -0
  115. package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.ts +71 -0
  116. package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.tsx +106 -0
  117. package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.ts +246 -0
  118. package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.ts +115 -0
  119. package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.ts +139 -0
  120. package/src/browser/merge-editor/view/merge-editor-scroll-sync.ts +241 -0
  121. package/src/browser/merge-editor/view/merge-editor-view-zones.ts +264 -0
  122. package/src/browser/merge-editor/view/merge-range-actions.ts +159 -0
  123. package/src/browser/scm-colors.ts +2 -0
  124. package/src/browser/scm-frontend-module.ts +4 -0
  125. package/src/browser/style/merge-editor.css +221 -0
@@ -0,0 +1,268 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 1C-Soft LLC and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /*---------------------------------------------------------------------------------------------
17
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+ // copied and modified from https://github.com/microsoft/vscode/blob/1.96.3/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts
21
+
22
+ import { ArrayUtils } from '@theia/core';
23
+ import { uinteger, Position, Range } from '@theia/core/shared/vscode-languageserver-protocol';
24
+ import { TextEditorDocument } from '@theia/editor/lib/browser/editor';
25
+ import { DetailedLineRangeMapping, MappingAlignment } from './range-mapping';
26
+ import { LineRange } from './line-range';
27
+ import { LineRangeEdit, RangeEdit } from './range-editing';
28
+ import { PositionUtils, RangeUtils } from './range-utils';
29
+
30
+ /**
31
+ * Describes modifications in side 1 and side 2 for a specific range in base.
32
+ */
33
+ export class MergeRange {
34
+
35
+ static computeMergeRanges(
36
+ side1Diff: readonly DetailedLineRangeMapping[],
37
+ side2Diff: readonly DetailedLineRangeMapping[],
38
+ baseDocument: TextEditorDocument,
39
+ side1Document: TextEditorDocument,
40
+ side2Document: TextEditorDocument
41
+ ): MergeRange[] {
42
+ const alignments = MappingAlignment.computeAlignments(side1Diff, side2Diff);
43
+ return alignments.map(
44
+ alignment => new MergeRange(
45
+ alignment.baseRange,
46
+ baseDocument,
47
+ alignment.side1Range,
48
+ alignment.side1Mappings,
49
+ side1Document,
50
+ alignment.side2Range,
51
+ alignment.side2Mappings,
52
+ side2Document
53
+ )
54
+ );
55
+ }
56
+
57
+ readonly side1CombinedChange = DetailedLineRangeMapping.join(this.side1Changes);
58
+ readonly side2CombinedChange = DetailedLineRangeMapping.join(this.side2Changes);
59
+ readonly isEqualChange = ArrayUtils.equals(this.side1Changes, this.side2Changes, (a, b) => a.getLineEdit().equals(b.getLineEdit()));
60
+
61
+ constructor(
62
+ readonly baseRange: LineRange,
63
+ readonly baseDocument: TextEditorDocument,
64
+ readonly side1Range: LineRange,
65
+ readonly side1Changes: readonly DetailedLineRangeMapping[],
66
+ readonly side1Document: TextEditorDocument,
67
+ readonly side2Range: LineRange,
68
+ readonly side2Changes: readonly DetailedLineRangeMapping[],
69
+ readonly side2Document: TextEditorDocument
70
+ ) {
71
+ if (side1Changes.length === 0 && side2Changes.length === 0) {
72
+ throw new Error('At least one change is expected');
73
+ }
74
+ }
75
+
76
+ getModifiedRange(side: MergeSide): LineRange {
77
+ return side === 1 ? this.side1Range : this.side2Range;
78
+ }
79
+
80
+ getCombinedChange(side: MergeSide): DetailedLineRangeMapping | undefined {
81
+ return side === 1 ? this.side1CombinedChange : this.side2CombinedChange;
82
+ }
83
+
84
+ getChanges(side: MergeSide): readonly DetailedLineRangeMapping[] {
85
+ return side === 1 ? this.side1Changes : this.side2Changes;
86
+ }
87
+
88
+ get isConflicting(): boolean {
89
+ return this.side1Changes.length > 0 && this.side2Changes.length > 0 && !this.isEqualChange;
90
+ }
91
+
92
+ canBeSmartCombined(firstSide: MergeSide): boolean {
93
+ return this.isConflicting && this.smartCombineChanges(firstSide) !== undefined;
94
+ }
95
+
96
+ get isSmartCombinationOrderRelevant(): boolean {
97
+ const edit1 = this.smartCombineChanges(1);
98
+ const edit2 = this.smartCombineChanges(2);
99
+ if (!edit1 || !edit2) {
100
+ return false;
101
+ }
102
+ return !edit1.equals(edit2);
103
+ }
104
+
105
+ getBaseRangeEdit(state: MergeRangeAcceptedState): LineRangeEdit {
106
+ if (state === 'Base') {
107
+ return new LineRangeEdit(this.baseRange, this.baseRange.getLines(this.baseDocument));
108
+ }
109
+ if (state === 'Side1') {
110
+ return new LineRangeEdit(this.baseRange, this.side1Range.getLines(this.side1Document));
111
+ }
112
+ if (state === 'Side2') {
113
+ return new LineRangeEdit(this.baseRange, this.side2Range.getLines(this.side2Document));
114
+ }
115
+
116
+ let edit: LineRangeEdit | undefined;
117
+ const firstSide = state.startsWith('Side1') ? 1 : 2;
118
+ if (state.endsWith('Smart')) {
119
+ edit = this.smartCombineChanges(firstSide);
120
+ }
121
+ if (!edit) {
122
+ edit = this.dumbCombineChanges(firstSide);
123
+ }
124
+ return edit;
125
+ }
126
+
127
+ protected smartCombinationEdit1?: { value: LineRangeEdit | undefined };
128
+ protected smartCombinationEdit2?: { value: LineRangeEdit | undefined };
129
+
130
+ protected smartCombineChanges(firstSide: MergeSide): LineRangeEdit | undefined {
131
+ if (firstSide === 1 && this.smartCombinationEdit1) {
132
+ return this.smartCombinationEdit1.value;
133
+ } else if (firstSide === 2 && this.smartCombinationEdit2) {
134
+ return this.smartCombinationEdit2.value;
135
+ }
136
+
137
+ const combinedChanges =
138
+ this.side1Changes.flatMap(change => change.rangeMappings.map(rangeMapping => ({ rangeMapping, side: 1 }))).concat(
139
+ this.side2Changes.flatMap(change => change.rangeMappings.map(rangeMapping => ({ rangeMapping, side: 2 })))).sort(
140
+ (a, b) => {
141
+ let result = RangeUtils.compareUsingStarts(a.rangeMapping.originalRange, b.rangeMapping.originalRange);
142
+ if (result === 0) {
143
+ const sideWeight = (side: number) => side === firstSide ? 1 : 2;
144
+ result = sideWeight(a.side) - sideWeight(b.side);
145
+ }
146
+ return result;
147
+ }
148
+ );
149
+
150
+ const sortedEdits = combinedChanges.map(change => {
151
+ const modifiedDocument = change.side === 1 ? this.side1Document : this.side2Document;
152
+ return new RangeEdit(change.rangeMapping.originalRange, modifiedDocument.getText(change.rangeMapping.modifiedRange));
153
+ });
154
+
155
+ const edit = this.editsToLineRangeEdit(this.baseRange, sortedEdits, this.baseDocument);
156
+ if (firstSide === 1) {
157
+ this.smartCombinationEdit1 = { value: edit };
158
+ } else {
159
+ this.smartCombinationEdit2 = { value: edit };
160
+ }
161
+ return edit;
162
+ }
163
+
164
+ protected editsToLineRangeEdit(range: LineRange, sortedEdits: RangeEdit[], document: TextEditorDocument): LineRangeEdit | undefined {
165
+ let text = '';
166
+ const startsLineBefore = range.startLineNumber > 0;
167
+ let currentPosition = startsLineBefore
168
+ ? Position.create(
169
+ range.startLineNumber - 1,
170
+ document.getLineMaxColumn((range.startLineNumber - 1) + 1) // note that getLineMaxColumn expects a 1-based line number
171
+ )
172
+ : Position.create(range.startLineNumber, 0);
173
+
174
+ for (const edit of sortedEdits) {
175
+ const diffStart = edit.range.start;
176
+ if (!PositionUtils.isBeforeOrEqual(currentPosition, diffStart)) {
177
+ return undefined;
178
+ }
179
+ let originalText = document.getText(Range.create(currentPosition, diffStart));
180
+ if (diffStart.line >= document.lineCount) {
181
+ // getText doesn't include this virtual line break, as the document ends the line before.
182
+ // endsLineAfter will be false.
183
+ originalText += '\n';
184
+ }
185
+ text += originalText;
186
+ text += edit.newText;
187
+ currentPosition = edit.range.end;
188
+ }
189
+
190
+ const endsLineAfter = range.endLineNumberExclusive < document.lineCount;
191
+ const end = endsLineAfter ?
192
+ Position.create(range.endLineNumberExclusive, 0) :
193
+ Position.create(range.endLineNumberExclusive - 1, uinteger.MAX_VALUE);
194
+
195
+ text += document.getText(Range.create(currentPosition, end));
196
+
197
+ const lines = text.split(/\r\n|\r|\n/);
198
+ if (startsLineBefore) {
199
+ if (lines[0] !== '') {
200
+ return undefined;
201
+ }
202
+ lines.shift();
203
+ }
204
+ if (endsLineAfter) {
205
+ if (lines[lines.length - 1] !== '') {
206
+ return undefined;
207
+ }
208
+ lines.pop();
209
+ }
210
+ return new LineRangeEdit(range, lines);
211
+ }
212
+
213
+ protected dumbCombinationEdit1?: LineRangeEdit;
214
+ protected dumbCombinationEdit2?: LineRangeEdit;
215
+
216
+ protected dumbCombineChanges(firstSide: MergeSide): LineRangeEdit {
217
+ if (firstSide === 1 && this.dumbCombinationEdit1) {
218
+ return this.dumbCombinationEdit1;
219
+ } else if (firstSide === 2 && this.dumbCombinationEdit2) {
220
+ return this.dumbCombinationEdit2;
221
+ }
222
+
223
+ const modifiedLines1 = this.side1Range.getLines(this.side1Document);
224
+ const modifiedLines2 = this.side2Range.getLines(this.side2Document);
225
+ const combinedLines = firstSide === 1 ? modifiedLines1.concat(modifiedLines2) : modifiedLines2.concat(modifiedLines1);
226
+
227
+ const edit = new LineRangeEdit(this.baseRange, combinedLines);
228
+ if (firstSide === 1) {
229
+ this.dumbCombinationEdit1 = edit;
230
+ } else {
231
+ this.dumbCombinationEdit2 = edit;
232
+ }
233
+ return edit;
234
+ }
235
+ }
236
+
237
+ export type MergeSide = 1 | 2;
238
+
239
+ export type MergeRangeAcceptedState = 'Base' | 'Side1' | 'Side2' | 'Side1Side2' | 'Side2Side1' | 'Side1Side2Smart' | 'Side2Side1Smart';
240
+
241
+ export namespace MergeRangeAcceptedState {
242
+
243
+ export function addSide(state: MergeRangeAcceptedState, side: MergeSide, options?: { smartCombination?: boolean }): MergeRangeAcceptedState {
244
+ if (state === 'Base') {
245
+ return side === 1 ? 'Side1' : 'Side2';
246
+ }
247
+ if (state.includes('Side' + side)) {
248
+ return state;
249
+ }
250
+ if (side === 2) {
251
+ return options?.smartCombination ? 'Side1Side2Smart' : 'Side1Side2';
252
+ } else {
253
+ return options?.smartCombination ? 'Side2Side1Smart' : 'Side2Side1';
254
+ }
255
+ }
256
+
257
+ export function removeSide(state: MergeRangeAcceptedState, side: MergeSide): MergeRangeAcceptedState {
258
+ if (!state.includes('Side' + side)) {
259
+ return state;
260
+ }
261
+ if (state === 'Side' + side) {
262
+ return 'Base';
263
+ }
264
+ return side === 1 ? 'Side2' : 'Side1';
265
+ }
266
+ }
267
+
268
+ export type MergeRangeResultState = MergeRangeAcceptedState | 'Unrecognized';
@@ -0,0 +1,81 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 1C-Soft LLC and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /*---------------------------------------------------------------------------------------------
17
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+ // copied and modified from https://github.com/microsoft/vscode/blob/1.96.3/src/vs/workbench/contrib/mergeEditor/browser/model/editing.ts
21
+
22
+ import { ArrayUtils } from '@theia/core';
23
+ import { Range, uinteger } from '@theia/core/shared/vscode-languageserver-protocol';
24
+ import { LineRange } from './line-range';
25
+ import * as monaco from '@theia/monaco-editor-core';
26
+
27
+ /**
28
+ * Represents an edit, expressed in whole lines:
29
+ * At (before) {@link LineRange.startLineNumber}, delete {@link LineRange.lineCount} many lines and insert {@link newLines}.
30
+ */
31
+ export class LineRangeEdit {
32
+ constructor(
33
+ readonly range: LineRange,
34
+ readonly newLines: string[]
35
+ ) { }
36
+
37
+ equals(other: LineRangeEdit): boolean {
38
+ return this.range.equals(other.range) && ArrayUtils.equals(this.newLines, other.newLines);
39
+ }
40
+
41
+ toRangeEdit(documentLineCount: number): RangeEdit {
42
+ if (this.range.endLineNumberExclusive < documentLineCount) {
43
+ return new RangeEdit(
44
+ Range.create(this.range.startLineNumber, 0, this.range.endLineNumberExclusive, 0),
45
+ this.newLines.map(s => s + '\n').join('')
46
+ );
47
+ }
48
+
49
+ if (this.range.startLineNumber === 0) {
50
+ return new RangeEdit(
51
+ Range.create(0, 0, documentLineCount - 1, uinteger.MAX_VALUE),
52
+ this.newLines.join('\n')
53
+ );
54
+ }
55
+
56
+ return new RangeEdit(
57
+ Range.create(this.range.startLineNumber - 1, uinteger.MAX_VALUE, documentLineCount - 1, uinteger.MAX_VALUE),
58
+ this.newLines.map(s => '\n' + s).join('')
59
+ );
60
+ }
61
+ }
62
+
63
+ export class RangeEdit {
64
+ constructor(
65
+ readonly range: Range,
66
+ readonly newText: string
67
+ ) { }
68
+
69
+ toMonacoEdit(): monaco.editor.ISingleEditOperation {
70
+ const { start, end } = this.range;
71
+ return {
72
+ range: {
73
+ startLineNumber: start.line + 1,
74
+ startColumn: start.character + 1,
75
+ endLineNumber: end.line + 1,
76
+ endColumn: end.character + 1
77
+ },
78
+ text: this.newText
79
+ };
80
+ }
81
+ }
@@ -0,0 +1,52 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 1C-Soft LLC and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /*---------------------------------------------------------------------------------------------
17
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+ // copied and modified from https://github.com/microsoft/vscode/blob/1.96.3/src/vs/workbench/contrib/mergeEditor/test/browser/mapping.test.ts
21
+
22
+ import { expect } from 'chai';
23
+ import { Range } from '@theia/core/shared/vscode-languageserver-protocol';
24
+ import { DocumentRangeMap, RangeMapping } from './range-mapping';
25
+
26
+ describe('document-range-map', () => {
27
+
28
+ it('project', () => {
29
+ const documentRangeMap = new DocumentRangeMap([
30
+ new RangeMapping(Range.create(2, 4, 2, 6), Range.create(2, 4, 2, 7)),
31
+ new RangeMapping(Range.create(3, 2, 4, 3), Range.create(3, 2, 6, 4)),
32
+ new RangeMapping(Range.create(4, 5, 4, 7), Range.create(6, 6, 6, 9)),
33
+ ]);
34
+
35
+ const project = (line: number, character: number) =>
36
+ documentRangeMap.projectPosition({ line, character }).toString();
37
+
38
+ expect(project(1, 1)).to.be.equal('[1:1, 1:1) -> [1:1, 1:1)');
39
+ expect(project(2, 3)).to.be.equal('[2:3, 2:3) -> [2:3, 2:3)');
40
+ expect(project(2, 4)).to.be.equal('[2:4, 2:6) -> [2:4, 2:7)');
41
+ expect(project(2, 5)).to.be.equal('[2:4, 2:6) -> [2:4, 2:7)');
42
+ expect(project(2, 6)).to.be.equal('[2:6, 2:6) -> [2:7, 2:7)');
43
+ expect(project(2, 7)).to.be.equal('[2:7, 2:7) -> [2:8, 2:8)');
44
+ expect(project(3, 1)).to.be.equal('[3:1, 3:1) -> [3:1, 3:1)');
45
+ expect(project(3, 2)).to.be.equal('[3:2, 4:3) -> [3:2, 6:4)');
46
+ expect(project(4, 2)).to.be.equal('[3:2, 4:3) -> [3:2, 6:4)');
47
+ expect(project(4, 3)).to.be.equal('[4:3, 4:3) -> [6:4, 6:4)');
48
+ expect(project(4, 4)).to.be.equal('[4:4, 4:4) -> [6:5, 6:5)');
49
+ expect(project(4, 5)).to.be.equal('[4:5, 4:7) -> [6:6, 6:9)');
50
+ });
51
+
52
+ });