Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5

This commit is contained in:
ADS Merger
2020-02-08 04:50:58 +00:00
parent 8c61538a27
commit 2af13c18d2
752 changed files with 16458 additions and 10063 deletions

View File

@@ -10,7 +10,7 @@ import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IDisposable, Disposable, toDisposable } 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, ITextEditorSelection } from 'vs/platform/editor/common/editor';
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext, ITextEditorSelection, TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';
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';
@@ -18,14 +18,18 @@ import { ITextModel } from 'vs/editor/common/model';
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 { IFileService, FileSystemProviderCapabilities } 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 { isEqual, dirname } from 'vs/base/common/resources';
import { IPanel } from 'vs/workbench/common/panel';
import { IRange } from 'vs/editor/common/core/range';
import { createMemoizer } from 'vs/base/common/decorators';
import { ILabelService } from 'vs/platform/label/common/label';
import { Schemas } from 'vs/base/common/network';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false);
export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null);
@@ -201,7 +205,7 @@ export interface IEditorInputFactoryRegistry {
export interface IEditorInputFactory {
/**
* Determines wether the given editor input can be serialized by the factory.
* Determines whether the given editor input can be serialized by the factory.
*/
canSerialize(editorInput: IEditorInput): boolean;
@@ -416,18 +420,20 @@ export interface IEditorInput extends IDisposable {
* to e.g. preserve view state of the editor and re-open it
* in the correct group after saving.
*
* @returns the resulting editor input of this operation. Can
* be the same editor input.
* @returns the resulting editor input (typically the same) of
* this operation or `undefined` to indicate that the operation
* failed or was canceled.
*/
save(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined>;
/**
* Saves the editor to a different location. The provided groupId
* Saves the editor to a different location. The provided `group`
* helps implementors to e.g. preserve view state of the editor
* and re-open it in the correct group after saving.
*
* @returns the resulting editor input of this operation. Typically
* a different editor input.
* @returns the resulting editor input (typically a different one)
* of this operation or `undefined` to indicate that the operation
* failed or was canceled.
*/
saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<IEditorInput | undefined>;
@@ -563,21 +569,123 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
}
}
export abstract class TextEditorInput extends EditorInput {
export abstract class TextResourceEditorInput extends EditorInput {
private static readonly MEMOIZER = createMemoizer();
constructor(
protected readonly resource: URI,
@IEditorService protected readonly editorService: IEditorService,
@IEditorGroupsService protected readonly editorGroupService: IEditorGroupsService,
@ITextFileService protected readonly textFileService: ITextFileService
@ITextFileService protected readonly textFileService: ITextFileService,
@ILabelService protected readonly labelService: ILabelService,
@IFileService protected readonly fileService: IFileService,
@IFilesConfigurationService protected readonly filesConfigurationService: IFilesConfigurationService
) {
super();
// Clear label memoizer on certain events that have impact
this._register(this.labelService.onDidChangeFormatters(() => TextResourceEditorInput.MEMOIZER.clear()));
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(() => TextResourceEditorInput.MEMOIZER.clear()));
}
getResource(): URI {
return this.resource;
}
getName(): string {
return this.basename;
}
@TextResourceEditorInput.MEMOIZER
private get basename(): string {
return this.labelService.getUriBasenameLabel(this.resource);
}
getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | undefined {
switch (verbosity) {
case Verbosity.SHORT:
return this.shortDescription;
case Verbosity.LONG:
return this.longDescription;
case Verbosity.MEDIUM:
default:
return this.mediumDescription;
}
}
@TextResourceEditorInput.MEMOIZER
private get shortDescription(): string {
return this.labelService.getUriBasenameLabel(dirname(this.resource));
}
@TextResourceEditorInput.MEMOIZER
private get mediumDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource), { relative: true });
}
@TextResourceEditorInput.MEMOIZER
private get longDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource));
}
@TextResourceEditorInput.MEMOIZER
private get shortTitle(): string {
return this.getName();
}
@TextResourceEditorInput.MEMOIZER
private get mediumTitle(): string {
return this.labelService.getUriLabel(this.resource, { relative: true });
}
@TextResourceEditorInput.MEMOIZER
private get longTitle(): string {
return this.labelService.getUriLabel(this.resource);
}
getTitle(verbosity: Verbosity): string {
switch (verbosity) {
case Verbosity.SHORT:
return this.shortTitle;
case Verbosity.LONG:
return this.longTitle;
default:
case Verbosity.MEDIUM:
return this.mediumTitle;
}
}
isUntitled(): boolean {
return this.resource.scheme === Schemas.untitled;
}
isReadonly(): boolean {
if (this.isUntitled()) {
return false; // untitled is never readonly
}
if (!this.fileService.canHandleResource(this.resource)) {
return true; // resources without file support are always readonly
}
const model = this.textFileService.files.get(this.resource);
return model?.isReadonly() || this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly);
}
isSaving(): boolean {
if (this.isUntitled()) {
return false; // untitled is never saving automatically
}
if (this.filesConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) {
return true; // a short auto save is configured, treat this as being saved
}
return false;
}
async save(group: GroupIdentifier, options?: ITextFileSaveOptions): Promise<IEditorInput | undefined> {
return this.doSave(group, options, false);
}
@@ -1002,9 +1110,9 @@ export class TextEditorOptions extends EditorOptions implements ITextEditorOptio
editorViewState: IEditorViewState | undefined;
/**
* Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.
* Option to control the text editor selection reveal type.
*/
revealInCenterIfOutsideViewport: boolean | undefined;
selectionRevealType: TextEditorSelectionRevealType | undefined;
static from(input?: IBaseResourceInput): TextEditorOptions | undefined {
if (!input || !input.options) {
@@ -1043,8 +1151,8 @@ export class TextEditorOptions extends EditorOptions implements ITextEditorOptio
this.editorViewState = options.viewState as IEditorViewState;
}
if (typeof options.revealInCenterIfOutsideViewport === 'boolean') {
this.revealInCenterIfOutsideViewport = options.revealInCenterIfOutsideViewport;
if (typeof options.selectionRevealType !== 'undefined') {
this.selectionRevealType = options.selectionRevealType;
}
return this;
@@ -1054,7 +1162,7 @@ export class TextEditorOptions extends EditorOptions implements ITextEditorOptio
* Returns if this options object has objects defined for the editor.
*/
hasOptionsDefined(): boolean {
return !!this.editorViewState || !!this.revealInCenterIfOutsideViewport || !!this.selection;
return !!this.editorViewState || !!this.selectionRevealType || !!this.selection;
}
/**
@@ -1094,7 +1202,9 @@ export class TextEditorOptions extends EditorOptions implements ITextEditorOptio
editor.setSelection(range);
if (this.revealInCenterIfOutsideViewport) {
if (this.selectionRevealType === TextEditorSelectionRevealType.NearTop) {
editor.revealRangeNearTop(range, scrollType);
} else if (this.selectionRevealType === TextEditorSelectionRevealType.CenterIfOutsideViewport) {
editor.revealRangeInCenterIfOutsideViewport(range, scrollType);
} else {
editor.revealRangeInCenter(range, scrollType);

View File

@@ -17,7 +17,7 @@ export class DiffEditorInput extends SideBySideEditorInput {
static readonly ID = 'workbench.editors.diffEditorInput';
private cachedModel: DiffEditorModel | null = null;
private cachedModel: DiffEditorModel | undefined = undefined;
constructor(
protected name: string | undefined,
@@ -96,7 +96,7 @@ export class DiffEditorInput extends SideBySideEditorInput {
// them without sideeffects.
if (this.cachedModel) {
this.cachedModel.dispose();
this.cachedModel = null;
this.cachedModel = undefined;
}
super.dispose();

View File

@@ -60,32 +60,29 @@ export class EditorGroup extends Disposable {
//#region events
private readonly _onDidEditorActivate = this._register(new Emitter<EditorInput>());
readonly onDidEditorActivate = this._onDidEditorActivate.event;
private readonly _onDidActivateEditor = this._register(new Emitter<EditorInput>());
readonly onDidActivateEditor = this._onDidActivateEditor.event;
private readonly _onDidEditorOpen = this._register(new Emitter<EditorInput>());
readonly onDidEditorOpen = this._onDidEditorOpen.event;
private readonly _onDidOpenEditor = this._register(new Emitter<EditorInput>());
readonly onDidOpenEditor = this._onDidOpenEditor.event;
private readonly _onDidEditorClose = this._register(new Emitter<EditorCloseEvent>());
readonly onDidEditorClose = this._onDidEditorClose.event;
private readonly _onDidCloseEditor = this._register(new Emitter<EditorCloseEvent>());
readonly onDidCloseEditor = this._onDidCloseEditor.event;
private readonly _onDidEditorDispose = this._register(new Emitter<EditorInput>());
readonly onDidEditorDispose = this._onDidEditorDispose.event;
private readonly _onDidDisposeEditor = this._register(new Emitter<EditorInput>());
readonly onDidDisposeEditor = this._onDidDisposeEditor.event;
private readonly _onDidEditorBecomeDirty = this._register(new Emitter<EditorInput>());
readonly onDidEditorBecomeDirty = this._onDidEditorBecomeDirty.event;
private readonly _onDidChangeEditorDirty = this._register(new Emitter<EditorInput>());
readonly onDidChangeEditorDirty = this._onDidChangeEditorDirty.event;
private readonly _onDidEditorLabelChange = this._register(new Emitter<EditorInput>());
readonly onDidEditorLabelChange = this._onDidEditorLabelChange.event;
private readonly _onDidChangeEditorLabel = this._register(new Emitter<EditorInput>());
readonly onDidEditorLabelChange = this._onDidChangeEditorLabel.event;
private readonly _onDidEditorMove = this._register(new Emitter<EditorInput>());
readonly onDidEditorMove = this._onDidEditorMove.event;
private readonly _onDidMoveEditor = this._register(new Emitter<EditorInput>());
readonly onDidMoveEditor = this._onDidMoveEditor.event;
private readonly _onDidEditorPin = this._register(new Emitter<EditorInput>());
readonly onDidEditorPin = this._onDidEditorPin.event;
private readonly _onDidEditorUnpin = this._register(new Emitter<EditorInput>());
readonly onDidEditorUnpin = this._onDidEditorUnpin.event;
private readonly _onDidChangeEditorPinned = this._register(new Emitter<EditorInput>());
readonly onDidChangeEditorPinned = this._onDidChangeEditorPinned.event;
//#endregion
@@ -221,7 +218,7 @@ export class EditorGroup extends Disposable {
this.registerEditorListeners(newEditor);
// Event
this._onDidEditorOpen.fire(newEditor);
this._onDidOpenEditor.fire(newEditor);
// Handle active
if (makeActive) {
@@ -260,22 +257,22 @@ export class EditorGroup extends Disposable {
const onceDispose = Event.once(editor.onDispose);
listeners.add(onceDispose(() => {
if (this.indexOf(editor) >= 0) {
this._onDidEditorDispose.fire(editor);
this._onDidDisposeEditor.fire(editor);
}
}));
// Re-Emit dirty state changes
listeners.add(editor.onDidChangeDirty(() => {
this._onDidEditorBecomeDirty.fire(editor);
this._onDidChangeEditorDirty.fire(editor);
}));
// Re-Emit label changes
listeners.add(editor.onDidChangeLabel(() => {
this._onDidEditorLabelChange.fire(editor);
this._onDidChangeEditorLabel.fire(editor);
}));
// Clean up dispose listeners once the editor gets closed
listeners.add(this.onDidEditorClose(event => {
listeners.add(this.onDidCloseEditor(event => {
if (event.editor.matches(editor)) {
dispose(listeners);
}
@@ -291,7 +288,7 @@ export class EditorGroup extends Disposable {
this.splice(replaceIndex, false, replaceWith);
if (event) {
this._onDidEditorClose.fire(event);
this._onDidCloseEditor.fire(event);
}
}
@@ -299,7 +296,7 @@ export class EditorGroup extends Disposable {
const event = this.doCloseEditor(candidate, openNext, false);
if (event) {
this._onDidEditorClose.fire(event);
this._onDidCloseEditor.fire(event);
return event.editor;
}
@@ -400,7 +397,7 @@ export class EditorGroup extends Disposable {
this.editors.splice(toIndex, 0, editor);
// Event
this._onDidEditorMove.fire(editor);
this._onDidMoveEditor.fire(editor);
return editor;
}
@@ -429,7 +426,7 @@ export class EditorGroup extends Disposable {
this.mru.unshift(editor);
// Event
this._onDidEditorActivate.fire(editor);
this._onDidActivateEditor.fire(editor);
}
pin(candidate: EditorInput): EditorInput | undefined {
@@ -452,7 +449,7 @@ export class EditorGroup extends Disposable {
this.preview = null;
// Event
this._onDidEditorPin.fire(editor);
this._onDidChangeEditorPinned.fire(editor);
}
unpin(candidate: EditorInput): EditorInput | undefined {
@@ -476,7 +473,7 @@ export class EditorGroup extends Disposable {
this.preview = editor;
// Event
this._onDidEditorUnpin.fire(editor);
this._onDidChangeEditorPinned.fire(editor);
// Close old preview editor if any
if (oldPreview) {

View File

@@ -3,26 +3,28 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITextEditorModel, IModeSupport, TextEditorInput } from 'vs/workbench/common/editor';
import { ITextEditorModel, IModeSupport, TextResourceEditorInput } from 'vs/workbench/common/editor';
import { URI } from 'vs/base/common/uri';
import { IReference } from 'vs/base/common/lifecycle';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
import { basename } from 'vs/base/common/resources';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IFileService } from 'vs/platform/files/common/files';
import { ILabelService } from 'vs/platform/label/common/label';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
/**
* A read-only text editor input whos contents are made of the provided resource that points to an existing
* code editor model.
*/
export class ResourceEditorInput extends TextEditorInput implements IModeSupport {
export class ResourceEditorInput extends TextResourceEditorInput implements IModeSupport {
static readonly ID: string = 'workbench.editors.resourceEditorInput';
private cachedModel: ResourceEditorModel | null = null;
private modelReference: Promise<IReference<ITextEditorModel>> | null = null;
private cachedModel: ResourceEditorModel | undefined = undefined;
private modelReference: Promise<IReference<ITextEditorModel>> | undefined = undefined;
constructor(
private name: string | undefined,
@@ -32,13 +34,12 @@ export class ResourceEditorInput extends TextEditorInput implements IModeSupport
@ITextModelService private readonly textModelResolverService: ITextModelService,
@ITextFileService textFileService: ITextFileService,
@IEditorService editorService: IEditorService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IFileService fileService: IFileService,
@ILabelService labelService: ILabelService,
@IFilesConfigurationService filesConfigurationService: IFilesConfigurationService
) {
super(resource, editorService, editorGroupService, textFileService);
}
getResource(): URI {
return this.resource;
super(resource, editorService, editorGroupService, textFileService, labelService, fileService, filesConfigurationService);
}
getTypeId(): string {
@@ -46,7 +47,7 @@ export class ResourceEditorInput extends TextEditorInput implements IModeSupport
}
getName(): string {
return this.name || basename(this.resource);
return this.name || super.getName();
}
setName(name: string): void {
@@ -91,7 +92,7 @@ export class ResourceEditorInput extends TextEditorInput implements IModeSupport
// Ensure the resolved model is of expected type
if (!(model instanceof ResourceEditorModel)) {
ref.dispose();
this.modelReference = null;
this.modelReference = undefined;
throw new Error(`Unexpected model for ResourceInput: ${this.resource}`);
}
@@ -122,10 +123,10 @@ export class ResourceEditorInput extends TextEditorInput implements IModeSupport
dispose(): void {
if (this.modelReference) {
this.modelReference.then(ref => ref.dispose());
this.modelReference = null;
this.modelReference = undefined;
}
this.cachedModel = null;
this.cachedModel = undefined;
super.dispose();
}

View File

@@ -81,14 +81,14 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel
* Creates the text editor model with the provided value, optional preferred mode
* (can be comma separated for multiple values) and optional resource URL.
*/
protected createTextEditorModel(value: ITextBufferFactory, resource: URI | undefined, preferredMode?: string): EditorModel {
protected createTextEditorModel(value: ITextBufferFactory, resource: URI | undefined, preferredMode?: string): ITextModel {
const firstLineText = this.getFirstLineText(value);
const languageSelection = this.getOrCreateMode(resource, this.modeService, preferredMode, firstLineText);
return this.doCreateTextEditorModel(value, languageSelection, resource);
}
private doCreateTextEditorModel(value: ITextBufferFactory, languageSelection: ILanguageSelection, resource: URI | undefined): EditorModel {
private doCreateTextEditorModel(value: ITextBufferFactory, languageSelection: ILanguageSelection, resource: URI | undefined): ITextModel {
let model = resource && this.modelService.getModel(resource);
if (!model) {
model = this.modelService.createModel(value, languageSelection, resource);
@@ -102,7 +102,7 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel
this.textEditorModelHandle = model.uri;
return this;
return model;
}
protected getFirstLineText(value: ITextBufferFactory | ITextModel): string {

View File

@@ -4,9 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { createMemoizer } from 'vs/base/common/decorators';
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
import { IEncodingSupport, EncodingMode, Verbosity, IModeSupport, TextEditorInput } from 'vs/workbench/common/editor';
import { IEncodingSupport, EncodingMode, Verbosity, IModeSupport, TextResourceEditorInput } from 'vs/workbench/common/editor';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Emitter } from 'vs/base/common/event';
@@ -15,22 +13,22 @@ 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 { IFileService } from 'vs/platform/files/common/files';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
/**
* An editor input to be used for untitled text buffers.
*/
export class UntitledTextEditorInput extends TextEditorInput implements IEncodingSupport, IModeSupport {
export class UntitledTextEditorInput extends TextResourceEditorInput implements IEncodingSupport, IModeSupport {
static readonly ID: string = 'workbench.editors.untitledEditorInput';
private static readonly MEMOIZER = createMemoizer();
private readonly _onDidModelChangeEncoding = this._register(new Emitter<void>());
readonly onDidModelChangeEncoding = this._onDidModelChangeEncoding.event;
private cachedModel: UntitledTextEditorModel | null = null;
private cachedModel: UntitledTextEditorModel | undefined = undefined;
private modelResolve: Promise<UntitledTextEditorModel & IResolvedTextEditorModel> | null = null;
private modelResolve: Promise<UntitledTextEditorModel & IResolvedTextEditorModel> | undefined = undefined;
private preferredMode: string | undefined;
@@ -42,21 +40,17 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
private preferredEncoding: string | undefined,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ITextFileService textFileService: ITextFileService,
@ILabelService private readonly labelService: ILabelService,
@ILabelService labelService: ILabelService,
@IEditorService editorService: IEditorService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IFileService fileService: IFileService,
@IFilesConfigurationService filesConfigurationService: IFilesConfigurationService
) {
super(resource, editorService, editorGroupService, textFileService);
super(resource, editorService, editorGroupService, textFileService, labelService, fileService, filesConfigurationService);
if (preferredMode) {
this.setMode(preferredMode);
}
this.registerListeners();
}
private registerListeners(): void {
this._register(this.labelService.onDidChangeFormatters(() => UntitledTextEditorInput.MEMOIZER.clear()));
}
get hasAssociatedFilePath(): boolean {
@@ -72,76 +66,41 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
return this.cachedModel.name;
}
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
}
@UntitledTextEditorInput.MEMOIZER
private get shortDescription(): string {
return this.labelService.getUriBasenameLabel(dirname(this.resource));
}
@UntitledTextEditorInput.MEMOIZER
private get mediumDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource), { relative: true });
}
@UntitledTextEditorInput.MEMOIZER
private get longDescription(): string {
return this.labelService.getUriLabel(dirname(this.resource));
return super.getName();
}
getDescription(verbosity: Verbosity = Verbosity.MEDIUM): string | undefined {
// Without associated path: only use if name and description differ
if (!this.hasAssociatedFilePath) {
const descriptionCandidate = this.resource.path;
if (descriptionCandidate !== this.getName()) {
return descriptionCandidate;
}
return undefined;
}
switch (verbosity) {
case Verbosity.SHORT:
return this.shortDescription;
case Verbosity.LONG:
return this.longDescription;
case Verbosity.MEDIUM:
default:
return this.mediumDescription;
}
}
@UntitledTextEditorInput.MEMOIZER
private get shortTitle(): string {
return this.getName();
}
@UntitledTextEditorInput.MEMOIZER
private get mediumTitle(): string {
return this.labelService.getUriLabel(this.resource, { relative: true });
}
@UntitledTextEditorInput.MEMOIZER
private get longTitle(): string {
return this.labelService.getUriLabel(this.resource);
// With associated path: delegate to parent
return super.getDescription(verbosity);
}
getTitle(verbosity: Verbosity): string {
// Without associated path: check if name and description differ to decide
// if description should appear besides the name to distinguish better
if (!this.hasAssociatedFilePath) {
return this.getName();
const name = this.getName();
const description = this.getDescription();
if (description && description !== name) {
return `${name}${description}`;
}
return name;
}
switch (verbosity) {
case Verbosity.SHORT:
return this.shortTitle;
case Verbosity.MEDIUM:
return this.mediumTitle;
case Verbosity.LONG:
return this.longTitle;
}
}
isReadonly(): boolean {
return false;
}
isUntitled(): boolean {
return true;
// With associated path: delegate to parent
return super.getTitle(verbosity);
}
isDirty(): boolean {
@@ -255,8 +214,8 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
}
dispose(): void {
this.cachedModel = null;
this.modelResolve = null;
this.cachedModel = undefined;
this.modelResolve = undefined;
super.dispose();
}

View File

@@ -11,21 +11,21 @@ import { IModelService } from 'vs/editor/common/services/modelService';
import { Emitter } from 'vs/base/common/event';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
import { ITextBufferFactory } from 'vs/editor/common/model';
import { ITextBufferFactory, ITextModel } from 'vs/editor/common/model';
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
import { IResolvedTextEditorModel, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { withNullAsUndefined } from 'vs/base/common/types';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types';
import { ILabelService } from 'vs/platform/label/common/label';
import { ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy { }
export class UntitledTextEditorModel extends BaseTextEditorModel implements IUntitledTextEditorModel {
private static readonly FIRST_LINE_NAME_MAX_LENGTH = 50;
private static readonly FIRST_LINE_NAME_MAX_LENGTH = 40;
private readonly _onDidChangeContent = this._register(new Emitter<void>());
readonly onDidChangeContent = this._onDidChangeContent.event;
@@ -51,7 +51,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
}
// Otherwise fallback to resource
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
return this.labelService.getUriBasenameLabel(this.resource);
}
private dirty = false;
@@ -67,9 +67,10 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
@IModeService modeService: IModeService,
@IModelService modelService: IModelService,
@IBackupFileService private readonly backupFileService: IBackupFileService,
@ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService,
@ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService,
@IWorkingCopyService private readonly workingCopyService: IWorkingCopyService,
@ITextFileService private readonly textFileService: ITextFileService
@ITextFileService private readonly textFileService: ITextFileService,
@ILabelService private readonly labelService: ILabelService
) {
super(modelService, modeService);
@@ -82,11 +83,11 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
private registerListeners(): void {
// Config Changes
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange()));
this._register(this.textResourceConfigurationService.onDidChangeConfiguration(e => this.onConfigurationChange()));
}
private onConfigurationChange(): void {
const configuredEncoding = this.configurationService.getValue<string>(this.resource, 'files.encoding');
const configuredEncoding = this.textResourceConfigurationService.getValue<string>(this.resource, 'files.encoding');
if (this.configuredEncoding !== configuredEncoding) {
this.configuredEncoding = configuredEncoding;
@@ -168,9 +169,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
// Check for backups
const backup = await this.backupFileService.resolve(this.resource);
// untitled associated to file path are dirty right away as well as untitled with content
this.setDirty(this.hasAssociatedFilePath || !!backup || !!this.initialValue);
let untitledContents: ITextBufferFactory;
if (backup) {
untitledContents = backup.value;
@@ -188,22 +186,21 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
this.updateTextEditorModel(untitledContents, this.preferredMode);
}
// Figure out encoding now that model is present
this.configuredEncoding = this.textResourceConfigurationService.getValue<string>(this.resource, 'files.encoding');
// Listen to text model events
const textEditorModel = assertIsDefined(this.textEditorModel);
this._register(textEditorModel.onDidChangeContent(e => this.onModelContentChanged(textEditorModel, e)));
this._register(textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config
// Name
if (backup || this.initialValue) {
this.updateNameFromFirstLine();
}
// Encoding
this.configuredEncoding = this.configurationService.getValue<string>(this.resource, 'files.encoding');
// We know for a fact there is a text editor model here
const textEditorModel = this.textEditorModel!;
// Listen to content changes
this._register(textEditorModel.onDidChangeContent(e => this.onModelContentChanged(e)));
// Listen to mode changes
this._register(textEditorModel.onDidChangeLanguage(() => this.onConfigurationChange())); // mode change can have impact on config
// Untitled associated to file path are dirty right away as well as untitled with content
this.setDirty(this.hasAssociatedFilePath || !!backup || !!this.initialValue);
// If we have initial contents, make sure to emit this
// as the appropiate events to the outside.
@@ -214,16 +211,12 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
return this as UntitledTextEditorModel & IResolvedTextEditorModel;
}
private onModelContentChanged(e: IModelContentChangedEvent): void {
if (!this.isResolved()) {
return;
}
private onModelContentChanged(model: ITextModel, e: IModelContentChangedEvent): void {
this.versionId++;
// 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 && model.getLineCount() === 1 && model.getLineContent(1) === '') {
this.setDirty(false);
}
@@ -232,8 +225,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
this.setDirty(true);
}
// Check for name change if first line changed
if (e.changes.some(change => change.range.startLineNumber === 1 || change.range.endLineNumber === 1)) {
// Check for name change if first line changed in the range of 0-FIRST_LINE_NAME_MAX_LENGTH columns
if (e.changes.some(change => (change.range.startLineNumber === 1 || change.range.endLineNumber === 1) && change.range.startColumn <= UntitledTextEditorModel.FIRST_LINE_NAME_MAX_LENGTH)) {
this.updateNameFromFirstLine();
}
@@ -253,7 +246,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
let modelFirstWordsCandidate: string | undefined = undefined;
const firstLineText = this.textEditorModel?.getValueInRange({ startLineNumber: 1, endLineNumber: 1, startColumn: 1, endColumn: UntitledTextEditorModel.FIRST_LINE_NAME_MAX_LENGTH }).trim();
const firstLineText = this.textEditorModel?.getValueInRange({ startLineNumber: 1, endLineNumber: 1, startColumn: 1, endColumn: UntitledTextEditorModel.FIRST_LINE_NAME_MAX_LENGTH + 1 }).trim();
if (firstLineText && ensureValidWordDefinition().exec(firstLineText)) {
modelFirstWordsCandidate = firstLineText;
}

View File

@@ -21,7 +21,6 @@ import { flatten } from 'vs/base/common/arrays';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test';
export const FocusedViewContext = new RawContextKey<string>('focusedView', '');
export namespace Extensions {
export const ViewContainersRegistry = 'workbench.registry.view.containers';
@@ -103,7 +102,7 @@ export interface IViewContainersRegistry {
/**
* Returns the view container location
*/
getViewContainerLocation(container: ViewContainer): ViewContainerLocation | undefined;
getViewContainerLocation(container: ViewContainer): ViewContainerLocation;
}
interface ViewOrderDelegate {
@@ -162,7 +161,7 @@ class ViewContainersRegistryImpl extends Disposable implements IViewContainersRe
return [...(this.viewContainers.get(location) || [])];
}
getViewContainerLocation(container: ViewContainer): ViewContainerLocation | undefined {
getViewContainerLocation(container: ViewContainer): ViewContainerLocation {
return keys(this.viewContainers).filter(location => this.getViewContainers(location).filter(viewContainer => viewContainer.id === container.id).length > 0)[0];
}
}
@@ -341,6 +340,12 @@ export interface IView {
readonly id: string;
isVisible(): boolean;
isBodyVisible(): boolean;
setExpanded(expanded: boolean): boolean;
}
export interface IViewsViewlet extends IViewlet {
@@ -349,23 +354,39 @@ export interface IViewsViewlet extends IViewlet {
}
export const IViewDescriptorService = createDecorator<IViewDescriptorService>('viewDescriptorService');
export const IViewsService = createDecorator<IViewsService>('viewsService');
export interface IViewsService {
_serviceBrand: undefined;
getActiveViewWithId(id: string): IView | null;
readonly onDidChangeViewVisibility: Event<{ id: string, visible: boolean }>;
isViewVisible(id: string): boolean;
getActiveViewWithId<T extends IView>(id: string): T | null;
openView<T extends IView>(id: string, focus?: boolean): Promise<T | null>;
closeView(id: string): void;
openView(id: string, focus?: boolean): Promise<IView | null>;
}
/**
* View Contexts
*/
export const FocusedViewContext = new RawContextKey<string>('focusedView', '');
export function getVisbileViewContextKey(viewId: string): string { return `${viewId}.visible`; }
export const IViewDescriptorService = createDecorator<IViewDescriptorService>('viewDescriptorService');
export interface IViewDescriptorService {
_serviceBrand: undefined;
readonly onDidChangeContainer: Event<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>;
readonly onDidChangeLocation: Event<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }>;
moveViewToLocation(view: IViewDescriptor, location: ViewContainerLocation): void;
moveViewsToContainer(views: IViewDescriptor[], viewContainer: ViewContainer): void;
@@ -376,9 +397,11 @@ export interface IViewDescriptorService {
getViewContainer(viewId: string): ViewContainer | null;
getViewLocation(viewId: string): ViewContainerLocation | null;
getViewContainerLocation(viewContainr: ViewContainer): ViewContainerLocation | null;
getDefaultContainer(viewId: string): ViewContainer | null;
getViewLocation(viewId: string): ViewContainerLocation | null;
}
// Custom views
@@ -443,9 +466,7 @@ export interface IRevealOptions {
}
export interface ITreeViewDescriptor extends IViewDescriptor {
readonly treeView: ITreeView;
treeView: ITreeView;
}
export type TreeViewItemHandleArg = {
@@ -510,6 +531,12 @@ export interface IEditableData {
}
export interface IViewPaneContainer {
onDidAddViews: Event<IView[]>;
onDidRemoveViews: Event<IView[]>;
onDidChangeViewVisibility: Event<IView>;
readonly views: IView[];
setVisible(visible: boolean): void;
isVisible(): boolean;
focus(): void;