mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-08 09:38:26 -05:00
Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c (#8525)
* Merge from vscode a5cf1da01d5db3d2557132be8d30f89c38019f6c * remove files we don't want * fix hygiene * update distro * update distro * fix hygiene * fix strict nulls * distro * distro * fix tests * fix tests * add another edit * fix viewlet icon * fix azure dialog * fix some padding * fix more padding issues
This commit is contained in:
@@ -10,19 +10,24 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { ICompositeControl } from 'vs/workbench/common/composite';
|
||||
import { ActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IPathData } from 'vs/platform/windows/common/windows';
|
||||
import { coalesce, firstOrDefault } from 'vs/base/common/arrays';
|
||||
import { ITextFileSaveOptions, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { IPanel } from 'vs/workbench/common/panel';
|
||||
|
||||
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false);
|
||||
export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null);
|
||||
export const ActiveEditorIsSaveableContext = new RawContextKey<boolean>('activeEditorIsSaveable', false);
|
||||
export const ActiveEditorIsReadonlyContext = new RawContextKey<boolean>('activeEditorIsReadonly', false);
|
||||
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false);
|
||||
export const EditorPinnedContext = new RawContextKey<boolean>('editorPinned', false);
|
||||
export const EditorGroupActiveEditorDirtyContext = new RawContextKey<boolean>('groupActiveEditorDirty', false);
|
||||
@@ -50,7 +55,7 @@ export const TEXT_DIFF_EDITOR_ID = 'workbench.editors.textDiffEditor';
|
||||
*/
|
||||
export const BINARY_DIFF_EDITOR_ID = 'workbench.editors.binaryResourceDiffEditor';
|
||||
|
||||
export interface IEditor {
|
||||
export interface IEditor extends IPanel {
|
||||
|
||||
/**
|
||||
* The assigned input of this editor.
|
||||
@@ -92,21 +97,11 @@ export interface IEditor {
|
||||
*/
|
||||
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined>;
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this editor.
|
||||
*/
|
||||
getId(): string;
|
||||
|
||||
/**
|
||||
* Returns the underlying control of this editor.
|
||||
*/
|
||||
getControl(): IEditorControl | undefined;
|
||||
|
||||
/**
|
||||
* Asks the underlying control to focus.
|
||||
*/
|
||||
focus(): void;
|
||||
|
||||
/**
|
||||
* Finds out if this editor is visible or not.
|
||||
*/
|
||||
@@ -119,6 +114,17 @@ export interface ITextEditor extends IEditor {
|
||||
* Returns the underlying text editor widget of this editor.
|
||||
*/
|
||||
getControl(): ICodeEditor | undefined;
|
||||
|
||||
/**
|
||||
* Returns the current view state of the text editor if any.
|
||||
*/
|
||||
getViewState(): IEditorViewState | undefined;
|
||||
}
|
||||
|
||||
export function isTextEditor(thing: IEditor | undefined): thing is ITextEditor {
|
||||
const candidate = thing as ITextEditor | undefined;
|
||||
|
||||
return typeof candidate?.getViewState === 'function';
|
||||
}
|
||||
|
||||
export interface ITextDiffEditor extends IEditor {
|
||||
@@ -175,7 +181,7 @@ export interface IEditorInputFactoryRegistry {
|
||||
* @param editorInputId the identifier of the editor input
|
||||
* @param factory the editor input factory for serialization/deserialization
|
||||
*/
|
||||
registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0<IEditorInputFactory>): void;
|
||||
registerEditorInputFactory<Services extends BrandedService[]>(editorInputId: string, ctor: { new(...Services: Services): IEditorInputFactory }): void;
|
||||
|
||||
/**
|
||||
* Returns the editor input factory for the given editor input.
|
||||
@@ -205,11 +211,11 @@ export interface IEditorInputFactory {
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined;
|
||||
}
|
||||
|
||||
export interface IUntitledResourceInput extends IBaseResourceInput {
|
||||
export interface IUntitledTextResourceInput extends IBaseResourceInput {
|
||||
|
||||
/**
|
||||
* Optional resource. If the resource is not provided a new untitled file is created (e.g. Untitled-1).
|
||||
* Otherwise the untitled editor will have an associated path and use that when saving.
|
||||
* Otherwise the untitled text editor will have an associated path and use that when saving.
|
||||
*/
|
||||
resource?: URI;
|
||||
|
||||
@@ -261,15 +267,67 @@ export const enum Verbosity {
|
||||
LONG
|
||||
}
|
||||
|
||||
export interface IRevertOptions {
|
||||
export const enum SaveReason {
|
||||
|
||||
/**
|
||||
* Forces to load the contents of the editor again even if the editor is not dirty.
|
||||
* Explicit user gesture.
|
||||
*/
|
||||
EXPLICIT = 1,
|
||||
|
||||
/**
|
||||
* Auto save after a timeout.
|
||||
*/
|
||||
AUTO = 2,
|
||||
|
||||
/**
|
||||
* Auto save after editor focus change.
|
||||
*/
|
||||
FOCUS_CHANGE = 3,
|
||||
|
||||
/**
|
||||
* Auto save after window change.
|
||||
*/
|
||||
WINDOW_CHANGE = 4
|
||||
}
|
||||
|
||||
export interface ISaveOptions {
|
||||
|
||||
/**
|
||||
* An indicator how the save operation was triggered.
|
||||
*/
|
||||
reason?: SaveReason;
|
||||
|
||||
/**
|
||||
* Forces to load the contents of the working copy
|
||||
* again even if the working copy is not dirty.
|
||||
*/
|
||||
force?: boolean;
|
||||
|
||||
/**
|
||||
* A soft revert will clear dirty state of an editor but will not attempt to load it.
|
||||
* Instructs the save operation to skip any save participants.
|
||||
*/
|
||||
skipSaveParticipants?: boolean;
|
||||
|
||||
/**
|
||||
* A hint as to which file systems should be available for saving.
|
||||
*/
|
||||
availableFileSystems?: string[];
|
||||
}
|
||||
|
||||
export interface IRevertOptions {
|
||||
|
||||
/**
|
||||
* Forces to load the contents of the working copy
|
||||
* again even if the working copy is not dirty.
|
||||
*/
|
||||
force?: boolean;
|
||||
|
||||
/**
|
||||
* A soft revert will clear dirty state of a working copy
|
||||
* but will not attempt to load it from its persisted state.
|
||||
*
|
||||
* This option may be used in scenarios where an editor is
|
||||
* closed and where we do not require to load the contents.
|
||||
*/
|
||||
soft?: boolean;
|
||||
}
|
||||
@@ -279,7 +337,7 @@ export interface IEditorInput extends IDisposable {
|
||||
/**
|
||||
* Triggered when this input is disposed.
|
||||
*/
|
||||
onDispose: Event<void>;
|
||||
readonly onDispose: Event<void>;
|
||||
|
||||
/**
|
||||
* Returns the associated resource of this input.
|
||||
@@ -294,7 +352,7 @@ export interface IEditorInput extends IDisposable {
|
||||
/**
|
||||
* Returns the display name of this input.
|
||||
*/
|
||||
getName(): string | undefined;
|
||||
getName(): string;
|
||||
|
||||
/**
|
||||
* Returns the display description of this input.
|
||||
@@ -311,11 +369,40 @@ export interface IEditorInput extends IDisposable {
|
||||
*/
|
||||
resolve(): Promise<IEditorModel | null>;
|
||||
|
||||
/**
|
||||
* Returns if this input is readonly or not.
|
||||
*/
|
||||
isReadonly(): boolean;
|
||||
|
||||
/**
|
||||
* Returns if the input is an untitled editor or not.
|
||||
*/
|
||||
isUntitled(): boolean;
|
||||
|
||||
/**
|
||||
* Returns if this input is dirty or not.
|
||||
*/
|
||||
isDirty(): boolean;
|
||||
|
||||
/**
|
||||
* Saves the editor. The provided groupId helps
|
||||
* implementors to e.g. preserve view state of the editor
|
||||
* and re-open it in the correct group after saving.
|
||||
*/
|
||||
save(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Saves the editor to a different location. The provided groupId
|
||||
* helps implementors to e.g. preserve view state of the editor
|
||||
* and re-open it in the correct group after saving.
|
||||
*/
|
||||
saveAs(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Handles when the input is replaced, such as by renaming its backing resource.
|
||||
*/
|
||||
handleMove?(groupId: GroupIdentifier, uri: URI, options?: ITextEditorOptions): IEditorInput | undefined;
|
||||
|
||||
/**
|
||||
* Reverts this input.
|
||||
*/
|
||||
@@ -325,6 +412,11 @@ export interface IEditorInput extends IDisposable {
|
||||
* Returns if the other object matches this input.
|
||||
*/
|
||||
matches(other: unknown): boolean;
|
||||
|
||||
/**
|
||||
* Returns if this editor is disposed.
|
||||
*/
|
||||
isDisposed(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,50 +425,32 @@ export interface IEditorInput extends IDisposable {
|
||||
*/
|
||||
export abstract class EditorInput extends Disposable implements IEditorInput {
|
||||
|
||||
protected readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty: Event<void> = this._onDidChangeDirty.event;
|
||||
protected readonly _onDidChangeDirty = this._register(new Emitter<void>());
|
||||
readonly onDidChangeDirty = this._onDidChangeDirty.event;
|
||||
|
||||
protected readonly _onDidChangeLabel: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeLabel: Event<void> = this._onDidChangeLabel.event;
|
||||
protected readonly _onDidChangeLabel = this._register(new Emitter<void>());
|
||||
readonly onDidChangeLabel = this._onDidChangeLabel.event;
|
||||
|
||||
private readonly _onDispose: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDispose: Event<void> = this._onDispose.event;
|
||||
private readonly _onDispose = this._register(new Emitter<void>());
|
||||
readonly onDispose = this._onDispose.event;
|
||||
|
||||
private disposed: boolean = false;
|
||||
|
||||
/**
|
||||
* Returns the unique type identifier of this input.
|
||||
*/
|
||||
abstract getTypeId(): string;
|
||||
|
||||
/**
|
||||
* Returns the associated resource of this input if any.
|
||||
*/
|
||||
getResource(): URI | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this input that can be shown to the user. Examples include showing the name of the input
|
||||
* above the editor area when the input is shown.
|
||||
*/
|
||||
getName(): string | undefined {
|
||||
return undefined;
|
||||
getName(): string {
|
||||
return `Editor ${this.getTypeId()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of this input that can be shown to the user. Examples include showing the description of
|
||||
* the input above the editor area to the side of the name of the input.
|
||||
*/
|
||||
getDescription(verbosity?: Verbosity): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of this input that can be shown to the user. Examples include showing the title of
|
||||
* the input above the editor area as hover over the input label.
|
||||
*/
|
||||
getTitle(verbosity?: Verbosity): string | undefined {
|
||||
getTitle(verbosity?: Verbosity): string {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
@@ -389,10 +463,10 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a descriptor suitable for telemetry events.
|
||||
*
|
||||
* Subclasses should extend if they can contribute.
|
||||
*/
|
||||
* Returns a descriptor suitable for telemetry events.
|
||||
*
|
||||
* Subclasses should extend if they can contribute.
|
||||
*/
|
||||
getTelemetryDescriptor(): { [key: string]: unknown } {
|
||||
/* __GDPR__FRAGMENT__
|
||||
"EditorTelemetryDescriptor" : {
|
||||
@@ -408,41 +482,30 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
|
||||
*/
|
||||
abstract resolve(): Promise<IEditorModel | null>;
|
||||
|
||||
/**
|
||||
* An editor that is dirty will be asked to be saved once it closes.
|
||||
*/
|
||||
isReadonly(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isUntitled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
isDirty(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result.
|
||||
*/
|
||||
confirmSave(): Promise<ConfirmResult> {
|
||||
return Promise.resolve(ConfirmResult.DONT_SAVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
|
||||
*/
|
||||
save(): Promise<boolean> {
|
||||
save(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
saveAs(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
|
||||
*/
|
||||
revert(options?: IRevertOptions): Promise<boolean> {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this input is no longer opened in any editor. Subclasses can free resources as needed.
|
||||
*/
|
||||
close(): void {
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can set this to false if it does not make sense to split the editor input.
|
||||
*/
|
||||
@@ -450,24 +513,14 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this input is identical to the otherInput.
|
||||
*/
|
||||
matches(otherInput: unknown): boolean {
|
||||
return this === otherInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this input was disposed or not.
|
||||
*/
|
||||
isDisposed(): boolean {
|
||||
return this.disposed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an editor input is no longer needed. Allows to free up any resources taken by
|
||||
* resolving the editor input.
|
||||
*/
|
||||
dispose(): void {
|
||||
this.disposed = true;
|
||||
this._onDispose.fire();
|
||||
@@ -476,10 +529,61 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
|
||||
}
|
||||
}
|
||||
|
||||
export const enum ConfirmResult {
|
||||
SAVE,
|
||||
DONT_SAVE,
|
||||
CANCEL
|
||||
export abstract class TextEditorInput extends EditorInput {
|
||||
|
||||
constructor(
|
||||
protected readonly resource: URI,
|
||||
@IEditorService protected readonly editorService: IEditorService,
|
||||
@IEditorGroupsService protected readonly editorGroupService: IEditorGroupsService,
|
||||
@ITextFileService protected readonly textFileService: ITextFileService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
async save(groupId: GroupIdentifier, options?: ITextFileSaveOptions): Promise<boolean> {
|
||||
if (this.isReadonly()) {
|
||||
return false; // return early if editor is readonly
|
||||
}
|
||||
|
||||
return this.textFileService.save(this.resource, options);
|
||||
}
|
||||
|
||||
saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<boolean> {
|
||||
return this.doSaveAs(group, () => this.textFileService.saveAs(this.resource, undefined, options));
|
||||
}
|
||||
|
||||
protected async doSaveAs(group: GroupIdentifier, saveRunnable: () => Promise<URI | undefined>, replaceAllEditors?: boolean): Promise<boolean> {
|
||||
|
||||
// Preserve view state by opening the editor first. In addition
|
||||
// this allows the user to review the contents of the editor.
|
||||
let viewState: IEditorViewState | undefined = undefined;
|
||||
const editor = await this.editorService.openEditor(this, undefined, group);
|
||||
if (isTextEditor(editor)) {
|
||||
viewState = editor.getViewState();
|
||||
}
|
||||
|
||||
// Save as
|
||||
const target = await saveRunnable();
|
||||
if (!target) {
|
||||
return false; // save cancelled
|
||||
}
|
||||
|
||||
// Replace editor preserving viewstate (either across all groups or
|
||||
// only selected group) if the target is different from the current resource
|
||||
if (!isEqual(target, this.resource)) {
|
||||
const replacement = this.editorService.createInput({ resource: target });
|
||||
const targetGroups = replaceAllEditors ? this.editorGroupService.groups.map(group => group.id) : [group];
|
||||
for (const group of targetGroups) {
|
||||
await this.editorService.replaceEditors([{ editor: this, replacement, options: { pinned: true, viewState } }], group);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export const enum EncodingMode {
|
||||
@@ -569,20 +673,28 @@ export class SideBySideEditorInput extends EditorInput {
|
||||
return this._details;
|
||||
}
|
||||
|
||||
isReadonly(): boolean {
|
||||
return this.master.isReadonly();
|
||||
}
|
||||
|
||||
isUntitled(): boolean {
|
||||
return this.master.isUntitled();
|
||||
}
|
||||
|
||||
isDirty(): boolean {
|
||||
return this.master.isDirty();
|
||||
}
|
||||
|
||||
confirmSave(): Promise<ConfirmResult> {
|
||||
return this.master.confirmSave();
|
||||
save(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
return this.master.save(groupId, options);
|
||||
}
|
||||
|
||||
save(): Promise<boolean> {
|
||||
return this.master.save();
|
||||
saveAs(groupId: GroupIdentifier, options?: ISaveOptions): Promise<boolean> {
|
||||
return this.master.saveAs(groupId, options);
|
||||
}
|
||||
|
||||
revert(): Promise<boolean> {
|
||||
return this.master.revert();
|
||||
revert(options?: IRevertOptions): Promise<boolean> {
|
||||
return this.master.revert(options);
|
||||
}
|
||||
|
||||
getTelemetryDescriptor(): { [key: string]: unknown } {
|
||||
@@ -657,8 +769,8 @@ export interface ITextEditorModel extends IEditorModel {
|
||||
*/
|
||||
export class EditorModel extends Disposable implements IEditorModel {
|
||||
|
||||
private readonly _onDispose: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDispose: Event<void> = this._onDispose.event;
|
||||
private readonly _onDispose = this._register(new Emitter<void>());
|
||||
readonly onDispose = this._onDispose.event;
|
||||
|
||||
/**
|
||||
* Causes this model to load returning a promise when loading is completed.
|
||||
@@ -1149,7 +1261,7 @@ export const Extensions = {
|
||||
|
||||
Registry.add(Extensions.EditorInputFactories, new EditorInputFactoryRegistry());
|
||||
|
||||
export async function pathsToEditors(paths: IPathData[] | undefined, fileService: IFileService): Promise<(IResourceInput | IUntitledResourceInput)[]> {
|
||||
export async function pathsToEditors(paths: IPathData[] | undefined, fileService: IFileService): Promise<(IResourceInput | IUntitledTextResourceInput)[]> {
|
||||
if (!paths || !paths.length) {
|
||||
return [];
|
||||
}
|
||||
@@ -1170,7 +1282,7 @@ export async function pathsToEditors(paths: IPathData[] | undefined, fileService
|
||||
};
|
||||
}
|
||||
|
||||
let input: IResourceInput | IUntitledResourceInput;
|
||||
let input: IResourceInput | IUntitledTextResourceInput;
|
||||
if (!exists) {
|
||||
input = { resource, options, forceUntitled: true };
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user