aux window - fixes for webview support (#207695)

This commit is contained in:
Benjamin Pasero 2024-03-14 15:08:47 +01:00 committed by GitHub
parent 8caaab7a3e
commit 686bdd6278
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 43 additions and 22 deletions

View file

@ -346,6 +346,8 @@ class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustom
// this seed.
readonly typeId = NO_TYPE_ID;
readonly isTextBased = false;
public static async create(
instantiationService: IInstantiationService,
proxy: extHostProtocol.ExtHostCustomEditorsShape,

View file

@ -349,10 +349,15 @@ export interface IInternalEditorCloseOptions extends IInternalEditorTitleControl
readonly context?: EditorCloseContext;
}
export interface IInternalMoveCopyOptions extends IInternalEditorOpenOptions {
export interface IInternalEditorMoveCopyOpenOptions extends IInternalEditorOpenOptions {
/**
* Whether to close the editor at the source or keep it.
*/
readonly keepCopy?: boolean;
/**
* The source group an editor is moved or copied from.
*/
readonly sourceGroup?: IEditorGroupView;
}

View file

@ -11,7 +11,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { Emitter, Relay } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, isAncestor, IDomNodePagePosition, isMouseEvent, isActiveElement, getWindow, getActiveElement } from 'vs/base/browser/dom';
import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, isAncestor, IDomNodePagePosition, isMouseEvent, isActiveElement, getWindow, getActiveElement, getWindowById } from 'vs/base/browser/dom';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
@ -28,7 +28,7 @@ import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { DeferredPromise, Promises, RunOnceWorker } from 'vs/base/common/async';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalEditorMoveCopyOpenOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IAction, SubmenuAction } from 'vs/base/common/actions';
@ -1049,7 +1049,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
});
}
private async doOpenEditor(editor: EditorInput, options?: IEditorOptions, internalOptions?: IInternalEditorOpenOptions): Promise<IEditorPane | undefined> {
private async doOpenEditor(editor: EditorInput, options?: IEditorOptions, internalOptions?: IInternalEditorMoveCopyOpenOptions): Promise<IEditorPane | undefined> {
// Guard against invalid editors. Disposed editors
// should never open because they emit no events
@ -1146,7 +1146,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return showEditorResult;
}
private doShowEditor(editor: EditorInput, context: { active: boolean; isNew: boolean }, options?: IEditorOptions, internalOptions?: IInternalEditorOpenOptions): Promise<IEditorPane | undefined> {
private doShowEditor(editor: EditorInput, context: { active: boolean; isNew: boolean }, options?: IEditorOptions, internalOptions?: IInternalEditorMoveCopyOpenOptions): Promise<IEditorPane | undefined> {
// Show in editor control if the active editor changed
let openEditorPromise: Promise<IEditorPane | undefined>;
@ -1253,7 +1253,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// through a method that allows for bulk updates but only
// when moving to a different group where many editors
// are more likely to occur.
const internalOptions: IInternalMoveCopyOptions = {
const internalOptions: IInternalEditorMoveCopyOpenOptions = {
skipTitleUpdate: this !== target
};
@ -1270,7 +1270,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
moveEditor(editor: EditorInput, target: EditorGroupView, options?: IEditorOptions, internalOptions?: IInternalMoveCopyOptions): void {
moveEditor(editor: EditorInput, target: EditorGroupView, options?: IEditorOptions, internalOptions?: IInternalEditorMoveCopyOpenOptions): void {
// Move within same group
if (this === target) {
@ -1320,7 +1320,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
private doMoveOrCopyEditorAcrossGroups(editor: EditorInput, target: EditorGroupView, openOptions?: IEditorOpenOptions, internalOptions?: IInternalMoveCopyOptions): void {
private doMoveOrCopyEditorAcrossGroups(editor: EditorInput, target: EditorGroupView, openOptions?: IEditorOpenOptions, internalOptions?: IInternalEditorMoveCopyOpenOptions): void {
const keepCopy = internalOptions?.keepCopy;
// When moving/copying an editor, try to preserve as much view state as possible
@ -1342,11 +1342,21 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
// A move to another group is an open first...
target.doOpenEditor(keepCopy ? editor.copy() : editor, options, internalOptions);
target.doOpenEditor(keepCopy ? editor.copy() : editor, options, { ...internalOptions, sourceGroup: this });
// ...and a close afterwards (unless we copy)
if (!keepCopy) {
this.doCloseEditor(editor, true /* do not focus next one behind if any */, { ...internalOptions, context: EditorCloseContext.MOVE });
let canCloseEditor = true;
if (
editor.hasCapability(EditorInputCapabilities.AuxWindowUnsupported) &&
getWindowById(target.windowId) !== getWindowById(this.windowId)
) {
canCloseEditor = false; // do not close the editor if it does not support aux windows
}
if (canCloseEditor) {
this.doCloseEditor(editor, true /* do not focus next one behind if any */, { ...internalOptions, context: EditorCloseContext.MOVE });
}
}
}
@ -1361,7 +1371,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// through a method that allows for bulk updates but only
// when moving to a different group where many editors
// are more likely to occur.
const internalOptions: IInternalMoveCopyOptions = {
const internalOptions: IInternalEditorMoveCopyOpenOptions = {
skipTitleUpdate: this !== target
};

View file

@ -17,7 +17,7 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress';
import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS, IInternalEditorOpenOptions } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS, IInternalEditorOpenOptions, IInternalEditorMoveCopyOpenOptions } from 'vs/workbench/browser/parts/editor/editor';
import { assertIsDefined } from 'vs/base/common/types';
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { ErrorPlaceholderEditor, IErrorEditorPlaceholderOptions, WorkspaceTrustRequiredPlaceholderEditor } from 'vs/workbench/browser/parts/editor/editorPlaceholder';
@ -28,7 +28,6 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IDialogService, IPromptButton, IPromptCancelButton } from 'vs/platform/dialogs/common/dialogs';
import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { mainWindow } from 'vs/base/browser/window';
export interface IOpenEditorResult {
@ -127,12 +126,12 @@ export class EditorPanes extends Disposable {
}
}
async openEditor(editor: EditorInput, options: IEditorOptions | undefined, internalOptions: IInternalEditorOpenOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise<IOpenEditorResult> {
async openEditor(editor: EditorInput, options: IEditorOptions | undefined, internalOptions: IInternalEditorMoveCopyOpenOptions | undefined, context: IEditorOpenContext = Object.create(null)): Promise<IOpenEditorResult> {
try {
// Assert the `EditorInputCapabilities.AuxWindowUnsupported` condition
if (getWindowById(this.groupView.windowId, true).window !== mainWindow && editor.hasCapability(EditorInputCapabilities.AuxWindowUnsupported)) {
return await this.doShowError(createEditorOpenError(localize('editorUnsupportedInAuxWindow', "This type of editor cannot be opened in other windows yet."), [
if (getWindowById(this.groupView.windowId) !== getWindowById(internalOptions?.sourceGroup?.windowId, true) && editor.hasCapability(EditorInputCapabilities.AuxWindowUnsupported)) {
return await this.doShowError(createEditorOpenError(localize('editorUnsupportedInAuxWindow', "Save the editor first before opening in this window."), [
toAction({
id: 'workbench.editor.action.closeEditor', label: localize('openFolder', "Close Editor"), run: async () => {
return this.groupView.closeEditor(editor);

View file

@ -793,7 +793,7 @@ export const enum EditorInputCapabilities {
/**
* Signals that the editor does not support opening in
* auxiliary windows yet.
* auxiliary windows.
*/
AuxWindowUnsupported = 1 << 10
}

View file

@ -152,10 +152,13 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput {
if (this.resource.scheme === Schemas.untitled) {
capabilities |= EditorInputCapabilities.Untitled;
capabilities |= EditorInputCapabilities.AuxWindowUnsupported;
}
if (this.isDirty()) {
if (this.isModified() && !this._modelRef?.object.isTextBased && !this.backupId) {
// Non-text based modified custom editors without associated
// backup should prevent to be moved across windows to prevent
// data loss. Their modified state is potentially stored within
// the `iframe` which will reset when moved across windows.
capabilities |= EditorInputCapabilities.AuxWindowUnsupported;
}

View file

@ -57,6 +57,7 @@ export interface ICustomEditorModel extends IDisposable {
readonly viewType: string;
readonly resource: URI;
readonly backupId: string | undefined;
readonly isTextBased: boolean;
isReadonly(): boolean | IMarkdownString;
readonly onDidChangeReadonly: Event<void>;

View file

@ -16,6 +16,8 @@ import { ITextFileEditorModel, ITextFileService, TextFileEditorModelState } from
export class CustomTextEditorModel extends Disposable implements ICustomEditorModel {
readonly isTextBased = true;
public static async create(
instantiationService: IInstantiationService,
viewType: string,

View file

@ -34,7 +34,7 @@ export class ExtensionsInput extends EditorInput {
}
override get capabilities(): EditorInputCapabilities {
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton | EditorInputCapabilities.AuxWindowUnsupported;
return EditorInputCapabilities.Readonly | EditorInputCapabilities.Singleton;
}
override get resource() {

View file

@ -815,8 +815,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
}
try {
this.element.parentElement?.focus(); // this helps to move floating windows to the front if any...
this.element.contentWindow?.focus(); // ...because `contentWindow` is not able to do so
this.element.contentWindow?.focus();
} catch {
// noop
}