mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -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:
@@ -3,11 +3,14 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export interface IActivity {
|
||||
id: string;
|
||||
name: string;
|
||||
keybindingId?: string;
|
||||
cssClass?: string;
|
||||
iconUrl?: URI;
|
||||
}
|
||||
|
||||
export const GLOBAL_ACTIVITY_ID = 'workbench.action.globalActivity';
|
||||
export const GLOBAL_ACTIVITY_ID = 'workbench.action.globalActivity';
|
||||
|
||||
@@ -4,9 +4,20 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAction, IActionViewItem } from 'vs/base/common/actions';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export interface IComposite {
|
||||
|
||||
/**
|
||||
* An event when the composite gained focus.
|
||||
*/
|
||||
readonly onDidFocus: Event<void>;
|
||||
|
||||
/**
|
||||
* An event when the composite lost focus.
|
||||
*/
|
||||
readonly onDidBlur: Event<void>;
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of this composite.
|
||||
*/
|
||||
|
||||
14
src/vs/workbench/common/configuration.ts
Normal file
14
src/vs/workbench/common/configuration.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
||||
export const workbenchConfigurationNodeBase = Object.freeze<IConfigurationNode>({
|
||||
'id': 'workbench',
|
||||
'order': 7,
|
||||
'title': localize('workbenchConfigurationTitle', "Workbench"),
|
||||
'type': 'object',
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IInstantiationService, IConstructorSignature0, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { runWhenIdle, IdleDeadline } from 'vs/base/common/async';
|
||||
@@ -19,7 +19,7 @@ export namespace Extensions {
|
||||
export const Workbench = 'workbench.contributions.kind';
|
||||
}
|
||||
|
||||
export type IWorkbenchContributionSignature = IConstructorSignature0<IWorkbenchContribution>;
|
||||
type IWorkbenchContributionSignature<Service extends BrandedService[]> = new (...services: Service) => IWorkbenchContribution;
|
||||
|
||||
export interface IWorkbenchContributionsRegistry {
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface IWorkbenchContributionsRegistry {
|
||||
*
|
||||
* @param phase the lifecycle phase when to instantiate the contribution.
|
||||
*/
|
||||
registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void;
|
||||
registerWorkbenchContribution<Services extends BrandedService[]>(contribution: IWorkbenchContributionSignature<Services>, phase: LifecyclePhase): void;
|
||||
|
||||
/**
|
||||
* Starts the registry by providing the required services.
|
||||
@@ -43,8 +43,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry
|
||||
|
||||
private readonly toBeInstantiated: Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]> = new Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]>();
|
||||
|
||||
registerWorkbenchContribution(ctor: IWorkbenchContributionSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void {
|
||||
|
||||
registerWorkbenchContribution<Services extends BrandedService[]>(ctor: { new(...services: Services): IWorkbenchContribution }, phase: LifecyclePhase = LifecyclePhase.Starting): void {
|
||||
// Instantiate directly if we are already matching the provided phase
|
||||
if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) {
|
||||
this.instantiationService.createInstance(ctor);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
import { EditorModel } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { DataUri, basename } from 'vs/base/common/resources';
|
||||
import { MIME_BINARY } from 'vs/base/common/mime';
|
||||
|
||||
/**
|
||||
@@ -19,8 +17,8 @@ export class BinaryEditorModel extends EditorModel {
|
||||
private readonly mime: string;
|
||||
|
||||
constructor(
|
||||
private readonly resource: URI,
|
||||
private readonly name: string | undefined,
|
||||
public readonly resource: URI,
|
||||
private readonly name: string,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
@@ -28,32 +26,13 @@ export class BinaryEditorModel extends EditorModel {
|
||||
this.resource = resource;
|
||||
this.name = name;
|
||||
this.mime = MIME_BINARY;
|
||||
|
||||
if (resource.scheme === Schemas.data) {
|
||||
const metadata = DataUri.parseMetaData(resource);
|
||||
if (metadata.has(DataUri.META_DATA_SIZE)) {
|
||||
this.size = Number(metadata.get(DataUri.META_DATA_SIZE));
|
||||
}
|
||||
|
||||
const metadataMime = metadata.get(DataUri.META_DATA_MIME);
|
||||
if (metadataMime) {
|
||||
this.mime = metadataMime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the binary resource.
|
||||
*/
|
||||
getName(): string {
|
||||
return this.name || basename(this.resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* The resource of the binary resource.
|
||||
*/
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { DataUri } from 'vs/base/common/resources';
|
||||
|
||||
/**
|
||||
* An editor input to present data URIs in a binary editor. Data URIs have the form of:
|
||||
* data:[mime type];[meta data <key=value>;...];base64,[base64 encoded value]
|
||||
*/
|
||||
export class DataUriEditorInput extends EditorInput {
|
||||
|
||||
static readonly ID: string = 'workbench.editors.dataUriEditorInput';
|
||||
|
||||
constructor(
|
||||
private readonly name: string | undefined,
|
||||
private readonly description: string | undefined,
|
||||
private readonly resource: URI,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
|
||||
if (!this.name || !this.description) {
|
||||
const metadata = DataUri.parseMetaData(this.resource);
|
||||
|
||||
if (!this.name) {
|
||||
this.name = metadata.get(DataUri.META_DATA_LABEL);
|
||||
}
|
||||
|
||||
if (!this.description) {
|
||||
this.description = metadata.get(DataUri.META_DATA_DESCRIPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
getTypeId(): string {
|
||||
return DataUriEditorInput.ID;
|
||||
}
|
||||
|
||||
getName(): string | undefined {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
getDescription(): string | undefined {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
resolve(): Promise<BinaryEditorModel> {
|
||||
return this.instantiationService.createInstance(BinaryEditorModel, this.resource, this.getName()).load();
|
||||
}
|
||||
|
||||
matches(otherInput: unknown): boolean {
|
||||
if (super.matches(otherInput) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare by resource
|
||||
if (otherInput instanceof DataUriEditorInput) {
|
||||
return otherInput.resource.toString() === this.resource.toString();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,13 @@ export class DiffEditorInput extends SideBySideEditorInput {
|
||||
|
||||
private cachedModel: DiffEditorModel | null = null;
|
||||
|
||||
constructor(name: string, description: string | undefined, original: EditorInput, modified: EditorInput, private readonly forceOpenAsBinary?: boolean) {
|
||||
constructor(
|
||||
name: string,
|
||||
description: string | undefined,
|
||||
original: EditorInput,
|
||||
modified: EditorInput,
|
||||
private readonly forceOpenAsBinary?: boolean
|
||||
) {
|
||||
super(name, description, original, modified);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Extensions, IEditorInputFactoryRegistry, EditorInput, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, CloseDirection, IEditorInput, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { coalesce, firstIndex } from 'vs/base/common/arrays';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput';
|
||||
import { doHandleUpgrade } from 'sql/workbench/common/languageAssociation';
|
||||
|
||||
const EditorOpenPositioning = {
|
||||
@@ -66,31 +64,31 @@ export class EditorGroup extends Disposable {
|
||||
//#region events
|
||||
|
||||
private readonly _onDidEditorActivate = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorActivate: Event<EditorInput> = this._onDidEditorActivate.event;
|
||||
readonly onDidEditorActivate = this._onDidEditorActivate.event;
|
||||
|
||||
private readonly _onDidEditorOpen = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorOpen: Event<EditorInput> = this._onDidEditorOpen.event;
|
||||
readonly onDidEditorOpen = this._onDidEditorOpen.event;
|
||||
|
||||
private readonly _onDidEditorClose = this._register(new Emitter<EditorCloseEvent>());
|
||||
readonly onDidEditorClose: Event<EditorCloseEvent> = this._onDidEditorClose.event;
|
||||
readonly onDidEditorClose = this._onDidEditorClose.event;
|
||||
|
||||
private readonly _onDidEditorDispose = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorDispose: Event<EditorInput> = this._onDidEditorDispose.event;
|
||||
readonly onDidEditorDispose = this._onDidEditorDispose.event;
|
||||
|
||||
private readonly _onDidEditorBecomeDirty = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorBecomeDirty: Event<EditorInput> = this._onDidEditorBecomeDirty.event;
|
||||
readonly onDidEditorBecomeDirty = this._onDidEditorBecomeDirty.event;
|
||||
|
||||
private readonly _onDidEditorLabelChange = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorLabelChange: Event<EditorInput> = this._onDidEditorLabelChange.event;
|
||||
readonly onDidEditorLabelChange = this._onDidEditorLabelChange.event;
|
||||
|
||||
private readonly _onDidEditorMove = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorMove: Event<EditorInput> = this._onDidEditorMove.event;
|
||||
readonly onDidEditorMove = this._onDidEditorMove.event;
|
||||
|
||||
private readonly _onDidEditorPin = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorPin: Event<EditorInput> = this._onDidEditorPin.event;
|
||||
readonly onDidEditorPin = this._onDidEditorPin.event;
|
||||
|
||||
private readonly _onDidEditorUnpin = this._register(new Emitter<EditorInput>());
|
||||
readonly onDidEditorUnpin: Event<EditorInput> = this._onDidEditorUnpin.event;
|
||||
readonly onDidEditorUnpin = this._onDidEditorUnpin.event;
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -99,7 +97,6 @@ export class EditorGroup extends Disposable {
|
||||
|
||||
private editors: EditorInput[] = [];
|
||||
private mru: EditorInput[] = [];
|
||||
private mapResourceToEditorCount: ResourceMap<number> = new ResourceMap<number>();
|
||||
|
||||
private preview: EditorInput | null = null; // editor in preview state
|
||||
private active: EditorInput | null = null; // editor in active state
|
||||
@@ -141,26 +138,8 @@ export class EditorGroup extends Disposable {
|
||||
return mru ? this.mru.slice(0) : this.editors.slice(0);
|
||||
}
|
||||
|
||||
getEditor(index: number): EditorInput | undefined;
|
||||
getEditor(resource: URI): EditorInput | undefined;
|
||||
getEditor(arg1: number | URI): EditorInput | undefined {
|
||||
if (typeof arg1 === 'number') {
|
||||
return this.editors[arg1];
|
||||
}
|
||||
|
||||
const resource: URI = arg1;
|
||||
if (!this.contains(resource)) {
|
||||
return undefined; // fast check for resource opened or not
|
||||
}
|
||||
|
||||
for (const editor of this.editors) {
|
||||
const editorResource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (editorResource?.toString() === resource.toString()) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
getEditorByIndex(index: number): EditorInput | undefined {
|
||||
return this.editors[index];
|
||||
}
|
||||
|
||||
get activeEditor(): EditorInput | null {
|
||||
@@ -515,7 +494,6 @@ export class EditorGroup extends Disposable {
|
||||
// Add
|
||||
if (!del && editor) {
|
||||
this.mru.push(editor); // make it LRU editor
|
||||
this.updateResourceMap(editor, false /* add */); // add new to resource map
|
||||
}
|
||||
|
||||
// Remove / Replace
|
||||
@@ -525,41 +503,11 @@ export class EditorGroup extends Disposable {
|
||||
// Remove
|
||||
if (del && !editor) {
|
||||
this.mru.splice(indexInMRU, 1); // remove from MRU
|
||||
this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove from resource map
|
||||
}
|
||||
|
||||
// Replace
|
||||
else if (del && editor) {
|
||||
this.mru.splice(indexInMRU, 1, editor); // replace MRU at location
|
||||
this.updateResourceMap(editor, false /* add */); // add new to resource map
|
||||
this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove replaced from resource map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateResourceMap(editor: EditorInput, remove: boolean): void {
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
if (resource) {
|
||||
|
||||
// It is possible to have the same resource opened twice (once as normal input and once as diff input)
|
||||
// So we need to do ref counting on the resource to provide the correct picture
|
||||
const counter = this.mapResourceToEditorCount.get(resource) || 0;
|
||||
|
||||
// Add
|
||||
let newCounter: number;
|
||||
if (!remove) {
|
||||
newCounter = counter + 1;
|
||||
}
|
||||
|
||||
// Delete
|
||||
else {
|
||||
newCounter = counter - 1;
|
||||
}
|
||||
|
||||
if (newCounter > 0) {
|
||||
this.mapResourceToEditorCount.set(resource, newCounter);
|
||||
} else {
|
||||
this.mapResourceToEditorCount.delete(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,28 +526,20 @@ export class EditorGroup extends Disposable {
|
||||
return -1;
|
||||
}
|
||||
|
||||
contains(editorOrResource: EditorInput | URI): boolean;
|
||||
contains(editor: EditorInput, supportSideBySide?: boolean): boolean;
|
||||
contains(editorOrResource: EditorInput | URI, supportSideBySide?: boolean): boolean {
|
||||
if (editorOrResource instanceof EditorInput) {
|
||||
const index = this.indexOf(editorOrResource);
|
||||
if (index >= 0) {
|
||||
contains(candidate: EditorInput, searchInSideBySideEditors?: boolean): boolean {
|
||||
for (const editor of this.editors) {
|
||||
if (this.matches(editor, candidate)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (supportSideBySide && editorOrResource instanceof SideBySideEditorInput) {
|
||||
const index = this.indexOf(editorOrResource.master);
|
||||
if (index >= 0) {
|
||||
if (searchInSideBySideEditors && editor instanceof SideBySideEditorInput) {
|
||||
if (this.matches(editor.master, candidate) || this.matches(editor.details, candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const counter = this.mapResourceToEditorCount.get(editorOrResource);
|
||||
|
||||
return typeof counter === 'number' && counter > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private setMostRecentlyUsed(editor: EditorInput): void {
|
||||
@@ -625,7 +565,6 @@ export class EditorGroup extends Disposable {
|
||||
const group = this.instantiationService.createInstance(EditorGroup, undefined);
|
||||
group.editors = this.editors.slice(0);
|
||||
group.mru = this.mru.slice(0);
|
||||
group.mapResourceToEditorCount = this.mapResourceToEditorCount.clone();
|
||||
group.preview = this.preview;
|
||||
group.active = this.active;
|
||||
group.editorOpenPositioning = this.editorOpenPositioning;
|
||||
@@ -647,7 +586,7 @@ export class EditorGroup extends Disposable {
|
||||
if (factory) {
|
||||
// {{SQL CARBON EDIT}}
|
||||
// don't serialize unmodified unitited files
|
||||
if (e instanceof UntitledEditorInput && !e.isDirty()
|
||||
if (e instanceof UntitledTextEditorInput && !e.isDirty()
|
||||
&& !this.configurationService.getValue<boolean>('sql.promptToSaveGeneratedFiles')) {
|
||||
return;
|
||||
}
|
||||
@@ -692,7 +631,6 @@ export class EditorGroup extends Disposable {
|
||||
const editor = this.instantiationService.invokeFunction(doHandleUpgrade, factory.deserialize(this.instantiationService, e.value)); // {{SQL CARBON EDIT}} handle upgrade path to new serialization
|
||||
if (editor) {
|
||||
this.registerEditorListeners(editor);
|
||||
this.updateResourceMap(editor, false /* add */);
|
||||
}
|
||||
|
||||
return editor;
|
||||
@@ -725,7 +663,7 @@ export class EditorGroup extends Disposable {
|
||||
// remove from MRU list otherwise later if we try to close them it leaves a sticky active editor with no data
|
||||
this.mru.splice(index, 1);
|
||||
this.active = this.isActive(editor) ? this.editors[0] : this.active;
|
||||
editor.close();
|
||||
editor.dispose();
|
||||
}
|
||||
else {
|
||||
n++;
|
||||
|
||||
@@ -21,10 +21,6 @@ export class ResourceEditorModel extends BaseTextEditorModel {
|
||||
super(modelService, modeService, resource);
|
||||
}
|
||||
|
||||
isReadonly(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
// TODO@Joao: force this class to dispose the underlying model
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITextModel, ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { ITextModel, ITextBufferFactory, ITextSnapshot, ModelConstants } from 'vs/editor/common/model';
|
||||
import { EditorModel, IModeSupport } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextEditorModel, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
@@ -16,8 +16,10 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
/**
|
||||
* The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated.
|
||||
*/
|
||||
export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport {
|
||||
export class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport {
|
||||
|
||||
protected textEditorModelHandle: URI | null = null;
|
||||
|
||||
private createdEditorModel: boolean | undefined;
|
||||
|
||||
private readonly modelDisposeListener = this._register(new MutableDisposable());
|
||||
@@ -59,7 +61,9 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
|
||||
return this.textEditorModelHandle ? this.modelService.getModel(this.textEditorModelHandle) : null;
|
||||
}
|
||||
|
||||
abstract isReadonly(): boolean;
|
||||
isReadonly(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
setMode(mode: string): void {
|
||||
if (!this.isResolved()) {
|
||||
@@ -106,12 +110,12 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd
|
||||
// text buffer factory
|
||||
const textBufferFactory = value as ITextBufferFactory;
|
||||
if (typeof textBufferFactory.getFirstLineText === 'function') {
|
||||
return textBufferFactory.getFirstLineText(100);
|
||||
return textBufferFactory.getFirstLineText(ModelConstants.FIRST_LINE_DETECTION_LENGTH_LIMIT);
|
||||
}
|
||||
|
||||
// text model
|
||||
const textSnapshot = value as ITextModel;
|
||||
return textSnapshot.getLineContent(1).substr(0, 100);
|
||||
return textSnapshot.getLineContent(1).substr(0, ModelConstants.FIRST_LINE_DETECTION_LENGTH_LIMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,44 +5,58 @@
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { suggestFilename } from 'vs/base/common/mime';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { createMemoizer } from 'vs/base/common/decorators';
|
||||
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
|
||||
import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor';
|
||||
import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel';
|
||||
import { basenameOrAuthority, dirname, toLocalResource } from 'vs/base/common/resources';
|
||||
import { IEncodingSupport, EncodingMode, Verbosity, IModeSupport, TextEditorInput, GroupIdentifier, IRevertOptions } from 'vs/workbench/common/editor';
|
||||
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ITextFileService, ITextFileSaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
/**
|
||||
* An editor input to be used for untitled text buffers.
|
||||
*/
|
||||
export class UntitledEditorInput extends EditorInput implements IEncodingSupport, IModeSupport {
|
||||
export class UntitledTextEditorInput extends TextEditorInput implements IEncodingSupport, IModeSupport {
|
||||
|
||||
static readonly ID: string = 'workbench.editors.untitledEditorInput';
|
||||
|
||||
private cachedModel: UntitledEditorModel | null = null;
|
||||
private modelResolve: Promise<UntitledEditorModel & IResolvedTextEditorModel> | null = null;
|
||||
private static readonly MEMOIZER = createMemoizer();
|
||||
|
||||
private readonly _onDidModelChangeContent: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidModelChangeContent: Event<void> = this._onDidModelChangeContent.event;
|
||||
private cachedModel: UntitledTextEditorModel | null = null;
|
||||
private modelResolve: Promise<UntitledTextEditorModel & IResolvedTextEditorModel> | null = null;
|
||||
|
||||
private readonly _onDidModelChangeEncoding: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidModelChangeEncoding: Event<void> = this._onDidModelChangeEncoding.event;
|
||||
private readonly _onDidModelChangeContent = this._register(new Emitter<void>());
|
||||
readonly onDidModelChangeContent = this._onDidModelChangeContent.event;
|
||||
|
||||
private readonly _onDidModelChangeEncoding = this._register(new Emitter<void>());
|
||||
readonly onDidModelChangeEncoding = this._onDidModelChangeEncoding.event;
|
||||
|
||||
constructor(
|
||||
private readonly resource: URI,
|
||||
resource: URI,
|
||||
private readonly _hasAssociatedFilePath: boolean,
|
||||
private preferredMode: string | undefined,
|
||||
private readonly initialValue: string | undefined,
|
||||
private preferredEncoding: string | undefined,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@ILabelService private readonly labelService: ILabelService,
|
||||
@IEditorService editorService: IEditorService,
|
||||
@IEditorGroupsService editorGroupService: IEditorGroupsService,
|
||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||
) {
|
||||
super();
|
||||
super(resource, editorService, editorGroupService, textFileService);
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(this.labelService.onDidChangeFormatters(() => UntitledTextEditorInput.MEMOIZER.clear()));
|
||||
}
|
||||
|
||||
get hasAssociatedFilePath(): boolean {
|
||||
@@ -50,28 +64,24 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
}
|
||||
|
||||
getTypeId(): string {
|
||||
return UntitledEditorInput.ID;
|
||||
}
|
||||
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
return UntitledTextEditorInput.ID;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get shortDescription(): string {
|
||||
return this.labelService.getUriBasenameLabel(dirname(this.resource));
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get mediumDescription(): string {
|
||||
return this.labelService.getUriLabel(dirname(this.resource), { relative: true });
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get longDescription(): string {
|
||||
return this.labelService.getUriLabel(dirname(this.resource));
|
||||
}
|
||||
@@ -92,22 +102,22 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
}
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get shortTitle(): string {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get mediumTitle(): string {
|
||||
return this.labelService.getUriLabel(this.resource, { relative: true });
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledTextEditorInput.MEMOIZER
|
||||
private get longTitle(): string {
|
||||
return this.labelService.getUriLabel(this.resource);
|
||||
}
|
||||
|
||||
getTitle(verbosity: Verbosity): string | undefined {
|
||||
getTitle(verbosity: Verbosity): string {
|
||||
if (!this.hasAssociatedFilePath) {
|
||||
return this.getName();
|
||||
}
|
||||
@@ -120,8 +130,14 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
case Verbosity.LONG:
|
||||
return this.longTitle;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
isReadonly(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
isUntitled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
isDirty(): boolean {
|
||||
@@ -146,22 +162,37 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
return false;
|
||||
}
|
||||
|
||||
confirmSave(): Promise<ConfirmResult> {
|
||||
return this.textFileService.confirmSave([this.resource]);
|
||||
save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<boolean> {
|
||||
return this.doSaveAs(group, async () => {
|
||||
|
||||
// With associated file path, save to the path that is
|
||||
// associated. Make sure to convert the result using
|
||||
// remote authority properly.
|
||||
if (this.hasAssociatedFilePath) {
|
||||
if (await this.textFileService.save(this.resource, options)) {
|
||||
return toLocalResource(this.resource, this.environmentService.configuration.remoteAuthority);
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
// Without associated file path, do a normal "Save As"
|
||||
return this.textFileService.saveAs(this.resource, undefined, options);
|
||||
}, true /* replace editor across all groups */);
|
||||
}
|
||||
|
||||
save(): Promise<boolean> {
|
||||
return this.textFileService.save(this.resource);
|
||||
saveAs(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<boolean> {
|
||||
return this.doSaveAs(group, () => this.textFileService.saveAs(this.resource, undefined, options), true /* replace editor across all groups */);
|
||||
}
|
||||
|
||||
revert(): Promise<boolean> {
|
||||
async revert(options?: IRevertOptions): Promise<boolean> {
|
||||
if (this.cachedModel) {
|
||||
this.cachedModel.revert();
|
||||
}
|
||||
|
||||
this.dispose(); // a reverted untitled editor is no longer valid, so we dispose it
|
||||
this.dispose(); // a reverted untitled text editor is no longer valid, so we dispose it
|
||||
|
||||
return Promise.resolve(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
suggestFileName(): string {
|
||||
@@ -209,7 +240,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
return this.preferredMode;
|
||||
}
|
||||
|
||||
resolve(): Promise<UntitledEditorModel & IResolvedTextEditorModel> {
|
||||
resolve(): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
|
||||
// Join a model resolve if we have had one before
|
||||
if (this.modelResolve) {
|
||||
@@ -223,8 +254,8 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
return this.modelResolve;
|
||||
}
|
||||
|
||||
private createModel(): UntitledEditorModel {
|
||||
const model = this._register(this.instantiationService.createInstance(UntitledEditorModel, this.preferredMode, this.resource, this.hasAssociatedFilePath, this.initialValue, this.preferredEncoding));
|
||||
private createModel(): UntitledTextEditorModel {
|
||||
const model = this._register(this.instantiationService.createInstance(UntitledTextEditorModel, this.preferredMode, this.resource, this.hasAssociatedFilePath, this.initialValue, this.preferredEncoding));
|
||||
|
||||
// re-emit some events from the model
|
||||
this._register(model.onDidChangeContent(() => this._onDidModelChangeContent.fire()));
|
||||
@@ -240,7 +271,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
}
|
||||
|
||||
// Otherwise compare by properties
|
||||
if (otherInput instanceof UntitledEditorInput) {
|
||||
if (otherInput instanceof UntitledTextEditorInput) {
|
||||
return otherInput.resource.toString() === this.resource.toString();
|
||||
}
|
||||
|
||||
@@ -253,4 +284,4 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEncodingSupport } from 'vs/workbench/common/editor';
|
||||
import { IEncodingSupport, ISaveOptions } from 'vs/workbench/common/editor';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files';
|
||||
@@ -16,8 +16,10 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res
|
||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
export class UntitledEditorModel extends BaseTextEditorModel implements IEncodingSupport {
|
||||
export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport, IWorkingCopy {
|
||||
|
||||
static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY;
|
||||
|
||||
@@ -30,33 +32,34 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
private readonly _onDidChangeEncoding: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidChangeEncoding: Event<void> = this._onDidChangeEncoding.event;
|
||||
|
||||
private dirty: boolean = false;
|
||||
private versionId: number = 0;
|
||||
private readonly contentChangeEventScheduler: RunOnceScheduler;
|
||||
readonly capabilities = 0;
|
||||
|
||||
private dirty = false;
|
||||
private versionId = 0;
|
||||
private readonly contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledTextEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY));
|
||||
private configuredEncoding?: string;
|
||||
|
||||
constructor(
|
||||
private readonly preferredMode: string | undefined,
|
||||
private readonly resource: URI,
|
||||
private _hasAssociatedFilePath: boolean,
|
||||
public readonly resource: URI,
|
||||
public readonly hasAssociatedFilePath: boolean,
|
||||
private readonly initialValue: string | undefined,
|
||||
private preferredEncoding: string | undefined,
|
||||
@IModeService modeService: IModeService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IBackupFileService private readonly backupFileService: IBackupFileService,
|
||||
@ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService
|
||||
@ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService,
|
||||
@IWorkingCopyService private readonly workingCopyService: IWorkingCopyService,
|
||||
@ITextFileService private readonly textFileService: ITextFileService
|
||||
) {
|
||||
super(modelService, modeService);
|
||||
|
||||
this.contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY));
|
||||
// Make known to working copy service
|
||||
this._register(this.workingCopyService.registerWorkingCopy(this));
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
get hasAssociatedFilePath(): boolean {
|
||||
return this._hasAssociatedFilePath;
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Config Changes
|
||||
@@ -116,15 +119,17 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
save(options?: ISaveOptions): Promise<boolean> {
|
||||
return this.textFileService.save(this.resource, options);
|
||||
}
|
||||
|
||||
revert(): void {
|
||||
async revert(): Promise<boolean> {
|
||||
this.setDirty(false);
|
||||
|
||||
// Handle content change event buffered
|
||||
this.contentChangeEventScheduler.schedule();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
backup(): Promise<void> {
|
||||
@@ -139,7 +144,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
return this.backupFileService.hasBackupSync(this.resource, this.versionId);
|
||||
}
|
||||
|
||||
async load(): Promise<UntitledEditorModel & IResolvedTextEditorModel> {
|
||||
async load(): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
|
||||
|
||||
// Check for backups first
|
||||
let backup: IResolvedBackup<object> | undefined = undefined;
|
||||
@@ -149,7 +154,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
}
|
||||
|
||||
// untitled associated to file path are dirty right away as well as untitled with content
|
||||
this.setDirty(this._hasAssociatedFilePath || !!backup || !!this.initialValue);
|
||||
this.setDirty(this.hasAssociatedFilePath || !!backup || !!this.initialValue);
|
||||
|
||||
let untitledContents: ITextBufferFactory;
|
||||
if (backup) {
|
||||
@@ -180,7 +185,7 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
// Listen to mode changes
|
||||
this._register(textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config
|
||||
|
||||
return this as UntitledEditorModel & IResolvedTextEditorModel;
|
||||
return this as UntitledTextEditorModel & IResolvedTextEditorModel;
|
||||
}
|
||||
|
||||
private onModelContentChanged(): void {
|
||||
@@ -190,9 +195,9 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
|
||||
|
||||
this.versionId++;
|
||||
|
||||
// mark the untitled editor as non-dirty once its content becomes empty and we do
|
||||
// mark the untitled text editor as non-dirty once its content becomes empty and we do
|
||||
// not have an associated path set. we never want dirty indicator in that case.
|
||||
if (!this._hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') {
|
||||
if (!this.hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') {
|
||||
this.setDirty(false);
|
||||
}
|
||||
|
||||
@@ -352,6 +352,12 @@ export const ACTIVITY_BAR_ACTIVE_BORDER = registerColor('activityBar.activeBorde
|
||||
hc: null
|
||||
}, nls.localize('activityBarActiveBorder', "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
|
||||
|
||||
export const ACTIVITY_BAR_ACTIVE_FOCUS_BORDER = registerColor('activityBar.activeFocusBorder', {
|
||||
dark: null,
|
||||
light: null,
|
||||
hc: null
|
||||
}, nls.localize('activityBarActiveFocusBorder', "Activity bar focus border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar."));
|
||||
|
||||
export const ACTIVITY_BAR_ACTIVE_BACKGROUND = registerColor('activityBar.activeBackground', {
|
||||
dark: null,
|
||||
light: null,
|
||||
@@ -575,19 +581,31 @@ export const NOTIFICATIONS_ERROR_ICON_FOREGROUND = registerColor('notificationsE
|
||||
dark: editorErrorForeground,
|
||||
light: editorErrorForeground,
|
||||
hc: editorErrorForeground
|
||||
}, nls.localize('notificationsErrorIconForeground', "The color used for the notification error icon."));
|
||||
}, nls.localize('notificationsErrorIconForeground', "The color used for the icon of error notifications. Notifications slide in from the bottom right of the window."));
|
||||
|
||||
export const NOTIFICATIONS_WARNING_ICON_FOREGROUND = registerColor('notificationsWarningIcon.foreground', {
|
||||
dark: editorWarningForeground,
|
||||
light: editorWarningForeground,
|
||||
hc: editorWarningForeground
|
||||
}, nls.localize('notificationsWarningIconForeground', "The color used for the notification warning icon."));
|
||||
}, nls.localize('notificationsWarningIconForeground', "The color used for the icon of warning notifications. Notifications slide in from the bottom right of the window."));
|
||||
|
||||
export const NOTIFICATIONS_INFO_ICON_FOREGROUND = registerColor('notificationsInfoIcon.foreground', {
|
||||
dark: editorInfoForeground,
|
||||
light: editorInfoForeground,
|
||||
hc: editorInfoForeground
|
||||
}, nls.localize('notificationsInfoIconForeground', "The color used for the notification info icon."));
|
||||
}, nls.localize('notificationsInfoIconForeground', "The color used for the icon of info notifications. Notifications slide in from the bottom right of the window."));
|
||||
|
||||
export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', {
|
||||
dark: null,
|
||||
light: null,
|
||||
hc: contrastBorder
|
||||
}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client when using the custom title bar."));
|
||||
|
||||
export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', {
|
||||
dark: null,
|
||||
light: null,
|
||||
hc: contrastBorder
|
||||
}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client when using the custom title bar."));
|
||||
|
||||
/**
|
||||
* Base class for all themable workbench components.
|
||||
|
||||
@@ -424,3 +424,10 @@ export interface ITreeViewDataProvider {
|
||||
getChildren(element?: ITreeItem): Promise<ITreeItem[]>;
|
||||
|
||||
}
|
||||
|
||||
export interface IEditableData {
|
||||
validationMessage: (value: string) => string | null;
|
||||
placeholder?: string | null;
|
||||
startingValue?: string | null;
|
||||
onFinish: (value: string, success: boolean) => void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user