Skip to content

Commit 23fa33b

Browse files
committed
feat: implement conflict actions operations (#2014)
* feat: implement conflict actions operations * feat: implement conflict actions operations * refactor: decorations type * fix: conflict-actions * chore: improve code * refactor: document mapping * chore: rename type * chore: add note
1 parent cca5a4d commit 23fa33b

18 files changed

+712
-169
lines changed

packages/monaco/src/browser/contrib/merge-editor/merge-editor.service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Disposable, MonacoService } from '@opensumi/ide-core-browser';
44
import { ICodeEditor } from '../../monaco-api/editor';
55

66
import { ComputerDiffModel } from './model/computer-diff';
7+
import { MappingManagerService } from './service/mapping-manager.service';
78
import { ActionsManager } from './view/actions-manager';
89
import { CurrentCodeEditor } from './view/editors/currentCodeEditor';
910
import { IncomingCodeEditor } from './view/editors/incomingCodeEditor';
@@ -19,6 +20,9 @@ export class MergeEditorService extends Disposable {
1920
@Autowired(MonacoService)
2021
private readonly monacoService: MonacoService;
2122

23+
@Autowired(MappingManagerService)
24+
protected readonly mappingManagerService: MappingManagerService;
25+
2226
private currentView: CurrentCodeEditor;
2327
private resultView: ResultCodeEditor;
2428
private incomingView: IncomingCodeEditor;
@@ -34,7 +38,7 @@ export class MergeEditorService extends Disposable {
3438
this.computerDiffModel = new ComputerDiffModel();
3539
this.scrollSynchronizer = new ScrollSynchronizer();
3640
this.stickinessConnectManager = new StickinessConnectManager();
37-
this.actionsManager = new ActionsManager();
41+
this.actionsManager = this.injector.get(ActionsManager, [this.mappingManagerService]);
3842
}
3943

4044
public instantiationCodeEditor(current: HTMLDivElement, result: HTMLDivElement, incoming: HTMLDivElement): void {

packages/monaco/src/browser/contrib/merge-editor/model/computer-diff.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
21
import { IDocumentDiff } from '@opensumi/monaco-editor-core/esm/vs/editor/common/diff/documentDiffProvider';
3-
import {
4-
LineRangeMapping,
5-
RangeMapping,
6-
} from '@opensumi/monaco-editor-core/esm/vs/editor/common/diff/linesDiffComputer';
2+
import { RangeMapping } from '@opensumi/monaco-editor-core/esm/vs/editor/common/diff/linesDiffComputer';
73
import {
84
IEditorWorkerService,
95
IDiffComputationResult,
@@ -12,7 +8,9 @@ import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/s
128

139
import { ITextModel } from '../../../monaco-api/types';
1410

11+
import { InnerRange } from './inner-range';
1512
import { LineRange } from './line-range';
13+
import { LineRangeMapping } from './line-range-mapping';
1614

1715
export class ComputerDiffModel {
1816
private editorWorkerService: IEditorWorkerService;
@@ -33,7 +31,9 @@ export class ComputerDiffModel {
3331
new LineRangeMapping(
3432
new LineRange(c[0], c[1]),
3533
new LineRange(c[2], c[3]),
36-
c[4]?.map((c) => new RangeMapping(new Range(c[0], c[1], c[2], c[3]), new Range(c[4], c[5], c[6], c[7]))),
34+
c[4]?.map(
35+
(c) => new RangeMapping(new InnerRange(c[0], c[1], c[2], c[3]), new InnerRange(c[4], c[5], c[6], c[7])),
36+
),
3737
),
3838
),
3939
};
Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,103 @@
11
import { Injectable, Optional } from '@opensumi/di';
22
import { Disposable } from '@opensumi/ide-core-common';
3-
import { IEditorDecorationsCollection } from '@opensumi/monaco-editor-core/esm/vs/editor/common/editorCommon';
43
import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
54

65
import { ICodeEditor, IModelDeltaDecoration } from '../../../monaco-api/editor';
76
import { IActionsDescription } from '../types';
87
import { BaseCodeEditor } from '../view/editors/baseCodeEditor';
98

10-
import { LineRange } from './line-range';
9+
export interface IActionsDecoration {
10+
id: string;
11+
readonly editorDecoration: IModelDeltaDecoration;
12+
}
1113

1214
@Injectable({ multiple: false })
1315
export class ConflictActions extends Disposable {
14-
private decorationsCollection: IEditorDecorationsCollection;
15-
private actionsCollect: Map<number, LineRange>;
16+
private deltaDecoration: IActionsDecoration[] = [];
17+
18+
private actionsCollect: Map<number, IActionsDescription> = new Map();
1619

1720
private get editor(): ICodeEditor {
1821
return this.codeEditor.getEditor();
1922
}
2023

2124
constructor(@Optional() private readonly codeEditor: BaseCodeEditor) {
2225
super();
23-
24-
this.decorationsCollection = this.editor.createDecorationsCollection();
25-
this.actionsCollect = new Map();
2626
}
2727

2828
public override dispose(): void {
2929
super.dispose();
30-
this.decorationsCollection.clear();
3130
this.actionsCollect.clear();
3231
}
3332

33+
public clearDecorations(): void {
34+
this.editor.changeDecorations((accessor) => {
35+
for (const decoration of this.deltaDecoration) {
36+
accessor.removeDecoration(decoration.id);
37+
}
38+
this.deltaDecoration = [];
39+
});
40+
}
41+
42+
public clearDecorationsById(id: string): void {
43+
this.editor.changeDecorations((accessor) => {
44+
if (id) {
45+
accessor.removeDecoration(id);
46+
47+
this.deltaDecoration = this.deltaDecoration.filter((d) => d.id !== id);
48+
}
49+
});
50+
}
51+
3452
public setActions(actions: IActionsDescription[]): void {
35-
const newDecorations: IModelDeltaDecoration[] = actions.map((action) => {
53+
const newDecorations: IActionsDecoration[] = actions.map((action) => {
3654
const { range } = action;
37-
this.actionsCollect.set(range.startLineNumber, range);
55+
this.actionsCollect.set(range.startLineNumber, action);
3856

3957
return {
40-
range: {
41-
startLineNumber: range.startLineNumber,
42-
startColumn: 0,
43-
endLineNumber: range.startLineNumber,
44-
endColumn: 0,
58+
id: '',
59+
editorDecoration: {
60+
range: {
61+
startLineNumber: range.startLineNumber,
62+
startColumn: 0,
63+
endLineNumber: range.startLineNumber,
64+
endColumn: 0,
65+
},
66+
options: ModelDecorationOptions.register({
67+
description: range.id,
68+
...action.decorationOptions,
69+
}),
4570
},
46-
options: ModelDecorationOptions.register(action.decorationOptions),
4771
};
4872
});
4973

50-
this.decorationsCollection.set(newDecorations);
74+
this.editor.changeDecorations((accessor) => {
75+
accessor
76+
.deltaDecorations(
77+
this.deltaDecoration.map((d) => d.id),
78+
newDecorations.map((d) => d.editorDecoration),
79+
)
80+
.forEach((id, i) => (newDecorations[i].id = id));
81+
this.deltaDecoration = newDecorations;
82+
});
83+
}
84+
85+
public clearActions(line: number): void {
86+
if (this.actionsCollect.has(line)) {
87+
const actions = this.actionsCollect.get(line);
88+
89+
const matchDecoration = this.deltaDecoration.find(
90+
(d) => d.editorDecoration.options.description === actions!.range.id,
91+
);
92+
if (matchDecoration) {
93+
this.clearDecorationsById(matchDecoration.id);
94+
}
95+
96+
this.actionsCollect.delete(line);
97+
}
5198
}
5299

53-
public getActions(line: number): LineRange | undefined {
100+
public getActions(line: number): IActionsDescription | undefined {
54101
return this.actionsCollect.get(line);
55102
}
56103
}

packages/monaco/src/browser/contrib/merge-editor/model/decorations.ts

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
import { Injectable, Optional } from '@opensumi/di';
22
import { Disposable, Emitter, Event } from '@opensumi/ide-core-common';
3-
import { IRange, Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
43
import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
54
import { IModelDecorationsChangedEvent } from '@opensumi/monaco-editor-core/esm/vs/editor/common/textModelEvents';
65

76
import { ICodeEditor, IModelDeltaDecoration } from '../../../monaco-api/editor';
8-
import { EditorViewType, LineRangeType } from '../types';
7+
import { EditorViewType } from '../types';
98
import { BaseCodeEditor } from '../view/editors/baseCodeEditor';
109
import { GuidelineWidget } from '../view/guideline-widget';
1110

11+
import { InnerRange } from './inner-range';
1212
import { LineRange } from './line-range';
1313

14-
export interface IRenderChangesInput {
15-
ranges: LineRange;
16-
type: LineRangeType;
17-
}
18-
19-
export interface IRenderInnerChangesInput {
20-
ranges: Range[];
21-
type: LineRangeType;
22-
}
23-
2414
export interface IDiffDecoration {
2515
id: string;
2616
readonly editorDecoration: IModelDeltaDecoration;
@@ -58,15 +48,19 @@ export class MergeEditorDecorations extends Disposable {
5848
this.editor.onDidChangeModelDecorations,
5949
this.onDidChangeLineWidget,
6050
)(() => {
61-
this._onDidChangeDecorations.fire(this);
51+
this.launchChange();
6252
}),
6353
);
6454
}
6555

66-
private createLineDecoration(range: LineRange, type: LineRangeType): IDiffDecoration {
56+
public launchChange(): void {
57+
this._onDidChangeDecorations.fire(this);
58+
}
59+
60+
public createLineDecoration(range: LineRange): IDiffDecoration {
6761
const options = ModelDecorationOptions.register({
68-
description: 'merge-editor-diff-line',
69-
className: `merge-editor-diff-line-background ${type}`,
62+
description: range.id,
63+
className: `merge-editor-diff-line-background ${range.type}`,
7064
isWholeLine: true,
7165
});
7266

@@ -76,7 +70,7 @@ export class MergeEditorDecorations extends Disposable {
7670
range: {
7771
startLineNumber: range.startLineNumber,
7872
startColumn: 0,
79-
endLineNumber: range.endLineNumberExclusive - 1,
73+
endLineNumber: Math.max(range.startLineNumber, range.endLineNumberExclusive - 1),
8074
endColumn: Number.MAX_SAFE_INTEGER,
8175
},
8276
options: {
@@ -87,21 +81,28 @@ export class MergeEditorDecorations extends Disposable {
8781
};
8882
}
8983

90-
private createInnerCharDecoration(range: IRange, type: LineRangeType): IDiffDecoration {
84+
public createInnerCharDecoration(range: InnerRange): IDiffDecoration {
9185
return {
9286
id: '',
9387
editorDecoration: {
9488
range,
9589
options: ModelDecorationOptions.register({
96-
description: 'merge-editor-diff-inner-char',
97-
className: `merge-editor-diff-inner-char-background ${type}`,
90+
description: range.toString(),
91+
className: `merge-editor-diff-inner-char-background ${range.type}`,
9892
isWholeLine: false,
9993
}),
10094
},
10195
};
10296
}
10397

104-
private setDecorations(ranges: IRenderChangesInput[], innerChanges: IRenderInnerChangesInput[]): void {
98+
public createGuideLineWidget(range: LineRange): GuidelineWidget {
99+
const guidelineWidget = new GuidelineWidget(this.editor);
100+
guidelineWidget.create();
101+
guidelineWidget.setLineRangeType(range.type).showByLine(Math.max(0, Math.max(0, range.startLineNumber - 1)));
102+
return guidelineWidget;
103+
}
104+
105+
private setDecorations(ranges: LineRange[], innerChanges: InnerRange[][]): void {
105106
this.editor.changeDecorations((accessor) => {
106107
const newDecorations: IDiffDecoration[] = this.retainDecoration;
107108
this.retainLineWidgetSet.forEach((widget) => {
@@ -110,23 +111,19 @@ export class MergeEditorDecorations extends Disposable {
110111
});
111112

112113
for (const range of ranges) {
113-
if (range.ranges.isEmpty) {
114-
const guidelineWidget = new GuidelineWidget(this.editor);
115-
guidelineWidget.create();
116-
guidelineWidget.setLineRangeType(range.type).showByLine(Math.max(0, range.ranges.startLineNumber - 1));
117-
114+
if (range.isEmpty) {
115+
const guidelineWidget = this.createGuideLineWidget(range);
118116
this.lineWidgetSet.add(guidelineWidget);
119117
this._onDidChangeLineWidget.fire();
120118
} else {
121-
newDecorations.push(this.createLineDecoration(range.ranges, range.type));
119+
newDecorations.push(this.createLineDecoration(range));
122120
}
123121
}
124122

125123
for (const innerRange of innerChanges) {
126-
const { ranges, type } = innerRange;
127-
for (const range of ranges) {
124+
for (const range of innerRange) {
128125
if (!range.isEmpty()) {
129-
newDecorations.push(this.createInnerCharDecoration(range, type));
126+
newDecorations.push(this.createInnerCharDecoration(range));
130127
}
131128
}
132129
}
@@ -160,7 +157,7 @@ export class MergeEditorDecorations extends Disposable {
160157
this.cleanUpLineWidget(this.lineWidgetSet);
161158
}
162159

163-
public updateDecorations(ranges: IRenderChangesInput[], innerChanges: IRenderInnerChangesInput[]): void {
160+
public updateDecorations(ranges: LineRange[], innerChanges: InnerRange[][]): void {
164161
this.clearDecorations();
165162
this.render(ranges, innerChanges);
166163
}
@@ -187,7 +184,7 @@ export class MergeEditorDecorations extends Disposable {
187184
return this;
188185
}
189186

190-
public render(ranges: IRenderChangesInput[], innerChanges: IRenderInnerChangesInput[]): void {
187+
public render(ranges: LineRange[], innerChanges: InnerRange[][]): void {
191188
this.setDecorations(ranges, innerChanges);
192189
}
193190

0 commit comments

Comments
 (0)