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:
Anthony Dresser
2019-12-04 19:28:22 -08:00
committed by GitHub
parent a8818ab0df
commit f5ce7fb2a5
1507 changed files with 42813 additions and 27370 deletions

View File

@@ -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';

View File

@@ -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.
*/

View 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',
});

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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;
}
/**

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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++;

View File

@@ -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

View File

@@ -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);
}
/**

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -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;
}