Skip to content

Commit 49b13fd

Browse files
committed
untitled - provide access to models from service
1 parent 985840d commit 49b13fd

File tree

10 files changed

+69
-59
lines changed

10 files changed

+69
-59
lines changed

src/vs/editor/common/services/resolverService.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ export interface ITextEditorModel extends IEditorModel {
6161
* Figure out if this model is resolved or not.
6262
*/
6363
isResolved(): this is IResolvedTextEditorModel;
64+
65+
/**
66+
* The mode id of the text model if known.
67+
*/
68+
getMode(): string | undefined;
6469
}
6570

6671
export interface IResolvedTextEditorModel extends ITextEditorModel {

src/vs/editor/standalone/browser/simpleServices.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ export class SimpleModel implements IResolvedTextEditorModel {
8484
public isResolved(): boolean {
8585
return true;
8686
}
87+
88+
public getMode(): string | undefined {
89+
return this.model.getModeId();
90+
}
8791
}
8892

8993
export interface IOpenEditorDelegate {

src/vs/workbench/browser/labels.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,20 @@ class ResourceLabelWidget extends IconLabel {
361361
// provided. If they are not provided from the label we got
362362
// we assume that the client does not want to display them
363363
// and as such do not override.
364-
const untitledEditor = this.textFileService.untitled.get(label.resource);
365-
if (untitledEditor && !untitledEditor.hasAssociatedFilePath) {
364+
const untitledModel = this.textFileService.untitled.get(label.resource);
365+
if (untitledModel && !untitledModel.hasAssociatedFilePath) {
366366
if (typeof label.name === 'string') {
367-
label.name = untitledEditor.getName();
367+
label.name = untitledModel.name;
368368
}
369369

370370
if (typeof label.description === 'string') {
371-
const untitledDescription = untitledEditor.getDescription();
371+
let untitledDescription: string;
372+
if (untitledModel.hasAssociatedFilePath) {
373+
untitledDescription = this.labelService.getUriLabel(resources.dirname(untitledModel.resource), { relative: true });
374+
} else {
375+
untitledDescription = untitledModel.resource.path;
376+
}
377+
372378
if (label.name !== untitledDescription) {
373379
label.description = untitledDescription;
374380
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,7 @@ export class ChangeModeAction extends Action {
10101010
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
10111011

10121012
let hasLanguageSupport = !!resource;
1013-
if (resource?.scheme === Schemas.untitled && !this.textFileService.untitled.hasAssociatedFilePath(resource)) {
1013+
if (resource?.scheme === Schemas.untitled && !this.textFileService.untitled.get(resource)?.hasAssociatedFilePath) {
10141014
hasLanguageSupport = false; // no configuration for untitled resources (e.g. "Untitled-1")
10151015
}
10161016

src/vs/workbench/common/editor/textEditorModel.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ export class BaseTextEditorModel extends EditorModel implements ITextEditorModel
7777
this.modelService.setMode(this.textEditorModel, this.modeService.create(mode));
7878
}
7979

80+
getMode(): string | undefined {
81+
return this.textEditorModel?.getModeId();
82+
}
83+
8084
/**
8185
* Creates the text editor model with the provided value, optional preferred mode
8286
* (can be comma separated for multiple values) and optional resource URL.

src/vs/workbench/common/editor/untitledTextEditorInput.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export class UntitledTextEditorInput extends TextResourceEditorInput implements
5353
}
5454
}
5555

56+
get model(): UntitledTextEditorModel | undefined {
57+
return this.cachedModel;
58+
}
59+
5660
get hasAssociatedFilePath(): boolean {
5761
return this._hasAssociatedFilePath;
5862
}

src/vs/workbench/common/editor/untitledTextEditorModel.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ import { withNullAsUndefined, assertIsDefined } from 'vs/base/common/types';
2121
import { ILabelService } from 'vs/platform/label/common/label';
2222
import { ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
2323

24-
export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy { }
24+
export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy {
25+
26+
/**
27+
* Wether this untitled text model has an associated file path.
28+
*/
29+
readonly hasAssociatedFilePath: boolean;
30+
}
2531

2632
export class UntitledTextEditorModel extends BaseTextEditorModel implements IUntitledTextEditorModel {
2733

src/vs/workbench/services/textfile/browser/textFileService.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
570570
// Untitled without associated file path
571571
const mode = model.getMode();
572572
if (mode !== PLAINTEXT_MODE_ID) { // do not suggest when the mode ID is simple plain text
573-
suggestedFilename = suggestFilename(mode, model.getName());
573+
suggestedFilename = suggestFilename(mode, model.name);
574574
} else {
575-
suggestedFilename = model.getName();
575+
suggestedFilename = model.name;
576576
}
577577
}
578578
}
@@ -595,7 +595,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex
595595

596596
// Untitled
597597
if (resource.scheme === Schemas.untitled) {
598-
const model = this.untitled.exists(resource) ? await this.untitled.resolve({ untitledResource: resource }) : undefined;
598+
const model = this.untitled.get(resource);
599599
if (model) {
600600
return model.revert(options);
601601
}

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

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,6 @@ export interface IUntitledTextEditorModelManager {
8585
*/
8686
readonly onDidDisposeModel: Event<URI>;
8787

88-
/**
89-
* Returns if an untitled resource with the given URI exists.
90-
*/
91-
exists(resource: URI): boolean;
92-
93-
/**
94-
* Returns an existing untitled input if already created before.
95-
*/
96-
get(resource: URI): UntitledTextEditorInput | undefined;
97-
9888
/**
9989
* Creates a new untitled input with the provided options. If the `untitledResource`
10090
* property is provided and the untitled input exists, it will return that existing
@@ -104,6 +94,11 @@ export interface IUntitledTextEditorModelManager {
10494
create(options?: INewUntitledTextEditorWithAssociatedResourceOptions): UntitledTextEditorInput;
10595
create(options?: IExistingUntitledTextEditorOptions): UntitledTextEditorInput;
10696

97+
/**
98+
* Returns an existing untitled model if already created before.
99+
*/
100+
get(resource: URI): IUntitledTextEditorModel | undefined;
101+
107102
/**
108103
* Resolves an untitled editor model from the provided options. If the `untitledResource`
109104
* property is provided and the untitled input exists, it will return that existing
@@ -112,11 +107,6 @@ export interface IUntitledTextEditorModelManager {
112107
resolve(options?: INewUntitledTextEditorOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
113108
resolve(options?: INewUntitledTextEditorWithAssociatedResourceOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
114109
resolve(options?: IExistingUntitledTextEditorOptions): Promise<IUntitledTextEditorModel & IResolvedTextEditorModel>;
115-
116-
/**
117-
* A check to find out if a untitled resource has a file path associated or not.
118-
*/
119-
hasAssociatedFilePath(resource: URI): boolean;
120110
}
121111

122112
export interface IUntitledTextEditorService extends IUntitledTextEditorModelManager {
@@ -141,7 +131,6 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
141131
readonly onDidChangeLabel = this._onDidChangeLabel.event;
142132

143133
private readonly mapResourceToInput = new ResourceMap<UntitledTextEditorInput>();
144-
private readonly mapResourceToAssociatedFilePath = new ResourceMap<boolean>();
145134

146135
constructor(
147136
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -150,12 +139,8 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
150139
super();
151140
}
152141

153-
exists(resource: URI): boolean {
154-
return this.mapResourceToInput.has(resource);
155-
}
156-
157-
get(resource: URI): UntitledTextEditorInput | undefined {
158-
return this.mapResourceToInput.get(resource);
142+
get(resource: URI): UntitledTextEditorModel | undefined {
143+
return this.mapResourceToInput.get(resource)?.model;
159144
}
160145

161146
resolve(options?: IInternalUntitledTextEditorOptions): Promise<UntitledTextEditorModel & IResolvedTextEditorModel> {
@@ -229,17 +214,22 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
229214
// Create new input with provided options
230215
const input = this.instantiationService.createInstance(UntitledTextEditorInput, untitledResource, !!options.associatedResource, options.mode, options.initialValue, options.encoding);
231216

232-
const dirtyListener = input.onDidChangeDirty(() => this._onDidChangeDirty.fire(input.getResource()));
233-
const labelListener = input.onDidChangeLabel(() => this._onDidChangeLabel.fire(input.getResource()));
234-
const encodingListener = input.onDidModelChangeEncoding(() => this._onDidChangeEncoding.fire(input.getResource()));
235-
const disposeListener = input.onDispose(() => this._onDidDisposeModel.fire(input.getResource()));
217+
this.register(input);
218+
219+
return input;
220+
}
221+
222+
private register(editor: UntitledTextEditorInput): void {
223+
const dirtyListener = editor.onDidChangeDirty(() => this._onDidChangeDirty.fire(editor.getResource()));
224+
const labelListener = editor.onDidChangeLabel(() => this._onDidChangeLabel.fire(editor.getResource()));
225+
const encodingListener = editor.onDidModelChangeEncoding(() => this._onDidChangeEncoding.fire(editor.getResource()));
226+
const disposeListener = editor.onDispose(() => this._onDidDisposeModel.fire(editor.getResource()));
236227

237228
// Remove from cache on dispose
238-
Event.once(input.onDispose)(() => {
229+
Event.once(editor.onDispose)(() => {
239230

240231
// Registry
241-
this.mapResourceToInput.delete(input.getResource());
242-
this.mapResourceToAssociatedFilePath.delete(input.getResource());
232+
this.mapResourceToInput.delete(editor.getResource());
243233

244234
// Listeners
245235
dirtyListener.dispose();
@@ -249,16 +239,7 @@ export class UntitledTextEditorService extends Disposable implements IUntitledTe
249239
});
250240

251241
// Add to cache
252-
this.mapResourceToInput.set(untitledResource, input);
253-
if (options.associatedResource) {
254-
this.mapResourceToAssociatedFilePath.set(untitledResource, true);
255-
}
256-
257-
return input;
258-
}
259-
260-
hasAssociatedFilePath(resource: URI): boolean {
261-
return this.mapResourceToAssociatedFilePath.has(resource);
242+
this.mapResourceToInput.set(editor.getResource(), editor);
262243
}
263244
}
264245

src/vs/workbench/test/browser/parts/editor/untitledTextEditor.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@ suite('Untitled text editors', () => {
5050
const input1 = service.create();
5151
await input1.resolve();
5252
assert.equal(input1, service.create({ untitledResource: input1.getResource() }));
53-
assert.equal(service.get(input1.getResource()), input1);
53+
assert.equal(service.get(input1.getResource()), input1.model);
5454

55-
assert.ok(service.exists(input1.getResource()));
56-
assert.ok(!service.exists(URI.file('testing')));
55+
assert.ok(service.get(input1.getResource()));
56+
assert.ok(!service.get(URI.file('testing')));
5757

5858
const input2 = service.create();
59-
assert.equal(service.get(input2.getResource()), input2);
59+
assert.equal(service.get(input2.getResource()), input2.model);
6060

6161
// get()
62-
assert.equal(service.get(input1.getResource()), input1);
63-
assert.equal(service.get(input2.getResource()), input2);
62+
assert.equal(service.get(input1.getResource()), input1.model);
63+
assert.equal(service.get(input2.getResource()), input2.model);
6464

6565
// revert()
6666
await input1.revert(0);
@@ -70,7 +70,7 @@ suite('Untitled text editors', () => {
7070
// dirty
7171
const model = await input2.resolve();
7272
assert.equal(await service.resolve({ untitledResource: input2.getResource() }), model);
73-
assert.ok(service.exists(model.resource));
73+
assert.ok(service.get(model.resource));
7474

7575
assert.ok(!input2.isDirty());
7676

@@ -99,10 +99,10 @@ suite('Untitled text editors', () => {
9999

100100
assert.equal(await input1.revert(0), false);
101101
assert.ok(input1.isDisposed());
102-
assert.ok(!service.exists(input1.getResource()));
102+
assert.ok(!service.get(input1.getResource()));
103103

104104
input2.dispose();
105-
assert.ok(!service.exists(input2.getResource()));
105+
assert.ok(!service.get(input2.getResource()));
106106
});
107107

108108
function awaitDidChangeDirty(service: IUntitledTextEditorService): Promise<URI> {
@@ -120,7 +120,7 @@ suite('Untitled text editors', () => {
120120
const file = URI.file(join('C:\\', '/foo/file.txt'));
121121
const untitled = service.create({ associatedResource: file });
122122

123-
assert.ok(service.hasAssociatedFilePath(untitled.getResource()));
123+
assert.ok(untitled.hasAssociatedFilePath);
124124
assert.equal(untitled.isDirty(), true);
125125

126126
untitled.dispose();
@@ -165,7 +165,7 @@ suite('Untitled text editors', () => {
165165

166166
const file = URI.file(join('C:\\', '/foo/file44.txt'));
167167
const model4 = await service.create({ associatedResource: file }).resolve();
168-
assert.ok(service.hasAssociatedFilePath(model4.resource));
168+
assert.ok(model4.hasAssociatedFilePath);
169169
assert.ok(model4.isDirty());
170170

171171
model1.dispose();

0 commit comments

Comments
 (0)