@opensumi/ide-editor 3.8.3-next-1745907010.0 → 3.8.3-next-1746586819.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/editor-collection.service.d.ts +4 -0
- package/lib/browser/editor-collection.service.d.ts.map +1 -1
- package/lib/browser/editor-collection.service.js +8 -0
- package/lib/browser/editor-collection.service.js.map +1 -1
- package/lib/browser/editor.contribution.d.ts +1 -0
- package/lib/browser/editor.contribution.d.ts.map +1 -1
- package/lib/browser/editor.contribution.js +22 -0
- package/lib/browser/editor.contribution.js.map +1 -1
- package/lib/browser/editor.module.less +6 -0
- package/lib/browser/editor.view.d.ts.map +1 -1
- package/lib/browser/editor.view.js +18 -0
- package/lib/browser/editor.view.js.map +1 -1
- package/lib/browser/index.d.ts +4 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +20 -1
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/multi-diff/multi-diff-editor.d.ts +46 -0
- package/lib/browser/multi-diff/multi-diff-editor.d.ts.map +1 -0
- package/lib/browser/multi-diff/multi-diff-editor.js +209 -0
- package/lib/browser/multi-diff/multi-diff-editor.js.map +1 -0
- package/lib/browser/multi-diff/multi-diff-resolver.d.ts +10 -0
- package/lib/browser/multi-diff/multi-diff-resolver.d.ts.map +1 -0
- package/lib/browser/multi-diff/multi-diff-resolver.js +42 -0
- package/lib/browser/multi-diff/multi-diff-resolver.js.map +1 -0
- package/lib/browser/multi-diff/multi-diff-resource.d.ts +23 -0
- package/lib/browser/multi-diff/multi-diff-resource.d.ts.map +1 -0
- package/lib/browser/multi-diff/multi-diff-resource.js +67 -0
- package/lib/browser/multi-diff/multi-diff-resource.js.map +1 -0
- package/lib/browser/multi-diff/multi-diff.contribution.d.ts +13 -0
- package/lib/browser/multi-diff/multi-diff.contribution.d.ts.map +1 -0
- package/lib/browser/multi-diff/multi-diff.contribution.js +51 -0
- package/lib/browser/multi-diff/multi-diff.contribution.js.map +1 -0
- package/lib/browser/multi-diff/resolver.service.d.ts +9 -0
- package/lib/browser/multi-diff/resolver.service.d.ts.map +1 -0
- package/lib/browser/multi-diff/resolver.service.js +35 -0
- package/lib/browser/multi-diff/resolver.service.js.map +1 -0
- package/lib/browser/types.d.ts +5 -0
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +2 -1
- package/lib/browser/types.js.map +1 -1
- package/lib/browser/workbench-editor.service.d.ts +10 -0
- package/lib/browser/workbench-editor.service.d.ts.map +1 -1
- package/lib/browser/workbench-editor.service.js +36 -0
- package/lib/browser/workbench-editor.service.js.map +1 -1
- package/lib/common/editor.d.ts +12 -1
- package/lib/common/editor.d.ts.map +1 -1
- package/lib/common/editor.js +1 -0
- package/lib/common/editor.js.map +1 -1
- package/lib/common/multi-diff.d.ts +61 -0
- package/lib/common/multi-diff.d.ts.map +1 -0
- package/lib/common/multi-diff.js +22 -0
- package/lib/common/multi-diff.js.map +1 -0
- package/package.json +14 -14
- package/src/browser/editor-collection.service.ts +11 -1
- package/src/browser/editor.contribution.ts +36 -1
- package/src/browser/editor.module.less +6 -0
- package/src/browser/editor.view.tsx +22 -0
- package/src/browser/index.ts +19 -1
- package/src/browser/multi-diff/multi-diff-editor.ts +249 -0
- package/src/browser/multi-diff/multi-diff-resolver.ts +44 -0
- package/src/browser/multi-diff/multi-diff-resource.ts +59 -0
- package/src/browser/multi-diff/multi-diff.contribution.ts +54 -0
- package/src/browser/multi-diff/resolver.service.ts +35 -0
- package/src/browser/types.ts +7 -0
- package/src/browser/workbench-editor.service.ts +51 -0
- package/src/common/editor.ts +14 -0
- package/src/common/multi-diff.ts +87 -0
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
IDecorationApplyOptions,
|
|
28
28
|
IDiffEditor,
|
|
29
29
|
IEditor,
|
|
30
|
+
IResource,
|
|
30
31
|
IResourceOpenOptions,
|
|
31
32
|
IUndoStopOptions,
|
|
32
33
|
ResourceDecorationNeedChangeEvent,
|
|
@@ -36,8 +37,9 @@ import { IEditorDocumentModel, IEditorDocumentModelRef, isTextEditorViewState }
|
|
|
36
37
|
import { MonacoEditorDecorationApplier } from './decoration-applier';
|
|
37
38
|
import { EditorDocumentModelContentChangedEvent, IEditorDocumentModelService } from './doc-model/types';
|
|
38
39
|
import { EditorFeatureRegistryImpl } from './feature';
|
|
40
|
+
import { BrowserMultiDiffEditor } from './multi-diff/multi-diff-editor';
|
|
39
41
|
import { getConvertedMonacoOptions, isDiffEditorOption, isEditorOption } from './preference/converter';
|
|
40
|
-
import { IEditorFeatureRegistry } from './types';
|
|
42
|
+
import { IConvertedMonacoOptions, IEditorFeatureRegistry } from './types';
|
|
41
43
|
|
|
42
44
|
import type {
|
|
43
45
|
ICodeEditor as IMonacoCodeEditor,
|
|
@@ -152,6 +154,14 @@ export class EditorCollectionServiceImpl extends WithEventBus implements EditorC
|
|
|
152
154
|
return editor;
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
createMultiDiffEditor(dom: HTMLElement, options?: any, overrides?: { [key: string]: any }) {
|
|
158
|
+
const convertedOptions = getConvertedMonacoOptions(this.configurationService);
|
|
159
|
+
const monacoMultiDiffEditorWidget = this.monacoService.createMultiDiffEditorWidget(dom, overrides);
|
|
160
|
+
const mergedOptions: IConvertedMonacoOptions = { ...convertedOptions.diffOptions, ...options };
|
|
161
|
+
const editor = this.injector.get(BrowserMultiDiffEditor, [monacoMultiDiffEditorWidget, mergedOptions]);
|
|
162
|
+
return editor;
|
|
163
|
+
}
|
|
164
|
+
|
|
155
165
|
public createMergeEditor(dom: HTMLElement, options?: any, overrides?: { [key: string]: any }) {
|
|
156
166
|
const convertedOptions = getConvertedMonacoOptions(this.configurationService);
|
|
157
167
|
const mergedOptions: IDiffEditorConstructionOptions = {
|
|
@@ -44,7 +44,7 @@ import { IMenuRegistry, MenuContribution, MenuId } from '@opensumi/ide-core-brow
|
|
|
44
44
|
import { AbstractContextMenuService } from '@opensumi/ide-core-browser/lib/menu/next/menu.interface';
|
|
45
45
|
import { ICtxMenuRenderer } from '@opensumi/ide-core-browser/lib/menu/next/renderer/ctxmenu/base';
|
|
46
46
|
import { IRelaxedOpenMergeEditorArgs } from '@opensumi/ide-core-browser/lib/monaco/merge-editor-widget';
|
|
47
|
-
import { IDisposable, ILogger, PreferenceScope, isWindows } from '@opensumi/ide-core-common';
|
|
47
|
+
import { IDisposable, ILogger, PreferenceScope, UriComponents, isWindows } from '@opensumi/ide-core-common';
|
|
48
48
|
import { MergeEditorService } from '@opensumi/ide-monaco/lib/browser/contrib/merge-editor/merge-editor.service';
|
|
49
49
|
import { ITextmateTokenizer, ITextmateTokenizerService } from '@opensumi/ide-monaco/lib/browser/contrib/tokenizer';
|
|
50
50
|
import { EOL } from '@opensumi/ide-monaco/lib/browser/monaco-api/types';
|
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
WorkbenchEditorService,
|
|
69
69
|
} from '../common';
|
|
70
70
|
import { AUTO_SAVE_MODE } from '../common/editor';
|
|
71
|
+
import { MultiDiffEditorItem } from '../common/multi-diff';
|
|
71
72
|
|
|
72
73
|
import { MonacoTextModelService } from './doc-model/override';
|
|
73
74
|
import { IEditorDocumentModelContentRegistry, IEditorDocumentModelService } from './doc-model/types';
|
|
@@ -79,6 +80,7 @@ import { DocumentFormatService } from './format/format.service';
|
|
|
79
80
|
import { FormattingSelector } from './format/formatter-selector';
|
|
80
81
|
import { EditorHistoryService } from './history';
|
|
81
82
|
import { EditorContextMenuController } from './menu/editor.context';
|
|
83
|
+
import { MultiDiffResolver } from './multi-diff/multi-diff-resolver';
|
|
82
84
|
import { NavigationMenuContainer } from './navigation.view';
|
|
83
85
|
import { GoToLineQuickOpenHandler } from './quick-open/go-to-line';
|
|
84
86
|
import { WorkspaceSymbolQuickOpenHandler } from './quick-open/workspace-symbol-quickopen';
|
|
@@ -231,6 +233,9 @@ export class EditorContribution
|
|
|
231
233
|
@Autowired(ICtxMenuRenderer)
|
|
232
234
|
private readonly contextMenuRenderer: ICtxMenuRenderer;
|
|
233
235
|
|
|
236
|
+
@Autowired(MultiDiffResolver)
|
|
237
|
+
private readonly multiDiffResolver: MultiDiffResolver;
|
|
238
|
+
|
|
234
239
|
registerMonacoDefaultFormattingSelector(register: (selector: IFormattingEditProviderSelector) => IDisposable): void {
|
|
235
240
|
const formatSelector = this.injector.get(FormattingSelector);
|
|
236
241
|
this.addDispose(register(formatSelector.selectFormatter.bind(formatSelector)));
|
|
@@ -1231,6 +1236,36 @@ export class EditorContribution
|
|
|
1231
1236
|
formatService.formatSelectionWith();
|
|
1232
1237
|
},
|
|
1233
1238
|
});
|
|
1239
|
+
|
|
1240
|
+
commands.registerCommand(
|
|
1241
|
+
{
|
|
1242
|
+
id: EDITOR_COMMANDS.VSCODE_OPEN_MULTI_DIFF_EDITOR_COMMAND_ID,
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
execute: async (options: {
|
|
1246
|
+
title: string;
|
|
1247
|
+
multiDiffSourceUri: UriComponents;
|
|
1248
|
+
resources: { originalUri?: UriComponents; modifiedUri?: UriComponents }[];
|
|
1249
|
+
}) => {
|
|
1250
|
+
const sources: MultiDiffEditorItem[] = [];
|
|
1251
|
+
for (const { originalUri, modifiedUri } of options.resources) {
|
|
1252
|
+
sources.push(
|
|
1253
|
+
new MultiDiffEditorItem(
|
|
1254
|
+
originalUri ? URI.from(originalUri) : undefined,
|
|
1255
|
+
modifiedUri ? URI.from(modifiedUri) : undefined,
|
|
1256
|
+
modifiedUri ? URI.from(modifiedUri) : undefined,
|
|
1257
|
+
),
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
const multiDiffSourceUri = URI.from(options.multiDiffSourceUri);
|
|
1261
|
+
// 提前注册到 resolver 内,相同的multiDiffSourceUri支持更新
|
|
1262
|
+
this.multiDiffResolver.registerSources(multiDiffSourceUri, sources);
|
|
1263
|
+
await this.workbenchEditorService.open(multiDiffSourceUri, {
|
|
1264
|
+
label: options.title,
|
|
1265
|
+
});
|
|
1266
|
+
},
|
|
1267
|
+
},
|
|
1268
|
+
);
|
|
1234
1269
|
}
|
|
1235
1270
|
|
|
1236
1271
|
registerMenus(menus: IMenuRegistry) {
|
|
@@ -316,6 +316,7 @@ export const EditorGroupBody = ({ group }: { group: EditorGroup }) => {
|
|
|
316
316
|
const components: React.ReactNode[] = [];
|
|
317
317
|
const codeEditorRef = React.useRef<HTMLDivElement>(null);
|
|
318
318
|
const diffEditorRef = React.useRef<HTMLDivElement>(null);
|
|
319
|
+
const multiDiffEditorRef = React.useRef<HTMLDivElement>(null);
|
|
319
320
|
const mergeEditorRef = React.useRef<HTMLDivElement>(null);
|
|
320
321
|
const [, updateState] = React.useState<any>();
|
|
321
322
|
const forceUpdate = React.useCallback(() => updateState({}), []);
|
|
@@ -367,6 +368,21 @@ export const EditorGroupBody = ({ group }: { group: EditorGroup }) => {
|
|
|
367
368
|
};
|
|
368
369
|
}, []);
|
|
369
370
|
|
|
371
|
+
React.useEffect(() => {
|
|
372
|
+
if (multiDiffEditorRef.current) {
|
|
373
|
+
group.attachMultiDiffEditorDom(multiDiffEditorRef.current);
|
|
374
|
+
const observer = new ResizeObserver((entries) => {
|
|
375
|
+
const entry = entries[0];
|
|
376
|
+
if (entry && entry.contentRect.height > 0) {
|
|
377
|
+
group.doLayoutEditors();
|
|
378
|
+
observer.disconnect();
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
observer.observe(multiDiffEditorRef.current);
|
|
382
|
+
return () => observer.disconnect();
|
|
383
|
+
}
|
|
384
|
+
}, [multiDiffEditorRef.current]);
|
|
385
|
+
|
|
370
386
|
group.activeComponents.forEach((resources, component) => {
|
|
371
387
|
const initialProps = group.activateComponentsProps.get(component);
|
|
372
388
|
components.push(
|
|
@@ -478,6 +494,12 @@ export const EditorGroupBody = ({ group }: { group: EditorGroup }) => {
|
|
|
478
494
|
})}
|
|
479
495
|
ref={diffEditorRef}
|
|
480
496
|
/>
|
|
497
|
+
<div
|
|
498
|
+
className={cls(styles.kt_editor_multi_diff_editor, styles_kt_editor_component, {
|
|
499
|
+
[styles.kt_hidden]: !group.currentOpenType || group.currentOpenType.type !== EditorOpenType.multiDiff,
|
|
500
|
+
})}
|
|
501
|
+
ref={multiDiffEditorRef}
|
|
502
|
+
/>
|
|
481
503
|
<div
|
|
482
504
|
className={cls(styles.kt_editor_diff_3_editor, styles_kt_editor_component, {
|
|
483
505
|
[styles.kt_hidden]: !group.currentOpenType || group.currentOpenType.type !== EditorOpenType.mergeEditor,
|
package/src/browser/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { ITypeHierarchyService } from '@opensumi/ide-monaco/lib/browser/contrib/
|
|
|
18
18
|
|
|
19
19
|
import { EditorCollectionService, ILanguageService, ResourceService, WorkbenchEditorService } from '../common';
|
|
20
20
|
import { IDocPersistentCacheProvider } from '../common/doc-cache';
|
|
21
|
+
import { IMultiDiffSourceResolverService } from '../common/multi-diff';
|
|
21
22
|
|
|
22
23
|
import { BreadCrumbServiceImpl } from './breadcrumb';
|
|
23
24
|
import { EditorComponentRegistryImpl } from './component';
|
|
@@ -52,6 +53,8 @@ import {
|
|
|
52
53
|
MonacoCommandService,
|
|
53
54
|
} from './monaco-contrib/command/command.service';
|
|
54
55
|
import { TextmateService } from './monaco-contrib/tokenizer/textmate.service';
|
|
56
|
+
import { MultiDiffEditorContribution } from './multi-diff/multi-diff.contribution';
|
|
57
|
+
import { MultiDiffSourceResolverService } from './multi-diff/resolver.service';
|
|
55
58
|
import { NotebookService } from './notebook.service';
|
|
56
59
|
import { EditorPreferenceContribution } from './preference/contribution';
|
|
57
60
|
import { EditorPreferences, editorPreferenceSchema } from './preference/schema';
|
|
@@ -67,6 +70,7 @@ import {
|
|
|
67
70
|
IEditorTabService,
|
|
68
71
|
ILanguageStatusService,
|
|
69
72
|
INotebookService,
|
|
73
|
+
MultiDiffSourceContribution,
|
|
70
74
|
} from './types';
|
|
71
75
|
import { UntitledDocumentIdCounter } from './untitled-resource';
|
|
72
76
|
import { WorkbenchEditorServiceImpl } from './workbench-editor.service';
|
|
@@ -180,8 +184,13 @@ export class EditorModule extends BrowserModule {
|
|
|
180
184
|
token: INotebookService,
|
|
181
185
|
useClass: NotebookService,
|
|
182
186
|
},
|
|
187
|
+
{
|
|
188
|
+
token: IMultiDiffSourceResolverService,
|
|
189
|
+
useClass: MultiDiffSourceResolverService,
|
|
190
|
+
},
|
|
183
191
|
EditorPreferenceContribution,
|
|
184
192
|
DefaultDiffEditorContribution,
|
|
193
|
+
MultiDiffEditorContribution,
|
|
185
194
|
MergeEditorContribution,
|
|
186
195
|
EditorClientAppContribution,
|
|
187
196
|
EditorContribution,
|
|
@@ -195,7 +204,7 @@ export class EditorModule extends BrowserModule {
|
|
|
195
204
|
OpenTypeMenuContribution,
|
|
196
205
|
];
|
|
197
206
|
electronProviders = [EditorElectronContribution];
|
|
198
|
-
contributionProvider = BrowserEditorContribution;
|
|
207
|
+
contributionProvider = [BrowserEditorContribution, MultiDiffSourceContribution];
|
|
199
208
|
}
|
|
200
209
|
|
|
201
210
|
@Domain(ClientAppContribution)
|
|
@@ -224,9 +233,15 @@ export class EditorClientAppContribution implements ClientAppContribution {
|
|
|
224
233
|
@Autowired(IEditorDocumentModelService)
|
|
225
234
|
modelService: EditorDocumentModelServiceImpl;
|
|
226
235
|
|
|
236
|
+
@Autowired(IMultiDiffSourceResolverService)
|
|
237
|
+
multiDiffSourceResolverService: IMultiDiffSourceResolverService;
|
|
238
|
+
|
|
227
239
|
@Autowired(BrowserEditorContribution)
|
|
228
240
|
private readonly contributions: ContributionProvider<BrowserEditorContribution>;
|
|
229
241
|
|
|
242
|
+
@Autowired(MultiDiffSourceContribution)
|
|
243
|
+
private readonly multiDiffSourceContribution: ContributionProvider<MultiDiffSourceContribution>;
|
|
244
|
+
|
|
230
245
|
async initialize() {
|
|
231
246
|
for (const contribution of this.contributions.getContributions()) {
|
|
232
247
|
if (contribution.registerResource) {
|
|
@@ -245,6 +260,9 @@ export class EditorClientAppContribution implements ClientAppContribution {
|
|
|
245
260
|
contribution.registerEditorFeature(this.editorFeatureRegistry);
|
|
246
261
|
}
|
|
247
262
|
}
|
|
263
|
+
for (const contribution of this.multiDiffSourceContribution.getContributions()) {
|
|
264
|
+
contribution.registerMultiDiffSourceResolver(this.multiDiffSourceResolverService);
|
|
265
|
+
}
|
|
248
266
|
this.workbenchEditorService.contributionsReady.resolve();
|
|
249
267
|
await Promise.all([this.workbenchEditorService.initialize(), this.modelService.initialize()]);
|
|
250
268
|
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di';
|
|
2
|
+
import { PreferenceService } from '@opensumi/ide-core-browser';
|
|
3
|
+
import {
|
|
4
|
+
Disposable,
|
|
5
|
+
DisposableStore,
|
|
6
|
+
Emitter,
|
|
7
|
+
IDisposable,
|
|
8
|
+
OnEvent,
|
|
9
|
+
URI,
|
|
10
|
+
WithEventBus,
|
|
11
|
+
} from '@opensumi/ide-core-common';
|
|
12
|
+
import {
|
|
13
|
+
ValueWithChangeEventFromObservable,
|
|
14
|
+
constObservable,
|
|
15
|
+
derived,
|
|
16
|
+
mapObservableArrayCached,
|
|
17
|
+
observableFromValueWithChangeEvent,
|
|
18
|
+
observableValue,
|
|
19
|
+
recomputeInitiallyAndOnChange,
|
|
20
|
+
} from '@opensumi/ide-monaco/lib/common/observable';
|
|
21
|
+
import { IMessageService } from '@opensumi/ide-overlay';
|
|
22
|
+
import { Dimension } from '@opensumi/monaco-editor-core/esm/vs/base/browser/dom';
|
|
23
|
+
import { ValueWithChangeEvent } from '@opensumi/monaco-editor-core/esm/vs/base/common/event';
|
|
24
|
+
import { ICodeEditor } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorBrowser';
|
|
25
|
+
import { RefCounted } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/widget/diffEditor/utils';
|
|
26
|
+
import {
|
|
27
|
+
IDocumentDiffItem,
|
|
28
|
+
IMultiDiffEditorModel,
|
|
29
|
+
} from '@opensumi/monaco-editor-core/esm/vs/editor/browser/widget/multiDiffEditor/model';
|
|
30
|
+
import { MultiDiffEditorWidget } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidget';
|
|
31
|
+
import { IMultiDiffResourceId } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl';
|
|
32
|
+
import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
|
|
33
|
+
import { IDiffEditor } from '@opensumi/monaco-editor-core/esm/vs/editor/common/editorCommon';
|
|
34
|
+
|
|
35
|
+
import { IEditorDocumentModelRef, IResourceOpenOptions } from '../../common/editor';
|
|
36
|
+
import { IMultiDiffEditor, IMultiDiffSourceResolverService, IResolvedMultiDiffSource } from '../../common/multi-diff';
|
|
37
|
+
import { EditorDocumentModelContentChangedEvent, IEditorDocumentModelService } from '../doc-model/types';
|
|
38
|
+
import { IConvertedMonacoOptions, IResource, ResourceDecorationNeedChangeEvent } from '../types';
|
|
39
|
+
|
|
40
|
+
@Injectable({ multiple: true })
|
|
41
|
+
export class BrowserMultiDiffEditor extends WithEventBus implements IMultiDiffEditor {
|
|
42
|
+
@Autowired(INJECTOR_TOKEN)
|
|
43
|
+
protected readonly injector: Injector;
|
|
44
|
+
|
|
45
|
+
@Autowired(IMessageService)
|
|
46
|
+
private readonly messageService: IMessageService;
|
|
47
|
+
|
|
48
|
+
@Autowired(IEditorDocumentModelService)
|
|
49
|
+
documentModelManager: IEditorDocumentModelService;
|
|
50
|
+
|
|
51
|
+
@Autowired(PreferenceService)
|
|
52
|
+
private readonly preferenceService: PreferenceService;
|
|
53
|
+
|
|
54
|
+
@Autowired(IMultiDiffSourceResolverService)
|
|
55
|
+
private readonly multiDiffSourceResolverService: IMultiDiffSourceResolverService;
|
|
56
|
+
|
|
57
|
+
private multiDiffModelChangeEmitter = new Emitter<IMultiDiffEditorModel>();
|
|
58
|
+
public readonly onMultiDiffModelChange = this.multiDiffModelChangeEmitter.event;
|
|
59
|
+
|
|
60
|
+
private viewStateMap: Map<string, any> = new Map();
|
|
61
|
+
private currentUri: URI | undefined;
|
|
62
|
+
|
|
63
|
+
private multiDiffModel: IMultiDiffEditorModel & IDisposable;
|
|
64
|
+
|
|
65
|
+
constructor(private multiDiffWidget: MultiDiffEditorWidget, private convertedOptions: IConvertedMonacoOptions) {
|
|
66
|
+
super();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@OnEvent(EditorDocumentModelContentChangedEvent)
|
|
70
|
+
onDocModelContentChangedEvent(e: EditorDocumentModelContentChangedEvent) {
|
|
71
|
+
if (!this.currentUri) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// TODO: 目前的设计下,不支持动态修改 resource 的 name,diff 数量变化时会有问题
|
|
75
|
+
if (
|
|
76
|
+
this.multiDiffModel?.documents.value === 'loading' ||
|
|
77
|
+
!this.multiDiffModel.documents.value.some(
|
|
78
|
+
(document) => document.object.modified?.uri.toString() === e.payload.uri.codeUri.toString(),
|
|
79
|
+
)
|
|
80
|
+
) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.eventBus.fire(
|
|
84
|
+
new ResourceDecorationNeedChangeEvent({
|
|
85
|
+
uri: this.currentUri,
|
|
86
|
+
decoration: {
|
|
87
|
+
dirty: !!e.payload.dirty,
|
|
88
|
+
readOnly: !!e.payload.readonly,
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private saveViewState(uri: URI) {
|
|
95
|
+
if (!uri) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const key = uri.toString();
|
|
99
|
+
const state = this.multiDiffWidget.getViewState();
|
|
100
|
+
if (state) {
|
|
101
|
+
this.viewStateMap.set(key, state);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private restoreViewState(uri: URI) {
|
|
106
|
+
if (!uri) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const key = uri.toString();
|
|
110
|
+
const state = this.viewStateMap.get(key);
|
|
111
|
+
if (state) {
|
|
112
|
+
this.multiDiffWidget.setViewState(state);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async compareMultiple(resource: IResource, options?: IResourceOpenOptions): Promise<void> {
|
|
117
|
+
// Save current view state before changing
|
|
118
|
+
if (this.currentUri) {
|
|
119
|
+
this.saveViewState(this.currentUri);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const source: IResolvedMultiDiffSource | undefined = resource.metadata.sources?.length
|
|
123
|
+
? { resources: ValueWithChangeEvent.const(resource.metadata.sources) }
|
|
124
|
+
: await this.multiDiffSourceResolverService.resolve(resource.uri);
|
|
125
|
+
const resources = source ? observableFromValueWithChangeEvent(this, source.resources) : constObservable([]);
|
|
126
|
+
|
|
127
|
+
const documentsWithPromises = mapObservableArrayCached(
|
|
128
|
+
this,
|
|
129
|
+
resources,
|
|
130
|
+
async (r, store) => {
|
|
131
|
+
/** @description documentsWithPromises */
|
|
132
|
+
let original: IEditorDocumentModelRef | undefined;
|
|
133
|
+
let modified: IEditorDocumentModelRef | undefined;
|
|
134
|
+
|
|
135
|
+
const multiDiffItemStore = new DisposableStore();
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
[original, modified] = await Promise.all([
|
|
139
|
+
r.originalUri ? this.documentModelManager.createModelReference(r.originalUri) : undefined,
|
|
140
|
+
r.modifiedUri ? this.documentModelManager.createModelReference(r.modifiedUri) : undefined,
|
|
141
|
+
]);
|
|
142
|
+
// console.log('original', original, 'modified', modified);
|
|
143
|
+
if (original) {
|
|
144
|
+
multiDiffItemStore.add(original);
|
|
145
|
+
}
|
|
146
|
+
if (modified) {
|
|
147
|
+
multiDiffItemStore.add(modified);
|
|
148
|
+
}
|
|
149
|
+
} catch (e) {
|
|
150
|
+
// e.g. "File seems to be binary and cannot be opened as text"
|
|
151
|
+
this.messageService.error(e.message);
|
|
152
|
+
// eslint-disable-next-line no-console
|
|
153
|
+
console.error(e);
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const uri = (r.modifiedUri ?? r.originalUri)!;
|
|
157
|
+
const result = {
|
|
158
|
+
multiDiffEditorItem: r,
|
|
159
|
+
original: original?.instance.getMonacoModel(),
|
|
160
|
+
modified: modified?.instance.getMonacoModel(),
|
|
161
|
+
contextKeys: r.contextKeys,
|
|
162
|
+
options: {
|
|
163
|
+
readOnly: modified?.instance.readonly,
|
|
164
|
+
// TODO: codelens,wordWrap options
|
|
165
|
+
...this.convertedOptions.diffOptions,
|
|
166
|
+
},
|
|
167
|
+
// TODO: 监听配置变化验证
|
|
168
|
+
onOptionsDidChange: (h) =>
|
|
169
|
+
this.preferenceService.onPreferenceChanged((e) => {
|
|
170
|
+
if (e.affects(uri.toString()) && e.preferenceName.includes('editor')) {
|
|
171
|
+
h();
|
|
172
|
+
}
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
return store.add(RefCounted.createOfNonDisposable(result, multiDiffItemStore, this));
|
|
176
|
+
},
|
|
177
|
+
(i) => JSON.stringify([i.modifiedUri?.toString(), i.originalUri?.toString()]),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const documents = observableValue<readonly RefCounted<IDocumentDiffItem>[] | 'loading'>('documents', 'loading');
|
|
181
|
+
|
|
182
|
+
const updateDocuments = derived(async (reader) => {
|
|
183
|
+
/** @description Update documents */
|
|
184
|
+
const docsPromises = documentsWithPromises.read(reader);
|
|
185
|
+
const docs = await Promise.all(docsPromises);
|
|
186
|
+
const newDocuments = docs.filter((item) => item !== undefined);
|
|
187
|
+
documents.set(newDocuments, undefined);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const a = recomputeInitiallyAndOnChange(updateDocuments);
|
|
191
|
+
await updateDocuments.get();
|
|
192
|
+
this.multiDiffModel?.dispose();
|
|
193
|
+
this.multiDiffModel = {
|
|
194
|
+
dispose: () => a.dispose(),
|
|
195
|
+
documents: new ValueWithChangeEventFromObservable(documents),
|
|
196
|
+
contextKeys: source?.contextKeys,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const viewModel = this.multiDiffWidget.createViewModel(this.multiDiffModel);
|
|
200
|
+
await viewModel.waitForDiffs();
|
|
201
|
+
this.multiDiffWidget.setViewModel(viewModel);
|
|
202
|
+
|
|
203
|
+
// Update current URI and restore view state
|
|
204
|
+
this.currentUri = resource.uri;
|
|
205
|
+
this.restoreViewState(resource.uri);
|
|
206
|
+
|
|
207
|
+
this.multiDiffModelChangeEmitter.fire(this.multiDiffModel);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
getDiffEntry(uri: URI): IDocumentDiffItem | undefined {
|
|
211
|
+
return this.multiDiffWidget.findDocumentDiffItem(uri.codeUri);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
getCurrentDiffEntry(): IDocumentDiffItem | undefined {
|
|
215
|
+
const activeControl = this.multiDiffWidget.getActiveControl();
|
|
216
|
+
if (!activeControl) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
const originalUri = activeControl.getOriginalEditor().getModel()?.uri;
|
|
220
|
+
if (!originalUri) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
return this.multiDiffWidget.findDocumentDiffItem(originalUri);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
reveal(resource: IMultiDiffResourceId, options?: { range?: Range; highlight: boolean }): void {
|
|
227
|
+
this.multiDiffWidget.reveal(resource, options);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
layout(dimension: Dimension): void {
|
|
231
|
+
this.multiDiffWidget.layout(dimension);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
focus(): void {
|
|
235
|
+
const activeControl = this.multiDiffWidget.getActiveControl();
|
|
236
|
+
if (activeControl) {
|
|
237
|
+
activeControl.focus();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
tryGetCodeEditor(uri: URI): { diffEditor: IDiffEditor; editor: ICodeEditor } | undefined {
|
|
242
|
+
return this.multiDiffWidget.tryGetCodeEditor(uri.codeUri);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
dispose(): void {
|
|
246
|
+
super.dispose();
|
|
247
|
+
this.multiDiffWidget.dispose();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { URI } from '@opensumi/ide-core-common';
|
|
3
|
+
import { ValueWithChangeEvent } from '@opensumi/monaco-editor-core/esm/vs/base/common/event';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
IMultiDiffSourceResolver,
|
|
7
|
+
IResolvedMultiDiffSource,
|
|
8
|
+
MULTI_DIFF_SCHEME,
|
|
9
|
+
MultiDiffEditorItem,
|
|
10
|
+
} from '../../common/multi-diff';
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class MultiDiffResolver implements IMultiDiffSourceResolver {
|
|
14
|
+
private readonly sourceValues = new Map<string, ValueWithChangeEvent<MultiDiffEditorItem[]>>();
|
|
15
|
+
|
|
16
|
+
registerSources(uri: URI, sources: MultiDiffEditorItem[]) {
|
|
17
|
+
const key = uri.toString();
|
|
18
|
+
const saved = this.sourceValues.get(key);
|
|
19
|
+
if (saved) {
|
|
20
|
+
saved.value = sources;
|
|
21
|
+
} else {
|
|
22
|
+
this.sourceValues.set(key, new ValueWithChangeEvent(sources));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
canHandleUri(uri: URI): boolean {
|
|
27
|
+
return uri.scheme === MULTI_DIFF_SCHEME;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async resolveDiffSource(uri: URI): Promise<IResolvedMultiDiffSource | undefined> {
|
|
31
|
+
const value = this.sourceValues.get(uri.toString());
|
|
32
|
+
if (!value) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
resources: value,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
dispose() {
|
|
42
|
+
this.sourceValues.clear();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { AppConfig, URI, WithEventBus, getIcon } from '@opensumi/ide-core-browser';
|
|
3
|
+
import { LabelService } from '@opensumi/ide-core-browser/lib/services';
|
|
4
|
+
import { IFileServiceClient } from '@opensumi/ide-file-service';
|
|
5
|
+
|
|
6
|
+
import { IResourceProvider, ResourceService } from '../../common';
|
|
7
|
+
import { IMultiDiffSourceResolverService } from '../../common/multi-diff';
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class MultiDiffResourceProvider extends WithEventBus implements IResourceProvider {
|
|
11
|
+
@Autowired()
|
|
12
|
+
labelService: LabelService;
|
|
13
|
+
|
|
14
|
+
@Autowired(ResourceService)
|
|
15
|
+
resourceService: ResourceService;
|
|
16
|
+
|
|
17
|
+
@Autowired(IFileServiceClient)
|
|
18
|
+
protected fileServiceClient: IFileServiceClient;
|
|
19
|
+
|
|
20
|
+
@Autowired(AppConfig)
|
|
21
|
+
protected readonly appConfig: AppConfig;
|
|
22
|
+
|
|
23
|
+
@Autowired(IMultiDiffSourceResolverService)
|
|
24
|
+
private readonly multiDiffSourceResolverService: IMultiDiffSourceResolverService;
|
|
25
|
+
|
|
26
|
+
handlesUri(uri: URI): number {
|
|
27
|
+
const resolvers = this.multiDiffSourceResolverService.getResolvers();
|
|
28
|
+
for (const resolver of resolvers) {
|
|
29
|
+
if (resolver.canHandleUri(uri)) {
|
|
30
|
+
return 10;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return -1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async provideResource(uri: URI) {
|
|
37
|
+
const { name, sources } = uri.getParsedQuery();
|
|
38
|
+
const parsedSources = sources ? JSON.parse(sources) : [];
|
|
39
|
+
|
|
40
|
+
// Get icon from the first modified file
|
|
41
|
+
const firstModifiedUri = parsedSources.length > 0 ? new URI(parsedSources[0].modifiedUri) : undefined;
|
|
42
|
+
const icon = firstModifiedUri ? this.labelService.getIcon(firstModifiedUri) : undefined;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
name: `Multi-Diff: ${name || parsedSources.length + ' files'}`,
|
|
46
|
+
icon: icon || getIcon('diff'),
|
|
47
|
+
uri,
|
|
48
|
+
supportsRevive: this.appConfig.enableDiffRevive ?? false,
|
|
49
|
+
metadata: {
|
|
50
|
+
sources: parsedSources,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async shouldCloseResource(resource, openedResources): Promise<boolean> {
|
|
56
|
+
// TODO: For now, always allow closing
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Autowired } from '@opensumi/di';
|
|
2
|
+
import { Domain, IDisposable, URI } from '@opensumi/ide-core-browser';
|
|
3
|
+
|
|
4
|
+
import { ResourceService } from '../../common';
|
|
5
|
+
import { IMultiDiffSourceResolverService, IResolvedMultiDiffSource, MULTI_DIFF_SCHEME } from '../../common/multi-diff';
|
|
6
|
+
import {
|
|
7
|
+
BrowserEditorContribution,
|
|
8
|
+
EditorComponentRegistry,
|
|
9
|
+
EditorOpenType,
|
|
10
|
+
MultiDiffSourceContribution,
|
|
11
|
+
} from '../types';
|
|
12
|
+
|
|
13
|
+
import { MultiDiffResolver } from './multi-diff-resolver';
|
|
14
|
+
import { MultiDiffResourceProvider } from './multi-diff-resource';
|
|
15
|
+
|
|
16
|
+
@Domain(BrowserEditorContribution, MultiDiffSourceContribution)
|
|
17
|
+
export class MultiDiffEditorContribution implements BrowserEditorContribution, MultiDiffSourceContribution {
|
|
18
|
+
@Autowired(IMultiDiffSourceResolverService)
|
|
19
|
+
private readonly multiDiffSourceResolverService: IMultiDiffSourceResolverService;
|
|
20
|
+
|
|
21
|
+
@Autowired(MultiDiffResolver)
|
|
22
|
+
private readonly multiDiffResolver: MultiDiffResolver;
|
|
23
|
+
|
|
24
|
+
@Autowired()
|
|
25
|
+
private readonly multiDiffResourceProvider: MultiDiffResourceProvider;
|
|
26
|
+
|
|
27
|
+
registerMultiDiffSourceResolver(resolverService: IMultiDiffSourceResolverService): IDisposable {
|
|
28
|
+
// 内置实现,通过 command 使用
|
|
29
|
+
return resolverService.registerResolver(this.multiDiffResolver);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
registerResource(resourceService: ResourceService): void {
|
|
33
|
+
resourceService.registerResourceProvider(this.multiDiffResourceProvider);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
registerEditorComponent(registry: EditorComponentRegistry) {
|
|
37
|
+
registry.registerEditorComponentResolver(
|
|
38
|
+
(scheme) => {
|
|
39
|
+
const resolvers = this.multiDiffSourceResolverService.getResolvers();
|
|
40
|
+
for (const resolver of resolvers) {
|
|
41
|
+
if (resolver.canHandleUri(new URI(`${scheme}:/empty`))) {
|
|
42
|
+
return 10;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return -1;
|
|
46
|
+
},
|
|
47
|
+
(resource, results) => {
|
|
48
|
+
results.push({
|
|
49
|
+
type: EditorOpenType.multiDiff,
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { IDisposable, URI, toDisposable } from '@opensumi/ide-utils';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
IMultiDiffSourceResolver,
|
|
6
|
+
IMultiDiffSourceResolverService,
|
|
7
|
+
IResolvedMultiDiffSource,
|
|
8
|
+
} from '../../common/multi-diff';
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
export class MultiDiffSourceResolverService implements IMultiDiffSourceResolverService {
|
|
12
|
+
private readonly _resolvers = new Set<IMultiDiffSourceResolver>();
|
|
13
|
+
|
|
14
|
+
registerResolver(resolver: IMultiDiffSourceResolver): IDisposable {
|
|
15
|
+
// throw on duplicate
|
|
16
|
+
if (this._resolvers.has(resolver)) {
|
|
17
|
+
throw new Error('Duplicate resolver');
|
|
18
|
+
}
|
|
19
|
+
this._resolvers.add(resolver);
|
|
20
|
+
return toDisposable(() => this._resolvers.delete(resolver));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
resolve(uri: URI): Promise<IResolvedMultiDiffSource | undefined> {
|
|
24
|
+
for (const resolver of this._resolvers) {
|
|
25
|
+
if (resolver.canHandleUri(uri)) {
|
|
26
|
+
return resolver.resolveDiffSource(uri);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return Promise.resolve(undefined);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getResolvers(): IMultiDiffSourceResolver[] {
|
|
33
|
+
return Array.from(this._resolvers);
|
|
34
|
+
}
|
|
35
|
+
}
|