提交 1762d508 编写于 作者: B Benjamin Pasero

working copies - add name property

上级 eda792e0
...@@ -18,7 +18,6 @@ import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverServ ...@@ -18,7 +18,6 @@ import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverServ
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
/** /**
* An editor input to be used for untitled text buffers. * An editor input to be used for untitled text buffers.
...@@ -29,13 +28,10 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin ...@@ -29,13 +28,10 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
private static readonly MEMOIZER = createMemoizer(); private static readonly MEMOIZER = createMemoizer();
private static readonly FIRST_LINE_MAX_TITLE_LENGTH = 50;
private readonly _onDidModelChangeEncoding = this._register(new Emitter<void>()); private readonly _onDidModelChangeEncoding = this._register(new Emitter<void>());
readonly onDidModelChangeEncoding = this._onDidModelChangeEncoding.event; readonly onDidModelChangeEncoding = this._onDidModelChangeEncoding.event;
private cachedModel: UntitledTextEditorModel | null = null; private cachedModel: UntitledTextEditorModel | null = null;
private cachedModelFirstWords: string | undefined = undefined;
private modelResolve: Promise<UntitledTextEditorModel & IResolvedTextEditorModel> | null = null; private modelResolve: Promise<UntitledTextEditorModel & IResolvedTextEditorModel> | null = null;
...@@ -76,15 +72,10 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin ...@@ -76,15 +72,10 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
} }
getName(): string { getName(): string {
if (this.cachedModel) {
// Take name from first words if present and only if return this.cachedModel.name;
// we have no associated file path. In that case we
// prefer the file name as title.
if (!this._hasAssociatedFilePath && this.cachedModelFirstWords) {
return this.cachedModelFirstWords;
} }
// Otherwise fallback to resource
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path; return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
} }
...@@ -294,32 +285,7 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin ...@@ -294,32 +285,7 @@ export class UntitledTextEditorInput extends TextEditorInput implements IEncodin
// re-emit some events from the model // re-emit some events from the model
this._register(model.onDidChangeDirty(() => this._onDidChangeDirty.fire())); this._register(model.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
this._register(model.onDidChangeEncoding(() => this._onDidModelChangeEncoding.fire())); this._register(model.onDidChangeEncoding(() => this._onDidModelChangeEncoding.fire()));
this._register(model.onDidChangeName(() => this._onDidChangeLabel.fire()));
// listen for first line change events if we use it for the label
// by checking the contents of the first line has changed
if (!this._hasAssociatedFilePath) {
this._register(model.onDidChangeFirstLine(() => this.onDidChangeFirstLine(model)));
}
}
private onDidChangeFirstLine(model: UntitledTextEditorModel): void {
// Determine the first words of the model following these rules:
// - cannot be only whitespace (so we trim())
// - cannot be only non-alphanumeric characters (so we run word definition regex over it)
// - cannot be longer than FIRST_LINE_MAX_TITLE_LENGTH
let modelFirstWordsCandidate: string | undefined = undefined;
const firstLineText = model.textEditorModel?.getValueInRange({ startLineNumber: 1, endLineNumber: 1, startColumn: 1, endColumn: UntitledTextEditorInput.FIRST_LINE_MAX_TITLE_LENGTH }).trim();
if (firstLineText && ensureValidWordDefinition().exec(firstLineText)) {
modelFirstWordsCandidate = firstLineText;
}
if (modelFirstWordsCandidate !== this.cachedModelFirstWords) {
this.cachedModelFirstWords = modelFirstWordsCandidate;
this._onDidChangeLabel.fire();
}
} }
matches(otherInput: unknown): boolean { matches(otherInput: unknown): boolean {
......
...@@ -18,16 +18,20 @@ import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities, IWorkingCop ...@@ -18,16 +18,20 @@ import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities, IWorkingCop
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents'; import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { withNullAsUndefined } from 'vs/base/common/types'; import { withNullAsUndefined } from 'vs/base/common/types';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy { } export interface IUntitledTextEditorModel extends ITextEditorModel, IModeSupport, IEncodingSupport, IWorkingCopy { }
export class UntitledTextEditorModel extends BaseTextEditorModel implements IUntitledTextEditorModel { export class UntitledTextEditorModel extends BaseTextEditorModel implements IUntitledTextEditorModel {
private static readonly FIRST_LINE_NAME_MAX_LENGTH = 50;
private readonly _onDidChangeContent = this._register(new Emitter<void>()); private readonly _onDidChangeContent = this._register(new Emitter<void>());
readonly onDidChangeContent = this._onDidChangeContent.event; readonly onDidChangeContent = this._onDidChangeContent.event;
private readonly _onDidChangeFirstLine = this._register(new Emitter<void>()); private readonly _onDidChangeName = this._register(new Emitter<void>());
readonly onDidChangeFirstLine = this._onDidChangeFirstLine.event; readonly onDidChangeName = this._onDidChangeName.event;
private readonly _onDidChangeDirty = this._register(new Emitter<void>()); private readonly _onDidChangeDirty = this._register(new Emitter<void>());
readonly onDidChangeDirty = this._onDidChangeDirty.event; readonly onDidChangeDirty = this._onDidChangeDirty.event;
...@@ -37,6 +41,19 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt ...@@ -37,6 +41,19 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
readonly capabilities = WorkingCopyCapabilities.Untitled; readonly capabilities = WorkingCopyCapabilities.Untitled;
private cachedModelFirstLineWords: string | undefined = undefined;
get name(): string {
// Take name from first line if present and only if
// we have no associated file path. In that case we
// prefer the file name as title.
if (!this.hasAssociatedFilePath && this.cachedModelFirstLineWords) {
return this.cachedModelFirstLineWords;
}
// Otherwise fallback to resource
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
}
private dirty = false; private dirty = false;
private versionId = 0; private versionId = 0;
private configuredEncoding: string | undefined; private configuredEncoding: string | undefined;
...@@ -158,6 +175,11 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt ...@@ -158,6 +175,11 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
this.updateTextEditorModel(untitledContents, this.preferredMode); this.updateTextEditorModel(untitledContents, this.preferredMode);
} }
// Name
if (backup || this.initialValue) {
this.updateNameFromFirstLine();
}
// Encoding // Encoding
this.configuredEncoding = this.configurationService.getValue<string>(this.resource, 'files.encoding'); this.configuredEncoding = this.configurationService.getValue<string>(this.resource, 'files.encoding');
...@@ -174,7 +196,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt ...@@ -174,7 +196,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
// as the appropiate events to the outside. // as the appropiate events to the outside.
if (backup || this.initialValue) { if (backup || this.initialValue) {
this._onDidChangeContent.fire(); this._onDidChangeContent.fire();
this._onDidChangeFirstLine.fire();
} }
return this as UntitledTextEditorModel & IResolvedTextEditorModel; return this as UntitledTextEditorModel & IResolvedTextEditorModel;
...@@ -198,12 +219,35 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt ...@@ -198,12 +219,35 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt
this.setDirty(true); this.setDirty(true);
} }
// Check for name change if first line changed
if (e.changes.some(change => change.range.startLineNumber === 1 || change.range.endLineNumber === 1)) {
this.updateNameFromFirstLine();
}
// Emit as general content change event // Emit as general content change event
this._onDidChangeContent.fire(); this._onDidChangeContent.fire();
}
// Emit as first line change event depending on actual change private updateNameFromFirstLine(): void {
if (e.changes.some(change => change.range.startLineNumber === 1 || change.range.endLineNumber === 1)) { if (this.hasAssociatedFilePath) {
this._onDidChangeFirstLine.fire(); return; // not in case of an associated file path
}
// Determine the first words of the model following these rules:
// - cannot be only whitespace (so we trim())
// - cannot be only non-alphanumeric characters (so we run word definition regex over it)
// - cannot be longer than FIRST_LINE_MAX_TITLE_LENGTH
let modelFirstWordsCandidate: string | undefined = undefined;
const firstLineText = this.textEditorModel?.getValueInRange({ startLineNumber: 1, endLineNumber: 1, startColumn: 1, endColumn: UntitledTextEditorModel.FIRST_LINE_NAME_MAX_LENGTH }).trim();
if (firstLineText && ensureValidWordDefinition().exec(firstLineText)) {
modelFirstWordsCandidate = firstLineText;
}
if (modelFirstWordsCandidate !== this.cachedModelFirstLineWords) {
this.cachedModelFirstLineWords = modelFirstWordsCandidate;
this._onDidChangeName.fire();
} }
} }
......
...@@ -165,7 +165,7 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont ...@@ -165,7 +165,7 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont
private async confirmBeforeShutdown(workingCopies: IWorkingCopy[]): Promise<boolean> { private async confirmBeforeShutdown(workingCopies: IWorkingCopy[]): Promise<boolean> {
// Show confirm dialog for all dirty working copies // Show confirm dialog for all dirty working copies
const confirm = await this.fileDialogService.showSaveConfirm(workingCopies.map(workingCopy => workingCopy.resource)); const confirm = await this.fileDialogService.showSaveConfirm(workingCopies.map(workingCopy => workingCopy.name));
// Save // Save
if (confirm === ConfirmResult.SAVE) { if (confirm === ConfirmResult.SAVE) {
...@@ -214,7 +214,6 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont ...@@ -214,7 +214,6 @@ export class NativeBackupTracker extends BackupTracker implements IWorkbenchCont
result = await this.editorService.saveAll({ includeUntitled: typeof arg1 === 'boolean' ? arg1 : true, ...saveOptions }); result = await this.editorService.saveAll({ includeUntitled: typeof arg1 === 'boolean' ? arg1 : true, ...saveOptions });
} }
// If we still have dirty working copies, save those directly // If we still have dirty working copies, save those directly
// unless the save was not successful (e.g. cancelled) // unless the save was not successful (e.g. cancelled)
if (result !== false) { if (result !== false) {
......
...@@ -31,6 +31,8 @@ import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/edito ...@@ -31,6 +31,8 @@ import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/edito
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { CustomFileEditorInput } from './customEditorInput'; import { CustomFileEditorInput } from './customEditorInput';
import { Emitter } from 'vs/base/common/event'; import { Emitter } from 'vs/base/common/event';
import { ILabelService } from 'vs/platform/label/common/label';
export const defaultEditorId = 'default'; export const defaultEditorId = 'default';
const defaultEditorInfo = new CustomEditorInfo({ const defaultEditorInfo = new CustomEditorInfo({
...@@ -110,10 +112,11 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ ...@@ -110,10 +112,11 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@IQuickInputService private readonly quickInputService: IQuickInputService, @IQuickInputService private readonly quickInputService: IQuickInputService,
@IWebviewService private readonly webviewService: IWebviewService, @IWebviewService private readonly webviewService: IWebviewService,
@ILabelService labelService: ILabelService
) { ) {
super(); super();
this._models = new CustomEditorModelManager(workingCopyService); this._models = new CustomEditorModelManager(workingCopyService, labelService);
this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService); this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService);
this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService); this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService);
......
...@@ -7,8 +7,10 @@ import { Emitter, Event } from 'vs/base/common/event'; ...@@ -7,8 +7,10 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ICustomEditorModel, CustomEditorEdit, CustomEditorSaveAsEvent, CustomEditorSaveEvent } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { ICustomEditorModel, CustomEditorEdit, CustomEditorSaveAsEvent, CustomEditorSaveEvent } from 'vs/workbench/contrib/customEditor/common/customEditor';
import { WorkingCopyCapabilities, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor'; import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
import { ILabelService } from 'vs/platform/label/common/label';
import { basename } from 'vs/base/common/path';
export class CustomEditorModel extends Disposable implements ICustomEditorModel { export class CustomEditorModel extends Disposable implements ICustomEditorModel {
...@@ -19,6 +21,7 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel ...@@ -19,6 +21,7 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel
constructor( constructor(
public readonly viewType: string, public readonly viewType: string,
private readonly _resource: URI, private readonly _resource: URI,
private readonly labelService: ILabelService
) { ) {
super(); super();
} }
...@@ -34,6 +37,10 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel ...@@ -34,6 +37,10 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel
return this._resource; return this._resource;
} }
public get name() {
return basename(this.labelService.getUriLabel(this._resource));
}
public get capabilities(): WorkingCopyCapabilities { public get capabilities(): WorkingCopyCapabilities {
return 0; return 0;
} }
...@@ -189,9 +196,4 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel ...@@ -189,9 +196,4 @@ export class CustomEditorModel extends Disposable implements ICustomEditorModel
this.updateDirty(); this.updateDirty();
this.updateContentChanged(); this.updateContentChanged();
} }
public async backup(): Promise<IWorkingCopyBackup> {
// TODO@matt implement
return {};
}
} }
...@@ -8,12 +8,14 @@ import { URI } from 'vs/base/common/uri'; ...@@ -8,12 +8,14 @@ import { URI } from 'vs/base/common/uri';
import { ICustomEditorModel, ICustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { ICustomEditorModel, ICustomEditorModelManager } from 'vs/workbench/contrib/customEditor/common/customEditor';
import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/common/customEditorModel'; import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/common/customEditorModel';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { ILabelService } from 'vs/platform/label/common/label';
export class CustomEditorModelManager implements ICustomEditorModelManager { export class CustomEditorModelManager implements ICustomEditorModelManager {
private readonly _models = new Map<string, { readonly model: CustomEditorModel, readonly disposables: DisposableStore }>(); private readonly _models = new Map<string, { readonly model: CustomEditorModel, readonly disposables: DisposableStore }>();
constructor( constructor(
@IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService, @IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService,
@ILabelService private readonly _labelService: ILabelService
) { } ) { }
...@@ -27,7 +29,7 @@ export class CustomEditorModelManager implements ICustomEditorModelManager { ...@@ -27,7 +29,7 @@ export class CustomEditorModelManager implements ICustomEditorModelManager {
return existing; return existing;
} }
const model = new CustomEditorModel(viewType, resource); const model = new CustomEditorModel(viewType, resource, this._labelService);
const disposables = new DisposableStore(); const disposables = new DisposableStore();
disposables.add(this._workingCopyService.registerWorkingCopy(model)); disposables.add(this._workingCopyService.registerWorkingCopy(model));
this._models.set(this.key(resource, viewType), { model, disposables }); this._models.set(this.key(resource, viewType), { model, disposables });
......
...@@ -66,6 +66,7 @@ export class SearchEditorInput extends EditorInput { ...@@ -66,6 +66,7 @@ export class SearchEditorInput extends EditorInput {
const workingCopyAdapter: IWorkingCopy = { const workingCopyAdapter: IWorkingCopy = {
resource: this.resource, resource: this.resource,
name: basename(this.resource.path),
capabilities: this.resource.scheme === 'search-editor' ? WorkingCopyCapabilities.Untitled : 0, capabilities: this.resource.scheme === 'search-editor' ? WorkingCopyCapabilities.Untitled : 0,
onDidChangeDirty: this.onDidChangeDirty, onDidChangeDirty: this.onDidChangeDirty,
onDidChangeContent: this.onDidChangeDirty, onDidChangeContent: this.onDidChangeDirty,
......
...@@ -19,11 +19,12 @@ import { timeout } from 'vs/base/common/async'; ...@@ -19,11 +19,12 @@ import { timeout } from 'vs/base/common/async';
import { ITextBufferFactory } from 'vs/editor/common/model'; import { ITextBufferFactory } from 'vs/editor/common/model';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { basename } from 'vs/base/common/resources'; import { basename } from 'vs/base/common/path';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { IWorkingCopyService, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { IWorkingCopyService, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { SaveSequentializer } from 'vs/workbench/services/textfile/common/saveSequenzializer'; import { SaveSequentializer } from 'vs/workbench/services/textfile/common/saveSequenzializer';
import { ILabelService } from 'vs/platform/label/common/label';
interface IBackupMetaData { interface IBackupMetaData {
mtime: number; mtime: number;
...@@ -74,6 +75,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ...@@ -74,6 +75,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
readonly capabilities = 0; readonly capabilities = 0;
readonly name = basename(this.labelService.getUriLabel(this.resource));
private contentEncoding: string | undefined; // encoding as reported from disk private contentEncoding: string | undefined; // encoding as reported from disk
private versionId = 0; private versionId = 0;
...@@ -103,7 +106,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ...@@ -103,7 +106,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
@IBackupFileService private readonly backupFileService: IBackupFileService, @IBackupFileService private readonly backupFileService: IBackupFileService,
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
@IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService,
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService @IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService,
@ILabelService private readonly labelService: ILabelService
) { ) {
super(modelService, modeService); super(modelService, modeService);
...@@ -286,7 +290,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ...@@ -286,7 +290,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
// Load with backup // Load with backup
this.loadFromContent({ this.loadFromContent({
resource: this.resource, resource: this.resource,
name: basename(this.resource), name: this.name,
mtime: backup.meta ? backup.meta.mtime : Date.now(), mtime: backup.meta ? backup.meta.mtime : Date.now(),
ctime: backup.meta ? backup.meta.ctime : Date.now(), ctime: backup.meta ? backup.meta.ctime : Date.now(),
size: backup.meta ? backup.meta.size : 0, size: backup.meta ? backup.meta.size : 0,
...@@ -784,7 +788,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ...@@ -784,7 +788,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
const notificationService = this.notificationService; const notificationService = this.notificationService;
TextFileEditorModel.setSaveErrorHandler({ TextFileEditorModel.setSaveErrorHandler({
onSaveError(error: Error, model: TextFileEditorModel): void { onSaveError(error: Error, model: TextFileEditorModel): void {
notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(model.resource), toErrorMessage(error, false))); notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", model.name, toErrorMessage(error, false)));
} }
}); });
} }
......
...@@ -44,6 +44,8 @@ export interface IWorkingCopy { ...@@ -44,6 +44,8 @@ export interface IWorkingCopy {
readonly resource: URI; readonly resource: URI;
readonly name: string;
readonly capabilities: WorkingCopyCapabilities; readonly capabilities: WorkingCopyCapabilities;
......
...@@ -10,6 +10,7 @@ import { Emitter } from 'vs/base/common/event'; ...@@ -10,6 +10,7 @@ import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; import { TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices';
import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor'; import { ISaveOptions, IRevertOptions } from 'vs/workbench/common/editor';
import { basename } from 'vs/base/common/resources';
suite('WorkingCopyService', () => { suite('WorkingCopyService', () => {
...@@ -26,6 +27,8 @@ suite('WorkingCopyService', () => { ...@@ -26,6 +27,8 @@ suite('WorkingCopyService', () => {
readonly capabilities = 0; readonly capabilities = 0;
readonly name = basename(this.resource);
private dirty = false; private dirty = false;
constructor(public readonly resource: URI, isDirty = false) { constructor(public readonly resource: URI, isDirty = false) {
......
...@@ -367,14 +367,14 @@ suite('Workbench untitled text editors', () => { ...@@ -367,14 +367,14 @@ suite('Workbench untitled text editors', () => {
model.dispose(); model.dispose();
}); });
test('model#onDidChangeFirstLine and input name', async function () { test('model#onDidChangeName and input name', async function () {
const service = accessor.untitledTextEditorService; const service = accessor.untitledTextEditorService;
const input = service.create(); const input = service.create();
let counter = 0; let counter = 0;
let model = await input.resolve(); let model = await input.resolve();
model.onDidChangeFirstLine(() => counter++); model.onDidChangeName(() => counter++);
model.textEditorModel.setValue('foo'); model.textEditorModel.setValue('foo');
assert.equal(input.getName(), 'foo'); assert.equal(input.getName(), 'foo');
...@@ -396,10 +396,10 @@ suite('Workbench untitled text editors', () => { ...@@ -396,10 +396,10 @@ suite('Workbench untitled text editors', () => {
model.textEditorModel.setValue('([]}hello '); // require actual words model.textEditorModel.setValue('([]}hello '); // require actual words
assert.equal(input.getName(), '([]}hello'); assert.equal(input.getName(), '([]}hello');
assert.equal(counter, 6); assert.equal(counter, 4);
model.textEditorModel.setValue('Hello\nWorld'); model.textEditorModel.setValue('Hello\nWorld');
assert.equal(counter, 7); assert.equal(counter, 5);
function createSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): IIdentifiedSingleEditOperation { function createSingleEditOp(text: string, positionLineNumber: number, positionColumn: number, selectionLineNumber: number = positionLineNumber, selectionColumn: number = positionColumn): IIdentifiedSingleEditOperation {
let range = new Range( let range = new Range(
...@@ -418,7 +418,7 @@ suite('Workbench untitled text editors', () => { ...@@ -418,7 +418,7 @@ suite('Workbench untitled text editors', () => {
} }
model.textEditorModel.applyEdits([createSingleEditOp('hello', 2, 2)]); model.textEditorModel.applyEdits([createSingleEditOp('hello', 2, 2)]);
assert.equal(counter, 7); // change was not on first line assert.equal(counter, 5); // change was not on first line
input.dispose(); input.dispose();
model.dispose(); model.dispose();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册