@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.
- package/lib/browser/decorations/scm-decorations-service.d.ts.map +1 -1
- package/lib/browser/decorations/scm-decorations-service.js +19 -1
- package/lib/browser/decorations/scm-decorations-service.js.map +1 -1
- package/lib/browser/merge-editor/merge-editor-contribution.d.ts +34 -0
- package/lib/browser/merge-editor/merge-editor-contribution.d.ts.map +1 -0
- package/lib/browser/merge-editor/merge-editor-contribution.js +335 -0
- package/lib/browser/merge-editor/merge-editor-contribution.js.map +1 -0
- package/lib/browser/merge-editor/merge-editor-dev-contribution.d.ts +31 -0
- package/lib/browser/merge-editor/merge-editor-dev-contribution.d.ts.map +1 -0
- package/lib/browser/merge-editor/merge-editor-dev-contribution.js +151 -0
- package/lib/browser/merge-editor/merge-editor-dev-contribution.js.map +1 -0
- package/lib/browser/merge-editor/merge-editor-module.d.ts +24 -0
- package/lib/browser/merge-editor/merge-editor-module.d.ts.map +1 -0
- package/lib/browser/merge-editor/merge-editor-module.js +109 -0
- package/lib/browser/merge-editor/merge-editor-module.js.map +1 -0
- package/lib/browser/merge-editor/merge-editor.d.ts +122 -0
- package/lib/browser/merge-editor/merge-editor.d.ts.map +1 -0
- package/lib/browser/merge-editor/merge-editor.js +560 -0
- package/lib/browser/merge-editor/merge-editor.js.map +1 -0
- package/lib/browser/merge-editor/model/line-range.d.ts +37 -0
- package/lib/browser/merge-editor/model/line-range.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/line-range.js +111 -0
- package/lib/browser/merge-editor/model/line-range.js.map +1 -0
- package/lib/browser/merge-editor/model/live-diff.d.ts +26 -0
- package/lib/browser/merge-editor/model/live-diff.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/live-diff.js +85 -0
- package/lib/browser/merge-editor/model/live-diff.js.map +1 -0
- package/lib/browser/merge-editor/model/merge-editor-model.d.ts +116 -0
- package/lib/browser/merge-editor/model/merge-editor-model.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/merge-editor-model.js +507 -0
- package/lib/browser/merge-editor/model/merge-editor-model.js.map +1 -0
- package/lib/browser/merge-editor/model/merge-range.d.ts +50 -0
- package/lib/browser/merge-editor/model/merge-range.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/merge-range.js +215 -0
- package/lib/browser/merge-editor/model/merge-range.js.map +1 -0
- package/lib/browser/merge-editor/model/range-editing.d.ts +21 -0
- package/lib/browser/merge-editor/model/range-editing.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/range-editing.js +68 -0
- package/lib/browser/merge-editor/model/range-editing.js.map +1 -0
- package/lib/browser/merge-editor/model/range-mapping.d.ts +106 -0
- package/lib/browser/merge-editor/model/range-mapping.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/range-mapping.js +252 -0
- package/lib/browser/merge-editor/model/range-mapping.js.map +1 -0
- package/lib/browser/merge-editor/model/range-mapping.spec.d.ts +2 -0
- package/lib/browser/merge-editor/model/range-mapping.spec.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/range-mapping.spec.js +48 -0
- package/lib/browser/merge-editor/model/range-mapping.spec.js.map +1 -0
- package/lib/browser/merge-editor/model/range-utils.d.ts +25 -0
- package/lib/browser/merge-editor/model/range-utils.d.ts.map +1 -0
- package/lib/browser/merge-editor/model/range-utils.js +118 -0
- package/lib/browser/merge-editor/model/range-utils.js.map +1 -0
- package/lib/browser/merge-editor/view/diff-spacers.d.ts +50 -0
- package/lib/browser/merge-editor/view/diff-spacers.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/diff-spacers.js +133 -0
- package/lib/browser/merge-editor/view/diff-spacers.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/index.d.ts +6 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/index.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/index.js +24 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/index.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.d.ts +12 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.js +65 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.d.ts +30 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js +102 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.d.ts +49 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.js +214 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.d.ts +16 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.js +107 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.d.ts +27 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.js +135 -0
- package/lib/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-scroll-sync.d.ts +20 -0
- package/lib/browser/merge-editor/view/merge-editor-scroll-sync.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-scroll-sync.js +218 -0
- package/lib/browser/merge-editor/view/merge-editor-scroll-sync.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-view-zones.d.ts +57 -0
- package/lib/browser/merge-editor/view/merge-editor-view-zones.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-editor-view-zones.js +218 -0
- package/lib/browser/merge-editor/view/merge-editor-view-zones.js.map +1 -0
- package/lib/browser/merge-editor/view/merge-range-actions.d.ts +23 -0
- package/lib/browser/merge-editor/view/merge-range-actions.d.ts.map +1 -0
- package/lib/browser/merge-editor/view/merge-range-actions.js +142 -0
- package/lib/browser/merge-editor/view/merge-range-actions.js.map +1 -0
- package/lib/browser/scm-colors.d.ts +2 -0
- package/lib/browser/scm-colors.d.ts.map +1 -1
- package/lib/browser/scm-colors.js +2 -0
- package/lib/browser/scm-colors.js.map +1 -1
- package/lib/browser/scm-frontend-module.d.ts.map +1 -1
- package/lib/browser/scm-frontend-module.js +2 -0
- package/lib/browser/scm-frontend-module.js.map +1 -1
- package/package.json +7 -7
- package/src/browser/decorations/scm-decorations-service.ts +18 -1
- package/src/browser/merge-editor/merge-editor-contribution.ts +346 -0
- package/src/browser/merge-editor/merge-editor-dev-contribution.ts +154 -0
- package/src/browser/merge-editor/merge-editor-module.ts +134 -0
- package/src/browser/merge-editor/merge-editor.ts +643 -0
- package/src/browser/merge-editor/model/line-range.ts +128 -0
- package/src/browser/merge-editor/model/live-diff.ts +111 -0
- package/src/browser/merge-editor/model/merge-editor-model.ts +623 -0
- package/src/browser/merge-editor/model/merge-range.ts +268 -0
- package/src/browser/merge-editor/model/range-editing.ts +81 -0
- package/src/browser/merge-editor/model/range-mapping.spec.ts +52 -0
- package/src/browser/merge-editor/model/range-mapping.ts +396 -0
- package/src/browser/merge-editor/model/range-utils.ts +115 -0
- package/src/browser/merge-editor/view/diff-spacers.ts +160 -0
- package/src/browser/merge-editor/view/merge-editor-panes/index.ts +21 -0
- package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-base-pane.ts +71 -0
- package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-pane-header.tsx +106 -0
- package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-pane.ts +246 -0
- package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-result-pane.ts +115 -0
- package/src/browser/merge-editor/view/merge-editor-panes/merge-editor-side-pane.ts +139 -0
- package/src/browser/merge-editor/view/merge-editor-scroll-sync.ts +241 -0
- package/src/browser/merge-editor/view/merge-editor-view-zones.ts +264 -0
- package/src/browser/merge-editor/view/merge-range-actions.ts +159 -0
- package/src/browser/scm-colors.ts +2 -0
- package/src/browser/scm-frontend-module.ts +4 -0
- package/src/browser/style/merge-editor.css +221 -0
|
@@ -0,0 +1,241 @@
|
|
|
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/view/scrollSynchronizer.ts
|
|
21
|
+
|
|
22
|
+
import { Disposable, DisposableCollection } from '@theia/core';
|
|
23
|
+
import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
|
|
24
|
+
import { MergeEditor } from '../merge-editor';
|
|
25
|
+
import { DocumentLineRangeMap } from '../model/range-mapping';
|
|
26
|
+
|
|
27
|
+
export class MergeEditorScrollSync implements Disposable {
|
|
28
|
+
|
|
29
|
+
protected readonly toDispose = new DisposableCollection();
|
|
30
|
+
protected isSyncing = false;
|
|
31
|
+
|
|
32
|
+
constructor(protected readonly mergeEditor: MergeEditor) {
|
|
33
|
+
const { side1Pane, side2Pane, resultPane, basePane } = mergeEditor;
|
|
34
|
+
|
|
35
|
+
const syncingHandler = <T>(handler: (event: T) => void) => (event: T) => {
|
|
36
|
+
if (this.isSyncing) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.isSyncing = true;
|
|
40
|
+
try {
|
|
41
|
+
handler(event);
|
|
42
|
+
} finally {
|
|
43
|
+
this.isSyncing = false;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
this.toDispose.push(side1Pane.editor.getControl().onDidScrollChange(syncingHandler(event => {
|
|
48
|
+
if (event.scrollTopChanged) {
|
|
49
|
+
this.handleSide1ScrollTopChanged(event.scrollTop);
|
|
50
|
+
}
|
|
51
|
+
if (event.scrollLeftChanged) {
|
|
52
|
+
basePane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
53
|
+
side2Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
54
|
+
resultPane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
55
|
+
}
|
|
56
|
+
})));
|
|
57
|
+
|
|
58
|
+
this.toDispose.push(side2Pane.editor.getControl().onDidScrollChange(syncingHandler(event => {
|
|
59
|
+
if (event.scrollTopChanged) {
|
|
60
|
+
this.handleSide2ScrollTopChanged(event.scrollTop);
|
|
61
|
+
}
|
|
62
|
+
if (event.scrollLeftChanged) {
|
|
63
|
+
basePane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
64
|
+
side1Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
65
|
+
resultPane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
66
|
+
}
|
|
67
|
+
})));
|
|
68
|
+
|
|
69
|
+
this.toDispose.push(resultPane.editor.getControl().onDidScrollChange(syncingHandler(event => {
|
|
70
|
+
if (event.scrollTopChanged) {
|
|
71
|
+
this.handleResultScrollTopChanged(event.scrollTop);
|
|
72
|
+
}
|
|
73
|
+
if (event.scrollLeftChanged) {
|
|
74
|
+
basePane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
75
|
+
side1Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
76
|
+
side2Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
77
|
+
}
|
|
78
|
+
})));
|
|
79
|
+
|
|
80
|
+
this.toDispose.push(basePane.editor.getControl().onDidScrollChange(syncingHandler(event => {
|
|
81
|
+
if (event.scrollTopChanged) {
|
|
82
|
+
this.handleBaseScrollTopChanged(event.scrollTop);
|
|
83
|
+
}
|
|
84
|
+
if (event.scrollLeftChanged) {
|
|
85
|
+
side1Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
86
|
+
side2Pane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
87
|
+
resultPane.editor.getControl().setScrollLeft(event.scrollLeft);
|
|
88
|
+
}
|
|
89
|
+
})));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
dispose(): void {
|
|
93
|
+
this.toDispose.dispose();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
storeScrollState(): unknown {
|
|
97
|
+
return this.mergeEditor.side1Pane.editor.getControl().getScrollTop();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
restoreScrollState(state: unknown): void {
|
|
101
|
+
if (typeof state === 'number') {
|
|
102
|
+
const scrollTop = this.mergeEditor.side1Pane.editor.getControl().getScrollTop();
|
|
103
|
+
if (state !== scrollTop) {
|
|
104
|
+
this.mergeEditor.side1Pane.editor.getControl().setScrollTop(state);
|
|
105
|
+
} else {
|
|
106
|
+
this.update();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
update(): void {
|
|
112
|
+
if (this.isSyncing) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.isSyncing = true;
|
|
116
|
+
try {
|
|
117
|
+
const scrollTop = this.mergeEditor.side1Pane.editor.getControl().getScrollTop();
|
|
118
|
+
this.handleSide1ScrollTopChanged(scrollTop);
|
|
119
|
+
} finally {
|
|
120
|
+
this.isSyncing = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected handleSide1ScrollTopChanged(scrollTop: number): void {
|
|
125
|
+
const { side1Pane, side2Pane, resultPane, basePane, shouldAlignBase, shouldAlignResult, model } = this.mergeEditor;
|
|
126
|
+
|
|
127
|
+
side2Pane.editor.getControl().setScrollTop(scrollTop);
|
|
128
|
+
|
|
129
|
+
if (shouldAlignResult) {
|
|
130
|
+
resultPane.editor.getControl().setScrollTop(scrollTop);
|
|
131
|
+
} else {
|
|
132
|
+
const targetScrollTop = this.computeTargetScrollTop(side1Pane.editor, resultPane.editor, model.side1ToResultLineRangeMap);
|
|
133
|
+
resultPane.editor.getControl().setScrollTop(targetScrollTop);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (shouldAlignBase) {
|
|
137
|
+
basePane.editor.getControl().setScrollTop(scrollTop);
|
|
138
|
+
} else {
|
|
139
|
+
const targetScrollTop = this.computeTargetScrollTop(side1Pane.editor, basePane.editor, model.side1ToBaseLineRangeMap);
|
|
140
|
+
basePane.editor.getControl().setScrollTop(targetScrollTop);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
protected handleSide2ScrollTopChanged(scrollTop: number): void {
|
|
145
|
+
const { side1Pane, side2Pane, resultPane, basePane, shouldAlignBase, shouldAlignResult, model } = this.mergeEditor;
|
|
146
|
+
|
|
147
|
+
side1Pane.editor.getControl().setScrollTop(scrollTop);
|
|
148
|
+
|
|
149
|
+
if (shouldAlignResult) {
|
|
150
|
+
resultPane.editor.getControl().setScrollTop(scrollTop);
|
|
151
|
+
} else {
|
|
152
|
+
const targetScrollTop = this.computeTargetScrollTop(side2Pane.editor, resultPane.editor, model.side2ToResultLineRangeMap);
|
|
153
|
+
resultPane.editor.getControl().setScrollTop(targetScrollTop);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (shouldAlignBase) {
|
|
157
|
+
basePane.editor.getControl().setScrollTop(scrollTop);
|
|
158
|
+
} else {
|
|
159
|
+
const targetScrollTop = this.computeTargetScrollTop(side2Pane.editor, basePane.editor, model.side2ToBaseLineRangeMap);
|
|
160
|
+
basePane.editor.getControl().setScrollTop(targetScrollTop);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
protected handleResultScrollTopChanged(scrollTop: number): void {
|
|
165
|
+
const { side1Pane, side2Pane, resultPane, basePane, shouldAlignBase, shouldAlignResult, model } = this.mergeEditor;
|
|
166
|
+
|
|
167
|
+
if (shouldAlignResult) {
|
|
168
|
+
side1Pane.editor.getControl().setScrollTop(scrollTop);
|
|
169
|
+
side2Pane.editor.getControl().setScrollTop(scrollTop);
|
|
170
|
+
} else {
|
|
171
|
+
const targetScrollTop = this.computeTargetScrollTop(resultPane.editor, side1Pane.editor, model.resultToSide1LineRangeMap);
|
|
172
|
+
side1Pane.editor.getControl().setScrollTop(targetScrollTop);
|
|
173
|
+
side2Pane.editor.getControl().setScrollTop(targetScrollTop);
|
|
174
|
+
if (shouldAlignBase) {
|
|
175
|
+
basePane.editor.getControl().setScrollTop(targetScrollTop);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!shouldAlignBase) {
|
|
180
|
+
const targetScrollTop = this.computeTargetScrollTop(resultPane.editor, basePane.editor, model.resultToBaseLineRangeMap);
|
|
181
|
+
basePane.editor.getControl().setScrollTop(targetScrollTop);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
protected handleBaseScrollTopChanged(scrollTop: number): void {
|
|
186
|
+
const { side1Pane, side2Pane, resultPane, basePane, shouldAlignBase, shouldAlignResult, model } = this.mergeEditor;
|
|
187
|
+
|
|
188
|
+
if (shouldAlignBase) {
|
|
189
|
+
side1Pane.editor.getControl().setScrollTop(scrollTop);
|
|
190
|
+
side2Pane.editor.getControl().setScrollTop(scrollTop);
|
|
191
|
+
} else {
|
|
192
|
+
const targetScrollTop = this.computeTargetScrollTop(basePane.editor, side1Pane.editor, model.baseToSide1LineRangeMap);
|
|
193
|
+
side1Pane.editor.getControl().setScrollTop(targetScrollTop);
|
|
194
|
+
side2Pane.editor.getControl().setScrollTop(targetScrollTop);
|
|
195
|
+
if (shouldAlignResult) {
|
|
196
|
+
resultPane.editor.getControl().setScrollTop(targetScrollTop);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!shouldAlignResult) {
|
|
201
|
+
const targetScrollTop = this.computeTargetScrollTop(basePane.editor, resultPane.editor, model.baseToResultLineRangeMap);
|
|
202
|
+
resultPane.editor.getControl().setScrollTop(targetScrollTop);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected computeTargetScrollTop(sourceEditor: MonacoEditor, targetEditor: MonacoEditor, lineRangeMap: DocumentLineRangeMap): number {
|
|
207
|
+
const visibleRanges = sourceEditor.getVisibleRanges();
|
|
208
|
+
if (visibleRanges.length === 0) {
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const topLineNumber = visibleRanges[0].start.line;
|
|
213
|
+
const scrollTop = sourceEditor.getControl().getScrollTop();
|
|
214
|
+
|
|
215
|
+
let sourceStartTopPx: number;
|
|
216
|
+
let sourceEndPx: number;
|
|
217
|
+
let targetStartTopPx: number;
|
|
218
|
+
let targetEndPx: number;
|
|
219
|
+
|
|
220
|
+
if (topLineNumber === 0 && scrollTop <= sourceEditor.getControl().getTopForLineNumber(1)) { // special case: scrollTop is before or at the top of the first line
|
|
221
|
+
sourceStartTopPx = 0;
|
|
222
|
+
sourceEndPx = sourceEditor.getControl().getTopForLineNumber(1);
|
|
223
|
+
|
|
224
|
+
targetStartTopPx = 0;
|
|
225
|
+
targetEndPx = targetEditor.getControl().getTopForLineNumber(1);
|
|
226
|
+
} else {
|
|
227
|
+
const { originalRange: sourceRange, modifiedRange: targetRange } = lineRangeMap.projectLine(Math.max(topLineNumber - 1, 0));
|
|
228
|
+
|
|
229
|
+
sourceStartTopPx = sourceEditor.getControl().getTopForLineNumber(sourceRange.startLineNumber + 1);
|
|
230
|
+
sourceEndPx = sourceEditor.getControl().getTopForLineNumber(sourceRange.endLineNumberExclusive + 1);
|
|
231
|
+
|
|
232
|
+
targetStartTopPx = targetEditor.getControl().getTopForLineNumber(targetRange.startLineNumber + 1);
|
|
233
|
+
targetEndPx = targetEditor.getControl().getTopForLineNumber(targetRange.endLineNumberExclusive + 1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const factor = Math.min(sourceEndPx === sourceStartTopPx ? 0 : (scrollTop - sourceStartTopPx) / (sourceEndPx - sourceStartTopPx), 1);
|
|
237
|
+
const targetScrollTop = targetStartTopPx + (targetEndPx - targetStartTopPx) * factor;
|
|
238
|
+
|
|
239
|
+
return targetScrollTop;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
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
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
|
+
import { Disposable } from '@theia/core';
|
|
19
|
+
import { Autorun, Observable } from '@theia/core/lib/common/observable';
|
|
20
|
+
import * as monaco from '@theia/monaco-editor-core';
|
|
21
|
+
import { MonacoEditorViewZone } from '@theia/monaco/lib/browser/monaco-editor-zone-widget';
|
|
22
|
+
import { MergeEditor } from '../merge-editor';
|
|
23
|
+
import { MergeRange } from '../model/merge-range';
|
|
24
|
+
import { MergeRangeAction, MergeRangeActions } from './merge-range-actions';
|
|
25
|
+
import { MergeEditorPane } from './merge-editor-panes';
|
|
26
|
+
import { DiffSpacers, DiffSpacerService } from './diff-spacers';
|
|
27
|
+
|
|
28
|
+
export interface MergeEditorViewZone {
|
|
29
|
+
create(ctx: MergeEditorViewZone.CreationContext): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export namespace MergeEditorViewZone {
|
|
33
|
+
export interface CreationContext {
|
|
34
|
+
createViewZone(viewZone: Omit<MonacoEditorViewZone, 'id'>): void;
|
|
35
|
+
register(disposable: Disposable): void;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MergeEditorViewZones {
|
|
40
|
+
readonly baseViewZones: readonly MergeEditorViewZone[];
|
|
41
|
+
readonly side1ViewZones: readonly MergeEditorViewZone[];
|
|
42
|
+
readonly side2ViewZones: readonly MergeEditorViewZone[];
|
|
43
|
+
readonly resultViewZones: readonly MergeEditorViewZone[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@injectable()
|
|
47
|
+
export class MergeEditorViewZoneComputer {
|
|
48
|
+
|
|
49
|
+
@inject(DiffSpacerService)
|
|
50
|
+
protected readonly diffSpacerService: DiffSpacerService;
|
|
51
|
+
|
|
52
|
+
computeViewZones(mergeEditor: MergeEditor): MergeEditorViewZones {
|
|
53
|
+
|
|
54
|
+
const baseViewZones: MergeEditorViewZone[] = [];
|
|
55
|
+
const side1ViewZones: MergeEditorViewZone[] = [];
|
|
56
|
+
const side2ViewZones: MergeEditorViewZone[] = [];
|
|
57
|
+
const resultViewZones: MergeEditorViewZone[] = [];
|
|
58
|
+
|
|
59
|
+
const { model, shouldAlignResult, shouldAlignBase } = mergeEditor;
|
|
60
|
+
|
|
61
|
+
for (const mergeRange of model.mergeRanges) {
|
|
62
|
+
const { side1Pane, side2Pane, resultPane } = mergeEditor;
|
|
63
|
+
|
|
64
|
+
const actions = this.newMergeRangeActions(mergeEditor, mergeRange);
|
|
65
|
+
|
|
66
|
+
let resultActionZoneHeight = this.getActionZoneMinHeight(resultPane);
|
|
67
|
+
if (actions.hasSideActions || (shouldAlignResult && actions.hasResultActions)) {
|
|
68
|
+
let actionZoneHeight = Math.max(this.getActionZoneMinHeight(side1Pane), this.getActionZoneMinHeight(side2Pane));
|
|
69
|
+
if (shouldAlignResult) {
|
|
70
|
+
resultActionZoneHeight = actionZoneHeight = Math.max(actionZoneHeight, resultActionZoneHeight);
|
|
71
|
+
}
|
|
72
|
+
side1ViewZones.push(this.newActionZone(side1Pane, actions.side1ActionsObservable, mergeRange.side1Range.startLineNumber - 1, actionZoneHeight));
|
|
73
|
+
side2ViewZones.push(this.newActionZone(side2Pane, actions.side2ActionsObservable, mergeRange.side2Range.startLineNumber - 1, actionZoneHeight));
|
|
74
|
+
if (shouldAlignBase) {
|
|
75
|
+
baseViewZones.push(this.newActionZonePlaceholder(mergeRange.baseRange.startLineNumber - 1, actionZoneHeight));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (actions.hasResultActions) {
|
|
79
|
+
resultViewZones.push(
|
|
80
|
+
this.newActionZone(resultPane, actions.resultActionsObservable, model.getLineRangeInResult(mergeRange).startLineNumber - 1, resultActionZoneHeight)
|
|
81
|
+
);
|
|
82
|
+
} else if (shouldAlignResult && actions.hasSideActions) {
|
|
83
|
+
resultViewZones.push(this.newActionZonePlaceholder(model.getLineRangeInResult(mergeRange).startLineNumber - 1, resultActionZoneHeight));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const baseLineCount = model.baseDocument.lineCount;
|
|
88
|
+
const multiDiffSpacers: DiffSpacers[] = [];
|
|
89
|
+
|
|
90
|
+
multiDiffSpacers.push(this.diffSpacerService.computeDiffSpacers(model.side1Changes, baseLineCount));
|
|
91
|
+
multiDiffSpacers.push(this.diffSpacerService.computeDiffSpacers(model.side2Changes, baseLineCount));
|
|
92
|
+
|
|
93
|
+
if (shouldAlignResult) {
|
|
94
|
+
multiDiffSpacers.push(this.diffSpacerService.computeDiffSpacers(model.resultChanges, baseLineCount));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const combinedMultiDiffSpacers = this.diffSpacerService.combineMultiDiffSpacers(multiDiffSpacers);
|
|
98
|
+
|
|
99
|
+
if (shouldAlignBase) {
|
|
100
|
+
this.createSpacerZones(combinedMultiDiffSpacers.originalSpacers, baseViewZones);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const { modifiedSides } = shouldAlignBase ? combinedMultiDiffSpacers : this.diffSpacerService.excludeOriginalSide(combinedMultiDiffSpacers);
|
|
104
|
+
|
|
105
|
+
this.createSpacerZones(modifiedSides[0].modifiedSpacers, side1ViewZones);
|
|
106
|
+
this.createSpacerZones(modifiedSides[1].modifiedSpacers, side2ViewZones);
|
|
107
|
+
|
|
108
|
+
if (shouldAlignResult) {
|
|
109
|
+
this.createSpacerZones(modifiedSides[2].modifiedSpacers, resultViewZones);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { baseViewZones, side1ViewZones, side2ViewZones, resultViewZones };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected createSpacerZones(spacers: number[], viewZones: MergeEditorViewZone[]): void {
|
|
116
|
+
const lineNumbers = Object.keys(spacers).map(Number); // note: spacers is a sparse array
|
|
117
|
+
for (const lineNumber of lineNumbers) {
|
|
118
|
+
const heightInLines = spacers[lineNumber];
|
|
119
|
+
if (heightInLines) {
|
|
120
|
+
viewZones.push(this.newSpacerZone(lineNumber - 1, heightInLines));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected newMergeRangeActions(mergeEditor: MergeEditor, mergeRange: MergeRange): MergeRangeActions {
|
|
126
|
+
return new MergeRangeActions(mergeEditor, mergeRange);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected getActionZoneMinHeight(pane: MergeEditorPane): number {
|
|
130
|
+
return pane.editor.getControl().getOption(monaco.editor.EditorOption.lineHeight);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected newActionZone(pane: MergeEditorPane, actions: Observable<readonly MergeRangeAction[]>, afterLineNumber: number, heightInPx: number): MergeEditorViewZone {
|
|
134
|
+
return new MergeEditorActionZone(pane, actions, afterLineNumber, heightInPx);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
protected newActionZonePlaceholder(afterLineNumber: number, heightInPx: number): MergeEditorViewZone {
|
|
138
|
+
return new MergeEditorActionZonePlaceholder(afterLineNumber, heightInPx);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected newSpacerZone(afterLineNumber: number, heightInLines: number): MergeEditorViewZone {
|
|
142
|
+
return new MergeEditorSpacerZone(afterLineNumber, heightInLines);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export class MergeEditorActionZone implements MergeEditorViewZone {
|
|
147
|
+
|
|
148
|
+
protected static counter = 0;
|
|
149
|
+
|
|
150
|
+
constructor(
|
|
151
|
+
protected readonly pane: MergeEditorPane,
|
|
152
|
+
protected readonly actionsObservable: Observable<readonly MergeRangeAction[]>,
|
|
153
|
+
protected readonly afterLineNumber: number,
|
|
154
|
+
protected readonly heightInPx: number
|
|
155
|
+
) {}
|
|
156
|
+
|
|
157
|
+
create(ctx: MergeEditorViewZone.CreationContext): void {
|
|
158
|
+
const overlayWidgetNode = document.createElement('div');
|
|
159
|
+
overlayWidgetNode.className = 'action-zone';
|
|
160
|
+
|
|
161
|
+
ctx.createViewZone({
|
|
162
|
+
domNode: document.createElement('div'),
|
|
163
|
+
afterLineNumber: this.afterLineNumber + 1, // + 1, since line numbers in Monaco are 1-based
|
|
164
|
+
heightInPx: this.heightInPx,
|
|
165
|
+
onComputedHeight: height => overlayWidgetNode.style.height = `${height}px`,
|
|
166
|
+
onDomNodeTop: top => overlayWidgetNode.style.top = `${top}px`
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const editor = this.pane.editor.getControl();
|
|
170
|
+
const setLeftPosition = () => overlayWidgetNode.style.left = editor.getLayoutInfo().contentLeft + 'px';
|
|
171
|
+
setLeftPosition();
|
|
172
|
+
ctx.register(editor.onDidLayoutChange(setLeftPosition));
|
|
173
|
+
|
|
174
|
+
const overlayWidgetId = `mergeEditorActionZone${MergeEditorActionZone.counter++}`;
|
|
175
|
+
const overlayWidget = {
|
|
176
|
+
getId: () => overlayWidgetId,
|
|
177
|
+
getDomNode: () => overlayWidgetNode,
|
|
178
|
+
// eslint-disable-next-line no-null/no-null
|
|
179
|
+
getPosition: () => null
|
|
180
|
+
};
|
|
181
|
+
editor.addOverlayWidget(overlayWidget);
|
|
182
|
+
ctx.register(Disposable.create(() => {
|
|
183
|
+
editor.removeOverlayWidget(overlayWidget);
|
|
184
|
+
}));
|
|
185
|
+
|
|
186
|
+
const actionContainer = document.createElement('div');
|
|
187
|
+
actionContainer.className = 'codelens-decoration';
|
|
188
|
+
overlayWidgetNode.appendChild(actionContainer);
|
|
189
|
+
|
|
190
|
+
ctx.register(Autorun.create(() => this.renderActions(actionContainer, this.actionsObservable.get())));
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
protected renderActions(parent: HTMLElement, actions: readonly MergeRangeAction[]): void {
|
|
194
|
+
const children: HTMLElement[] = [];
|
|
195
|
+
let isFirst = true;
|
|
196
|
+
for (const action of actions) {
|
|
197
|
+
if (isFirst) {
|
|
198
|
+
isFirst = false;
|
|
199
|
+
} else {
|
|
200
|
+
const actionSeparator = document.createElement('span');
|
|
201
|
+
actionSeparator.append('\u00a0|\u00a0');
|
|
202
|
+
children.push(actionSeparator);
|
|
203
|
+
}
|
|
204
|
+
const title = this.getActionTitle(action);
|
|
205
|
+
if (action.run) {
|
|
206
|
+
const actionLink = document.createElement('a');
|
|
207
|
+
actionLink.role = 'button';
|
|
208
|
+
actionLink.onclick = () => action.run!();
|
|
209
|
+
if (action.tooltip) {
|
|
210
|
+
actionLink.title = action.tooltip;
|
|
211
|
+
}
|
|
212
|
+
actionLink.append(title);
|
|
213
|
+
children.push(actionLink);
|
|
214
|
+
} else {
|
|
215
|
+
const actionLabel = document.createElement('span');
|
|
216
|
+
if (action.tooltip) {
|
|
217
|
+
actionLabel.title = action.tooltip;
|
|
218
|
+
}
|
|
219
|
+
actionLabel.append(title);
|
|
220
|
+
children.push(actionLabel);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
parent.innerText = ''; // reset children
|
|
224
|
+
parent.append(...children);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
protected getActionTitle(action: MergeRangeAction): string {
|
|
228
|
+
return action.text;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export class MergeEditorActionZonePlaceholder implements MergeEditorViewZone {
|
|
233
|
+
constructor(
|
|
234
|
+
protected readonly afterLineNumber: number,
|
|
235
|
+
protected readonly heightInPx: number
|
|
236
|
+
) {}
|
|
237
|
+
|
|
238
|
+
create(ctx: MergeEditorViewZone.CreationContext): void {
|
|
239
|
+
const domNode = document.createElement('div');
|
|
240
|
+
domNode.className = 'action-zone-placeholder';
|
|
241
|
+
ctx.createViewZone({
|
|
242
|
+
afterLineNumber: this.afterLineNumber + 1, // + 1, since line numbers in Monaco are 1-based
|
|
243
|
+
heightInPx: this.heightInPx,
|
|
244
|
+
domNode
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export class MergeEditorSpacerZone implements MergeEditorViewZone {
|
|
250
|
+
constructor(
|
|
251
|
+
protected readonly afterLineNumber: number,
|
|
252
|
+
protected readonly heightInLines: number
|
|
253
|
+
) { }
|
|
254
|
+
|
|
255
|
+
create(ctx: MergeEditorViewZone.CreationContext): void {
|
|
256
|
+
const domNode = document.createElement('div');
|
|
257
|
+
domNode.className = 'diagonal-fill';
|
|
258
|
+
ctx.createViewZone({
|
|
259
|
+
afterLineNumber: this.afterLineNumber + 1, // + 1, since line numbers in Monaco are 1-based
|
|
260
|
+
heightInLines: this.heightInLines,
|
|
261
|
+
domNode
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
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/view/conflictActions.ts
|
|
21
|
+
|
|
22
|
+
import { DerivedObservable, ObservableUtils } from '@theia/core/lib/common/observable';
|
|
23
|
+
import { MergeRange, MergeRangeAcceptedState, MergeSide } from '../model/merge-range';
|
|
24
|
+
import { MergeEditor } from '../merge-editor';
|
|
25
|
+
import { nls } from '@theia/core';
|
|
26
|
+
|
|
27
|
+
export interface MergeRangeAction {
|
|
28
|
+
readonly text: string;
|
|
29
|
+
readonly tooltip?: string;
|
|
30
|
+
run?(): unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class MergeRangeActions {
|
|
34
|
+
|
|
35
|
+
readonly side1ActionsObservable = DerivedObservable.create(() => this.getActionsForSide(1));
|
|
36
|
+
readonly side2ActionsObservable = DerivedObservable.create(() => this.getActionsForSide(2));
|
|
37
|
+
readonly resultActionsObservable = DerivedObservable.create(() => this.getResultActions());
|
|
38
|
+
|
|
39
|
+
protected readonly hasSideActionsObservable = DerivedObservable.create(() => this.side1ActionsObservable.get().length + this.side2ActionsObservable.get().length > 0);
|
|
40
|
+
get hasSideActions(): boolean { return this.hasSideActionsObservable.get(); }
|
|
41
|
+
|
|
42
|
+
protected readonly hasResultActionsObservable = DerivedObservable.create(() => this.resultActionsObservable.get().length > 0);
|
|
43
|
+
get hasResultActions(): boolean { return this.hasResultActionsObservable.get(); }
|
|
44
|
+
|
|
45
|
+
constructor(
|
|
46
|
+
protected readonly mergeEditor: MergeEditor,
|
|
47
|
+
protected readonly mergeRange: MergeRange
|
|
48
|
+
) {}
|
|
49
|
+
|
|
50
|
+
protected getActionsForSide(side: MergeSide): readonly MergeRangeAction[] {
|
|
51
|
+
const { mergeEditor, mergeRange } = this;
|
|
52
|
+
const { model, side1Title, side2Title } = mergeEditor;
|
|
53
|
+
|
|
54
|
+
if (!model.hasMergeRange(mergeRange)) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result: MergeRangeAction[] = [];
|
|
59
|
+
const sideTitle = side === 1 ? side1Title : side2Title;
|
|
60
|
+
const state = model.getMergeRangeResultState(mergeRange);
|
|
61
|
+
|
|
62
|
+
if (state !== 'Unrecognized' && !state.includes('Side' + side)) {
|
|
63
|
+
if (state !== 'Base' || mergeRange.getChanges(side).length) {
|
|
64
|
+
result.push({
|
|
65
|
+
text: nls.localizeByDefault('Accept {0}', sideTitle),
|
|
66
|
+
tooltip: nls.localizeByDefault('Accept {0} in the result document.', sideTitle),
|
|
67
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, MergeRangeAcceptedState.addSide(state, side))
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (mergeRange.canBeSmartCombined(side)) {
|
|
72
|
+
result.push({
|
|
73
|
+
text: mergeRange.isSmartCombinationOrderRelevant ?
|
|
74
|
+
nls.localizeByDefault('Accept Combination ({0} First)', sideTitle) :
|
|
75
|
+
nls.localizeByDefault('Accept Combination'),
|
|
76
|
+
tooltip: nls.localizeByDefault('Accept an automatic combination of both sides in the result document.'),
|
|
77
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, MergeRangeAcceptedState.addSide(
|
|
78
|
+
side === 1 ? 'Side1' : 'Side2', side === 1 ? 2 : 1, { smartCombination: true }))
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected getResultActions(): readonly MergeRangeAction[] {
|
|
86
|
+
const { mergeEditor, mergeRange } = this;
|
|
87
|
+
const { model, side1Title, side2Title } = mergeEditor;
|
|
88
|
+
|
|
89
|
+
if (!model.hasMergeRange(mergeRange)) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const result: MergeRangeAction[] = [];
|
|
94
|
+
const state = model.getMergeRangeResultState(mergeRange);
|
|
95
|
+
|
|
96
|
+
if (state === 'Unrecognized') {
|
|
97
|
+
result.push({
|
|
98
|
+
text: nls.localizeByDefault('Manual Resolution'),
|
|
99
|
+
tooltip: nls.localizeByDefault('This conflict has been resolved manually.')
|
|
100
|
+
});
|
|
101
|
+
result.push({
|
|
102
|
+
text: nls.localizeByDefault('Reset to base'),
|
|
103
|
+
tooltip: nls.localizeByDefault('Reset this conflict to the common ancestor of both the right and left changes.'),
|
|
104
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, 'Base')
|
|
105
|
+
});
|
|
106
|
+
} else if (state === 'Base') {
|
|
107
|
+
result.push({
|
|
108
|
+
text: nls.localizeByDefault('No Changes Accepted'),
|
|
109
|
+
tooltip: nls.localizeByDefault('The current resolution of this conflict equals the common ancestor of both the right and left changes.')
|
|
110
|
+
});
|
|
111
|
+
if (!model.isMergeRangeHandled(mergeRange)) {
|
|
112
|
+
result.push({
|
|
113
|
+
text: nls.localizeByDefault('Mark as Handled'),
|
|
114
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, state)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const labels: string[] = [];
|
|
119
|
+
const stateToggles: MergeRangeAction[] = [];
|
|
120
|
+
if (state.includes('Side1')) {
|
|
121
|
+
labels.push(side1Title);
|
|
122
|
+
stateToggles.push({
|
|
123
|
+
text: nls.localizeByDefault('Remove {0}', side1Title),
|
|
124
|
+
tooltip: nls.localizeByDefault('Remove {0} from the result document.', side1Title),
|
|
125
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, MergeRangeAcceptedState.removeSide(state, 1))
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (state.includes('Side2')) {
|
|
129
|
+
labels.push(side2Title);
|
|
130
|
+
stateToggles.push({
|
|
131
|
+
text: nls.localizeByDefault('Remove {0}', side2Title),
|
|
132
|
+
tooltip: nls.localizeByDefault('Remove {0} from the result document.', side2Title),
|
|
133
|
+
run: () => this.applyMergeRangeAcceptedState(mergeRange, MergeRangeAcceptedState.removeSide(state, 2))
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (state.startsWith('Side2')) {
|
|
137
|
+
labels.reverse();
|
|
138
|
+
stateToggles.reverse();
|
|
139
|
+
}
|
|
140
|
+
if (labels.length) {
|
|
141
|
+
result.push({
|
|
142
|
+
text: labels.join(' + ')
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
result.push(...stateToggles);
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
protected async applyMergeRangeAcceptedState(mergeRange: MergeRange, state: MergeRangeAcceptedState): Promise<void> {
|
|
151
|
+
const { model, resultPane } = this.mergeEditor;
|
|
152
|
+
resultPane.activate();
|
|
153
|
+
await ObservableUtils.waitForState(model.isUpToDateObservable);
|
|
154
|
+
resultPane.goToMergeRange(mergeRange, { reveal: false }); // set the cursor state that will be restored when undoing the operation
|
|
155
|
+
model.applyMergeRangeAcceptedState(mergeRange, state);
|
|
156
|
+
await ObservableUtils.waitForState(model.isUpToDateObservable);
|
|
157
|
+
resultPane.goToMergeRange(mergeRange, { reveal: false }); // set the resulting cursor state
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -18,4 +18,6 @@ export namespace ScmColors {
|
|
|
18
18
|
export const editorGutterModifiedBackground = 'editorGutter.modifiedBackground';
|
|
19
19
|
export const editorGutterAddedBackground = 'editorGutter.addedBackground';
|
|
20
20
|
export const editorGutterDeletedBackground = 'editorGutter.deletedBackground';
|
|
21
|
+
export const handledConflictMinimapOverviewRulerColor = 'mergeEditor.conflict.handled.minimapOverViewRuler';
|
|
22
|
+
export const unhandledConflictMinimapOverviewRulerColor = 'mergeEditor.conflict.unhandled.minimapOverViewRuler';
|
|
21
23
|
}
|