Skip to content

Commit 15a420f

Browse files
committed
Improve MergeEditor#getControl so that the editor language status works (knows the editor/model to operate on). This opens a can of worms as other things start to work, e.g outline and breakcrumbs and that requires some "redirect magic" to ensure opening a symbol from outline/breakcrumbs stays within the merge editor...
fyi @bpasero @lramos15 I dynamically register/unregister an editor with the editor resolver service which I think is pretty bad but the only "contained/local" way I could find
1 parent c779574 commit 15a420f

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import { IAction } from 'vs/base/common/actions';
1010
import { CancellationToken } from 'vs/base/common/cancellation';
1111
import { Color } from 'vs/base/common/color';
1212
import { BugIndicatingError } from 'vs/base/common/errors';
13-
import { DisposableStore } from 'vs/base/common/lifecycle';
13+
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
14+
import { isEqual } from 'vs/base/common/resources';
1415
import { URI } from 'vs/base/common/uri';
1516
import 'vs/css!./media/mergeEditor';
16-
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
17+
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1718
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
1819
import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions';
1920
import { ScrollType } from 'vs/editor/common/editorCommon';
@@ -32,7 +33,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
3233
import { IThemeService } from 'vs/platform/theme/common/themeService';
3334
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
3435
import { AbstractTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
35-
import { IEditorOpenContext } from 'vs/workbench/common/editor';
36+
import { EditorInputWithOptions, EditorResourceAccessor, IEditorOpenContext } from 'vs/workbench/common/editor';
3637
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
3738
import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions';
3839
import { autorunWithStore, IObservable } from 'vs/workbench/contrib/audioCues/browser/observable';
@@ -43,6 +44,7 @@ import { ReentrancyBarrier, thenIfNotDisposed } from 'vs/workbench/contrib/merge
4344
import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel';
4445
import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
4546
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
47+
import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
4648
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
4749
import './colors';
4850
import { InputCodeEditorView } from './editors/inputCodeEditorView';
@@ -87,7 +89,8 @@ export class MergeEditor extends AbstractTextEditor<any> {
8789
@IConfigurationService private readonly _configurationService: IConfigurationService,
8890
@IEditorService editorService: IEditorService,
8991
@IEditorGroupsService editorGroupService: IEditorGroupsService,
90-
@IFileService fileService: IFileService
92+
@IFileService fileService: IFileService,
93+
@IEditorResolverService private readonly _editorResolverService: IEditorResolverService,
9194
) {
9295
super(MergeEditor.ID, telemetryService, instantiation, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService, fileService);
9396

@@ -230,6 +233,8 @@ export class MergeEditor extends AbstractTextEditor<any> {
230233
await super.setInput(input, options, context, token);
231234

232235
this._sessionDisposables.clear();
236+
this._toggleEditorOverwrite(true);
237+
233238
const model = await input.resolve();
234239
this._model = model;
235240

@@ -302,6 +307,7 @@ export class MergeEditor extends AbstractTextEditor<any> {
302307
super.clearInput();
303308

304309
this._sessionDisposables.clear();
310+
this._toggleEditorOverwrite(false);
305311

306312
for (const { editor } of [this.input1View, this.input2View, this.inputResultView]) {
307313
editor.setModel(null);
@@ -333,24 +339,50 @@ export class MergeEditor extends AbstractTextEditor<any> {
333339
}
334340

335341
this._ctxIsMergeEditor.set(visible);
342+
this._toggleEditorOverwrite(visible);
336343
}
337344

338-
// ---- interact with "outside world" via `getControl`, `scopedContextKeyService`
345+
private readonly _editorOverrideHandle = this._store.add(new MutableDisposable());
339346

340-
override getControl(): ICodeEditor | undefined {
341-
for (const { editor } of [this.input1View, this.input2View, this.inputResultView]) {
342-
if (editor.hasWidgetFocus()) {
343-
return editor;
344-
}
347+
private _toggleEditorOverwrite(haveIt: boolean) {
348+
if (!haveIt) {
349+
this._editorOverrideHandle.clear();
350+
return;
345351
}
346-
return undefined;
352+
// this is RATHER UGLY. I dynamically register an editor for THIS (editor,input) so that
353+
// navigating within the merge editor works, e.g navigating from the outline or breakcrumps
354+
// or revealing a definition, reference etc
355+
// TODO@jrieken @bpasero @lramos15
356+
const input = this.input;
357+
if (input instanceof MergeEditorInput) {
358+
this._editorOverrideHandle.value = this._editorResolverService.registerEditor(
359+
`${input.result.scheme}:${input.result.fsPath}`,
360+
{
361+
id: `${this.getId()}/fake`,
362+
label: this.input?.getName()!,
363+
priority: RegisteredEditorPriority.exclusive
364+
},
365+
{},
366+
(candidate): EditorInputWithOptions => {
367+
const resource = EditorResourceAccessor.getCanonicalUri(candidate);
368+
if (!isEqual(resource, this.model?.result.uri)) {
369+
throw new Error(`Expected to be called WITH ${input.result.toString()}`);
370+
}
371+
return { editor: input };
372+
}
373+
);
374+
}
375+
}
376+
377+
// ---- interact with "outside world" via`getControl`, `scopedContextKeyService`: we only expose the result-editor keep the others internal
378+
379+
override getControl(): ICodeEditor | undefined {
380+
return this.inputResultView.editor;
347381
}
348382

349383
override get scopedContextKeyService(): IContextKeyService | undefined {
350384
const control = this.getControl();
351-
return isCodeEditor(control)
352-
? control.invokeWithinContext(accessor => accessor.get(IContextKeyService))
353-
: undefined;
385+
return control?.invokeWithinContext(accessor => accessor.get(IContextKeyService));
354386
}
355387

356388
// --- layout

0 commit comments

Comments
 (0)