mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
joh/issue151136 (#153101)
* Implement `ILanguageSupport#setLanguageId` for merge editor input. With this the editor langauge status shows (but doesn't do anything yet) * 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
This commit is contained in:
@@ -16,7 +16,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput';
|
||||
import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ILanguageSupport, ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
export class MergeEditorInputData {
|
||||
constructor(
|
||||
@@ -27,7 +27,7 @@ export class MergeEditorInputData {
|
||||
) { }
|
||||
}
|
||||
|
||||
export class MergeEditorInput extends AbstractTextResourceEditorInput {
|
||||
export class MergeEditorInput extends AbstractTextResourceEditorInput implements ILanguageSupport {
|
||||
|
||||
static readonly ID = 'mergeEditor.Input';
|
||||
|
||||
@@ -140,6 +140,9 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput {
|
||||
return Boolean(this._outTextModel?.isDirty());
|
||||
}
|
||||
|
||||
setLanguageId(languageId: string, _setExplicitly?: boolean): void {
|
||||
this._model?.setLanguageId(languageId);
|
||||
}
|
||||
|
||||
// implement get/set languageId
|
||||
// implement get/set encoding
|
||||
|
||||
@@ -20,6 +20,8 @@ import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRa
|
||||
import { TextModelDiffChangeReason, TextModelDiffs, TextModelDiffState } from 'vs/workbench/contrib/mergeEditor/browser/model/textModelDiffs';
|
||||
import { concatArrays, leftJoin, elementAtOrUndefined } from 'vs/workbench/contrib/mergeEditor/browser/utils';
|
||||
import { ModifiedBaseRange, ModifiedBaseRangeState } from './modifiedBaseRange';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
|
||||
export const enum MergeEditorModelState {
|
||||
initializing = 1,
|
||||
@@ -134,7 +136,9 @@ export class MergeEditorModel extends EditorModel {
|
||||
readonly input2Detail: string | undefined,
|
||||
readonly input2Description: string | undefined,
|
||||
readonly result: ITextModel,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
@IModelService private readonly modelService: IModelService,
|
||||
@ILanguageService private readonly languageService: ILanguageService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -329,6 +333,10 @@ export class MergeEditorModel extends EditorModel {
|
||||
public setHandled(baseRange: ModifiedBaseRange, handled: boolean, tx: ITransaction): void {
|
||||
this.modifiedBaseRangeHandlingStateStores.get().get(baseRange)!.set(handled, tx);
|
||||
}
|
||||
|
||||
public setLanguageId(languageId: string): void {
|
||||
this.modelService.setMode(this.result, this.languageService.createById(languageId));
|
||||
}
|
||||
}
|
||||
|
||||
function getEditForBase(baseRange: ModifiedBaseRange, state: ModifiedBaseRangeState): { edit: LineRangeEdit | undefined; effectiveState: ModifiedBaseRangeState } {
|
||||
|
||||
@@ -10,10 +10,11 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { BugIndicatingError } from 'vs/base/common/errors';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/mergeEditor';
|
||||
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
@@ -32,7 +33,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { AbstractTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorInputWithOptions, EditorResourceAccessor, IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions';
|
||||
import { autorunWithStore, IObservable } from 'vs/workbench/contrib/audioCues/browser/observable';
|
||||
@@ -43,6 +44,7 @@ import { ReentrancyBarrier, thenIfNotDisposed } from 'vs/workbench/contrib/merge
|
||||
import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel';
|
||||
import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorResolverService, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import './colors';
|
||||
import { InputCodeEditorView } from './editors/inputCodeEditorView';
|
||||
@@ -87,7 +89,8 @@ export class MergeEditor extends AbstractTextEditor<any> {
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@IFileService fileService: IFileService
|
||||
@IFileService fileService: IFileService,
|
||||
@IEditorResolverService private readonly _editorResolverService: IEditorResolverService,
|
||||
) {
|
||||
super(MergeEditor.ID, telemetryService, instantiation, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService, fileService);
|
||||
|
||||
@@ -230,6 +233,8 @@ export class MergeEditor extends AbstractTextEditor<any> {
|
||||
await super.setInput(input, options, context, token);
|
||||
|
||||
this._sessionDisposables.clear();
|
||||
this._toggleEditorOverwrite(true);
|
||||
|
||||
const model = await input.resolve();
|
||||
this._model = model;
|
||||
|
||||
@@ -302,6 +307,7 @@ export class MergeEditor extends AbstractTextEditor<any> {
|
||||
super.clearInput();
|
||||
|
||||
this._sessionDisposables.clear();
|
||||
this._toggleEditorOverwrite(false);
|
||||
|
||||
for (const { editor } of [this.input1View, this.input2View, this.inputResultView]) {
|
||||
editor.setModel(null);
|
||||
@@ -333,24 +339,50 @@ export class MergeEditor extends AbstractTextEditor<any> {
|
||||
}
|
||||
|
||||
this._ctxIsMergeEditor.set(visible);
|
||||
this._toggleEditorOverwrite(visible);
|
||||
}
|
||||
|
||||
// ---- interact with "outside world" via `getControl`, `scopedContextKeyService`
|
||||
private readonly _editorOverrideHandle = this._store.add(new MutableDisposable());
|
||||
|
||||
private _toggleEditorOverwrite(haveIt: boolean) {
|
||||
if (!haveIt) {
|
||||
this._editorOverrideHandle.clear();
|
||||
return;
|
||||
}
|
||||
// this is RATHER UGLY. I dynamically register an editor for THIS (editor,input) so that
|
||||
// navigating within the merge editor works, e.g navigating from the outline or breakcrumps
|
||||
// or revealing a definition, reference etc
|
||||
// TODO@jrieken @bpasero @lramos15
|
||||
const input = this.input;
|
||||
if (input instanceof MergeEditorInput) {
|
||||
this._editorOverrideHandle.value = this._editorResolverService.registerEditor(
|
||||
`${input.result.scheme}:${input.result.fsPath}`,
|
||||
{
|
||||
id: `${this.getId()}/fake`,
|
||||
label: this.input?.getName()!,
|
||||
priority: RegisteredEditorPriority.exclusive
|
||||
},
|
||||
{},
|
||||
(candidate): EditorInputWithOptions => {
|
||||
const resource = EditorResourceAccessor.getCanonicalUri(candidate);
|
||||
if (!isEqual(resource, this.model?.result.uri)) {
|
||||
throw new Error(`Expected to be called WITH ${input.result.toString()}`);
|
||||
}
|
||||
return { editor: input };
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- interact with "outside world" via`getControl`, `scopedContextKeyService`: we only expose the result-editor keep the others internal
|
||||
|
||||
override getControl(): ICodeEditor | undefined {
|
||||
for (const { editor } of [this.input1View, this.input2View, this.inputResultView]) {
|
||||
if (editor.hasWidgetFocus()) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
return this.inputResultView.editor;
|
||||
}
|
||||
|
||||
override get scopedContextKeyService(): IContextKeyService | undefined {
|
||||
const control = this.getControl();
|
||||
return isCodeEditor(control)
|
||||
? control.invokeWithinContext(accessor => accessor.get(IContextKeyService))
|
||||
: undefined;
|
||||
return control?.invokeWithinContext(accessor => accessor.get(IContextKeyService));
|
||||
}
|
||||
|
||||
// --- layout
|
||||
|
||||
Reference in New Issue
Block a user