Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

untitled - have a isUntitledWithAssociatedResource method from the service #183420

Merged
merged 1 commit into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/vs/workbench/browser/parts/editor/editorCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IEditorIdentifier, IEditorCommandsContext, CloseDirection, IVisibleEditorPane, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, isEditorInputWithOptionsAndGroup, IUntitledTextResourceEditorInput, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
import { IEditorIdentifier, IEditorCommandsContext, CloseDirection, IVisibleEditorPane, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, isEditorInputWithOptionsAndGroup, IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor';
import { TextCompareEditorVisibleContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, ActiveEditorStickyContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, TextCompareEditorActiveContext, SideBySideEditorActiveContext } from 'vs/workbench/common/contextkeys';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { EditorGroupColumn, columnToEditorGroup } from 'vs/workbench/services/editor/common/editorGroupColumn';
Expand Down Expand Up @@ -39,6 +39,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extname } from 'vs/base/common/resources';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';

export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
Expand Down Expand Up @@ -517,6 +518,7 @@ function registerOpenEditorAPICommands(): void {
const openerService = accessor.get(IOpenerService);
const pathService = accessor.get(IPathService);
const configurationService = accessor.get(IConfigurationService);
const untitledTextEditorService = accessor.get(IUntitledTextEditorService);

const resourceOrString = typeof resourceArg === 'string' ? resourceArg : URI.from(resourceArg, true);
const [columnArg, optionsArg] = columnAndOptions ?? [];
Expand All @@ -528,7 +530,7 @@ function registerOpenEditorAPICommands(): void {
const resource = URI.isUri(resourceOrString) ? resourceOrString : URI.parse(resourceOrString);

let input: IResourceEditorInput | IUntitledTextResourceEditorInput;
if (isUntitledWithAssociatedResource(resource)) {
if (untitledTextEditorService.isUntitledWithAssociatedResource(resource)) {
// special case for untitled: we are getting a resource with meaningful
// path from an extension to use for the untitled editor. as such, we
// have to assume it as an associated resource to use when saving. we
Expand Down
6 changes: 0 additions & 6 deletions src/vs/workbench/common/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,12 +567,6 @@ export function isUntitledResourceEditorInput(editor: unknown): editor is IUntit
return candidate.resource === undefined || candidate.resource.scheme === Schemas.untitled || candidate.forceUntitled === true;
}

const UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX = /Untitled-\d+/;

export function isUntitledWithAssociatedResource(resource: URI): boolean {
return resource.scheme === Schemas.untitled && resource.path.length > 1 && !UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX.test(resource.path);
}

export function isResourceMergeEditorInput(editor: unknown): editor is IResourceMergeEditorInput {
if (isEditorInput(editor)) {
return false; // make sure to not accidentally match on typed editor inputs
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/contrib/files/browser/fileCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
args: [
{
isOptional: true,
name: 'New Untitled Text File args',
description: 'The editor view type, language ID, or resource path if known',
name: 'New Untitled Text File arguments',
description: 'The editor view type or language ID if known',
schema: {
'type': 'object',
'properties': {
Expand All @@ -673,7 +673,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
},
'languageId': {
'type': 'string'
},
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { Schemas } from 'vs/base/common/network';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IEditorSerializer, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
import { IEditorSerializer } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { ITextEditorService } from 'vs/workbench/services/textfile/common/textEditorService';
import { isEqual, toLocalResource } from 'vs/base/common/resources';
Expand All @@ -19,11 +19,12 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IWorkingCopyIdentifier, NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { IWorkingCopyEditorHandler, IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';

interface ISerializedUntitledTextEditorInput {
resourceJSON: UriComponents;
modeId: string | undefined; // should be `languageId` but is kept for backwards compatibility
encoding: string | undefined;
readonly resourceJSON: UriComponents;
readonly modeId: string | undefined; // should be `languageId` but is kept for backwards compatibility
readonly encoding: string | undefined;
}

export class UntitledTextEditorInputSerializer implements IEditorSerializer {
Expand Down Expand Up @@ -89,7 +90,8 @@ export class UntitledTextEditorWorkingCopyEditorHandler extends Disposable imple
@IWorkingCopyEditorService workingCopyEditorService: IWorkingCopyEditorService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IPathService private readonly pathService: IPathService,
@ITextEditorService private readonly textEditorService: ITextEditorService
@ITextEditorService private readonly textEditorService: ITextEditorService,
@IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService
) {
super();

Expand All @@ -113,7 +115,7 @@ export class UntitledTextEditorWorkingCopyEditorHandler extends Disposable imple

// If the untitled has an associated resource,
// ensure to restore the local resource it had
if (isUntitledWithAssociatedResource(workingCopy.resource)) {
if (this.untitledTextEditorService.isUntitledWithAssociatedResource(workingCopy.resource)) {
editorInputResource = toLocalResource(workingCopy.resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme);
} else {
editorInputResource = workingCopy.resource;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class UntitledTextEditorInput extends AbstractTextResourceEditorInput imp
if (typeof options?.preserveViewState === 'number') {
untypedInput.encoding = this.getEncoding();
untypedInput.languageId = this.getLanguageId();
untypedInput.contents = this.model.isDirty() ? this.model.textEditorModel?.getValue() : undefined;
untypedInput.contents = this.model.isModified() ? this.model.textEditorModel?.getValue() : undefined;
untypedInput.options.viewState = findViewStateForEditor(this, options.preserveViewState, this.editorService);

if (typeof untypedInput.contents === 'string' && !this.model.hasAssociatedFilePath) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
}

async revert(): Promise<void> {

// No longer dirty
this.setDirty(false);

// Emit as event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ export interface IUntitledTextEditorModelManager {
resolve(options?: INewUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;
resolve(options?: INewUntitledTextEditorWithAssociatedResourceOptions): Promise<IUntitledTextEditorModel>;
resolve(options?: IExistingUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;

/**
* Figures out if the given resource has an associated resource or not.
*/
isUntitledWithAssociatedResource(resource: URI): boolean;
}

export interface IUntitledTextEditorService extends IUntitledTextEditorModelManager {
Expand All @@ -123,6 +128,8 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe

declare readonly _serviceBrand: undefined;

private static readonly UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX = /Untitled-\d+/;

private readonly _onDidChangeDirty = this._register(new Emitter<IUntitledTextEditorModel>());
readonly onDidChangeDirty = this._onDidChangeDirty.event;

Expand Down Expand Up @@ -259,6 +266,10 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
this._onDidChangeDirty.fire(model);
}
}

isUntitledWithAssociatedResource(resource: URI): boolean {
return resource.scheme === Schemas.untitled && resource.path.length > 1 && !UntitledTextEditorService.UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX.test(resource.path);
}
}

registerSingleton(IUntitledTextEditorService, UntitledTextEditorService, InstantiationType.Delayed);
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Range } from 'vs/editor/common/core/range';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
import { CancellationToken } from 'vs/base/common/cancellation';
import { EditorInputCapabilities, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
import { EditorInputCapabilities } from 'vs/workbench/common/editor';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isReadable, isReadableStream } from 'vs/base/common/stream';
import { readableToBuffer, streamToBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';
Expand Down Expand Up @@ -46,7 +46,7 @@ suite('Untitled text editors', () => {
const input1 = instantiationService.createInstance(UntitledTextEditorInput, service.create());
await input1.resolve();
assert.strictEqual(service.get(input1.resource), input1.model);
assert.ok(!isUntitledWithAssociatedResource(input1.resource));
assert.ok(!accessor.untitledTextEditorService.isUntitledWithAssociatedResource(input1.resource));

assert.ok(service.get(input1.resource));
assert.ok(!service.get(URI.file('testing')));
Expand All @@ -55,6 +55,7 @@ suite('Untitled text editors', () => {
assert.ok(!input1.hasCapability(EditorInputCapabilities.Readonly));
assert.ok(!input1.hasCapability(EditorInputCapabilities.Singleton));
assert.ok(!input1.hasCapability(EditorInputCapabilities.RequiresTrust));
assert.ok(!input1.hasCapability(EditorInputCapabilities.Scratchpad));

const input2 = instantiationService.createInstance(UntitledTextEditorInput, service.create());
assert.strictEqual(service.get(input2.resource), input2.model);
Expand Down Expand Up @@ -138,7 +139,7 @@ suite('Untitled text editors', () => {
});

const model = service.create({ associatedResource: file });
assert.ok(isUntitledWithAssociatedResource(model.resource));
assert.ok(accessor.untitledTextEditorService.isUntitledWithAssociatedResource(model.resource));
const untitled = instantiationService.createInstance(UntitledTextEditorInput, model);
assert.ok(untitled.isDirty());
assert.strictEqual(model, onDidChangeDirtyModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class UntitledFileWorkingCopy<M extends IUntitledFileWorkingCopyModel> ex
this._register(workingCopyService.registerWorkingCopy(this));
}

//#region Dirty
//#region Dirty/Modified

private modified = this.hasAssociatedFilePath || Boolean(this.initialContents && this.initialContents.markModified !== false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,10 @@ export class UntitledFileWorkingCopyManager<M extends IUntitledFileWorkingCopyMo
}

// Handle untitled resource
else if (options.untitledResource?.scheme === Schemas.untitled) {
massagedOptions.untitledResource = options.untitledResource;
else {
if (options.untitledResource?.scheme === Schemas.untitled) {
massagedOptions.untitledResource = options.untitledResource;
}
massagedOptions.isScratchpad = options.isScratchpad;
}

Expand All @@ -191,7 +193,7 @@ export class UntitledFileWorkingCopyManager<M extends IUntitledFileWorkingCopyMo
do {
untitledResource = URI.from({
scheme: Schemas.untitled,
path: `Untitled-${counter}`,
path: options.isScratchpad ? `Scratchpad-${counter}` : `Untitled-${counter}`,
query: this.workingCopyTypeId ?
`typeId=${this.workingCopyTypeId}` : // distinguish untitled resources among others by encoding the `typeId` as query param
undefined // keep untitled resources for text files as they are (when `typeId === ''`)
Expand Down