mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 17:23:56 -05:00
Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user