Skip to content

Commit 49f7ecf

Browse files
authored
untitled - have a isUntitledWithAssociatedResource method from the service (microsoft#183420)
1 parent 8cf85bd commit 49f7ecf

File tree

10 files changed

+39
-25
lines changed

10 files changed

+39
-25
lines changed

src/vs/workbench/browser/parts/editor/editorCommands.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
77
import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types';
88
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
99
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
10-
import { IEditorIdentifier, IEditorCommandsContext, CloseDirection, IVisibleEditorPane, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, isEditorInputWithOptionsAndGroup, IUntitledTextResourceEditorInput, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
10+
import { IEditorIdentifier, IEditorCommandsContext, CloseDirection, IVisibleEditorPane, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, isEditorInputWithOptionsAndGroup, IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor';
1111
import { TextCompareEditorVisibleContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, ActiveEditorStickyContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, TextCompareEditorActiveContext, SideBySideEditorActiveContext } from 'vs/workbench/common/contextkeys';
1212
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
1313
import { EditorGroupColumn, columnToEditorGroup } from 'vs/workbench/services/editor/common/editorGroupColumn';
@@ -39,6 +39,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
3939
import { extname } from 'vs/base/common/resources';
4040
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
4141
import { isDiffEditor } from 'vs/editor/browser/editorBrowser';
42+
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
4243

4344
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
4445
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
@@ -517,6 +518,7 @@ function registerOpenEditorAPICommands(): void {
517518
const openerService = accessor.get(IOpenerService);
518519
const pathService = accessor.get(IPathService);
519520
const configurationService = accessor.get(IConfigurationService);
521+
const untitledTextEditorService = accessor.get(IUntitledTextEditorService);
520522

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

530532
let input: IResourceEditorInput | IUntitledTextResourceEditorInput;
531-
if (isUntitledWithAssociatedResource(resource)) {
533+
if (untitledTextEditorService.isUntitledWithAssociatedResource(resource)) {
532534
// special case for untitled: we are getting a resource with meaningful
533535
// path from an extension to use for the untitled editor. as such, we
534536
// have to assume it as an associated resource to use when saving. we

src/vs/workbench/common/editor.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -567,12 +567,6 @@ export function isUntitledResourceEditorInput(editor: unknown): editor is IUntit
567567
return candidate.resource === undefined || candidate.resource.scheme === Schemas.untitled || candidate.forceUntitled === true;
568568
}
569569

570-
const UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX = /Untitled-\d+/;
571-
572-
export function isUntitledWithAssociatedResource(resource: URI): boolean {
573-
return resource.scheme === Schemas.untitled && resource.path.length > 1 && !UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX.test(resource.path);
574-
}
575-
576570
export function isResourceMergeEditorInput(editor: unknown): editor is IResourceMergeEditorInput {
577571
if (isEditorInput(editor)) {
578572
return false; // make sure to not accidentally match on typed editor inputs

src/vs/workbench/contrib/files/browser/fileCommands.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,8 +663,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
663663
args: [
664664
{
665665
isOptional: true,
666-
name: 'New Untitled Text File args',
667-
description: 'The editor view type, language ID, or resource path if known',
666+
name: 'New Untitled Text File arguments',
667+
description: 'The editor view type or language ID if known',
668668
schema: {
669669
'type': 'object',
670670
'properties': {
@@ -673,7 +673,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
673673
},
674674
'languageId': {
675675
'type': 'string'
676-
},
676+
}
677677
}
678678
}
679679
}

src/vs/workbench/services/untitled/common/untitledTextEditorHandler.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { Schemas } from 'vs/base/common/network';
77
import { Disposable } from 'vs/base/common/lifecycle';
88
import { URI, UriComponents } from 'vs/base/common/uri';
9-
import { IEditorSerializer, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
9+
import { IEditorSerializer } from 'vs/workbench/common/editor';
1010
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
1111
import { ITextEditorService } from 'vs/workbench/services/textfile/common/textEditorService';
1212
import { isEqual, toLocalResource } from 'vs/base/common/resources';
@@ -19,11 +19,12 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
1919
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
2020
import { IWorkingCopyIdentifier, NO_TYPE_ID } from 'vs/workbench/services/workingCopy/common/workingCopy';
2121
import { IWorkingCopyEditorHandler, IWorkingCopyEditorService } from 'vs/workbench/services/workingCopy/common/workingCopyEditorService';
22+
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
2223

2324
interface ISerializedUntitledTextEditorInput {
24-
resourceJSON: UriComponents;
25-
modeId: string | undefined; // should be `languageId` but is kept for backwards compatibility
26-
encoding: string | undefined;
25+
readonly resourceJSON: UriComponents;
26+
readonly modeId: string | undefined; // should be `languageId` but is kept for backwards compatibility
27+
readonly encoding: string | undefined;
2728
}
2829

2930
export class UntitledTextEditorInputSerializer implements IEditorSerializer {
@@ -89,7 +90,8 @@ export class UntitledTextEditorWorkingCopyEditorHandler extends Disposable imple
8990
@IWorkingCopyEditorService workingCopyEditorService: IWorkingCopyEditorService,
9091
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
9192
@IPathService private readonly pathService: IPathService,
92-
@ITextEditorService private readonly textEditorService: ITextEditorService
93+
@ITextEditorService private readonly textEditorService: ITextEditorService,
94+
@IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService
9395
) {
9496
super();
9597

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

114116
// If the untitled has an associated resource,
115117
// ensure to restore the local resource it had
116-
if (isUntitledWithAssociatedResource(workingCopy.resource)) {
118+
if (this.untitledTextEditorService.isUntitledWithAssociatedResource(workingCopy.resource)) {
117119
editorInputResource = toLocalResource(workingCopy.resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme);
118120
} else {
119121
editorInputResource = workingCopy.resource;

src/vs/workbench/services/untitled/common/untitledTextEditorInput.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export class UntitledTextEditorInput extends AbstractTextResourceEditorInput imp
140140
if (typeof options?.preserveViewState === 'number') {
141141
untypedInput.encoding = this.getEncoding();
142142
untypedInput.languageId = this.getLanguageId();
143-
untypedInput.contents = this.model.isDirty() ? this.model.textEditorModel?.getValue() : undefined;
143+
untypedInput.contents = this.model.isModified() ? this.model.textEditorModel?.getValue() : undefined;
144144
untypedInput.options.viewState = findViewStateForEditor(this, options.preserveViewState, this.editorService);
145145

146146
if (typeof untypedInput.contents === 'string' && !this.model.hasAssociatedFilePath) {

src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
272272
}
273273

274274
async revert(): Promise<void> {
275+
276+
// No longer dirty
275277
this.setDirty(false);
276278

277279
// Emit as event

src/vs/workbench/services/untitled/common/untitledTextEditorService.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ export interface IUntitledTextEditorModelManager {
112112
resolve(options?: INewUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;
113113
resolve(options?: INewUntitledTextEditorWithAssociatedResourceOptions): Promise<IUntitledTextEditorModel>;
114114
resolve(options?: IExistingUntitledTextEditorOptions): Promise<IUntitledTextEditorModel>;
115+
116+
/**
117+
* Figures out if the given resource has an associated resource or not.
118+
*/
119+
isUntitledWithAssociatedResource(resource: URI): boolean;
115120
}
116121

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

124129
declare readonly _serviceBrand: undefined;
125130

131+
private static readonly UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX = /Untitled-\d+/;
132+
126133
private readonly _onDidChangeDirty = this._register(new Emitter<IUntitledTextEditorModel>());
127134
readonly onDidChangeDirty = this._onDidChangeDirty.event;
128135

@@ -259,6 +266,10 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
259266
this._onDidChangeDirty.fire(model);
260267
}
261268
}
269+
270+
isUntitledWithAssociatedResource(resource: URI): boolean {
271+
return resource.scheme === Schemas.untitled && resource.path.length > 1 && !UntitledTextEditorService.UNTITLED_WITHOUT_ASSOCIATED_RESOURCE_REGEX.test(resource.path);
272+
}
262273
}
263274

264275
registerSingleton(IUntitledTextEditorService, UntitledTextEditorService, InstantiationType.Delayed);

src/vs/workbench/services/untitled/test/browser/untitledTextEditor.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { Range } from 'vs/editor/common/core/range';
1616
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
1717
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
1818
import { CancellationToken } from 'vs/base/common/cancellation';
19-
import { EditorInputCapabilities, isUntitledWithAssociatedResource } from 'vs/workbench/common/editor';
19+
import { EditorInputCapabilities } from 'vs/workbench/common/editor';
2020
import { DisposableStore } from 'vs/base/common/lifecycle';
2121
import { isReadable, isReadableStream } from 'vs/base/common/stream';
2222
import { readableToBuffer, streamToBuffer, VSBufferReadable, VSBufferReadableStream } from 'vs/base/common/buffer';
@@ -46,7 +46,7 @@ suite('Untitled text editors', () => {
4646
const input1 = instantiationService.createInstance(UntitledTextEditorInput, service.create());
4747
await input1.resolve();
4848
assert.strictEqual(service.get(input1.resource), input1.model);
49-
assert.ok(!isUntitledWithAssociatedResource(input1.resource));
49+
assert.ok(!accessor.untitledTextEditorService.isUntitledWithAssociatedResource(input1.resource));
5050

5151
assert.ok(service.get(input1.resource));
5252
assert.ok(!service.get(URI.file('testing')));
@@ -55,6 +55,7 @@ suite('Untitled text editors', () => {
5555
assert.ok(!input1.hasCapability(EditorInputCapabilities.Readonly));
5656
assert.ok(!input1.hasCapability(EditorInputCapabilities.Singleton));
5757
assert.ok(!input1.hasCapability(EditorInputCapabilities.RequiresTrust));
58+
assert.ok(!input1.hasCapability(EditorInputCapabilities.Scratchpad));
5859

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

140141
const model = service.create({ associatedResource: file });
141-
assert.ok(isUntitledWithAssociatedResource(model.resource));
142+
assert.ok(accessor.untitledTextEditorService.isUntitledWithAssociatedResource(model.resource));
142143
const untitled = instantiationService.createInstance(UntitledTextEditorInput, model);
143144
assert.ok(untitled.isDirty());
144145
assert.strictEqual(model, onDidChangeDirtyModel);

src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class UntitledFileWorkingCopy<M extends IUntitledFileWorkingCopyModel> ex
135135
this._register(workingCopyService.registerWorkingCopy(this));
136136
}
137137

138-
//#region Dirty
138+
//#region Dirty/Modified
139139

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

src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopyManager.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,10 @@ export class UntitledFileWorkingCopyManager<M extends IUntitledFileWorkingCopyMo
171171
}
172172

173173
// Handle untitled resource
174-
else if (options.untitledResource?.scheme === Schemas.untitled) {
175-
massagedOptions.untitledResource = options.untitledResource;
174+
else {
175+
if (options.untitledResource?.scheme === Schemas.untitled) {
176+
massagedOptions.untitledResource = options.untitledResource;
177+
}
176178
massagedOptions.isScratchpad = options.isScratchpad;
177179
}
178180

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

0 commit comments

Comments
 (0)