Merge from vscode 9bc92b48d945144abb405b9e8df05e18accb9148

This commit is contained in:
ADS Merger
2020-02-19 03:11:35 +00:00
parent 98584d32a7
commit 1e308639e5
253 changed files with 6414 additions and 2296 deletions

View File

@@ -58,7 +58,7 @@ suite('MainThreadDocumentsAndEditors', () => {
const editorGroupService = new TestEditorGroupsService();
const fileService = new class extends mock<IFileService>() {
onAfterOperation = Event.None;
onDidRunOperation = Event.None;
};
new MainThreadDocumentsAndEditors(

View File

@@ -40,6 +40,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ILabelService } from 'vs/platform/label/common/label';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
suite('MainThreadEditors', () => {
@@ -79,14 +80,17 @@ suite('MainThreadEditors', () => {
services.set(IEditorGroupsService, new TestEditorGroupsService());
services.set(ITextFileService, new class extends mock<ITextFileService>() {
isDirty() { return false; }
create(uri: URI, contents?: string, options?: any) {
createdResources.add(uri);
create(resource: URI) {
createdResources.add(resource);
return Promise.resolve(Object.create(null));
}
delete(resource: URI) {
deletedResources.add(resource);
return Promise.resolve(undefined);
}
files = <any>{
onDidSave: Event.None,
onDidRevert: Event.None,
onDidChangeDirty: Event.None
};
});
services.set(IWorkingCopyFileService, new class extends mock<IWorkingCopyFileService>() {
move(source: URI, target: URI) {
movedResources.set(source, target);
return Promise.resolve(Object.create(null));
@@ -95,11 +99,10 @@ suite('MainThreadEditors', () => {
copiedResources.set(source, target);
return Promise.resolve(Object.create(null));
}
files = <any>{
onDidSave: Event.None,
onDidRevert: Event.None,
onDidChangeDirty: Event.None
};
delete(resource: URI) {
deletedResources.add(resource);
return Promise.resolve(undefined);
}
});
services.set(ITextModelService, new class extends mock<ITextModelService>() {
createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {

View File

@@ -64,6 +64,9 @@ class MyInputFactory implements IEditorInputFactory {
}
class MyInput extends EditorInput {
readonly resource = undefined;
getPreferredEditorId(ids: string[]) {
return ids[1];
}
@@ -78,6 +81,9 @@ class MyInput extends EditorInput {
}
class MyOtherInput extends EditorInput {
readonly resource = undefined;
getTypeId(): string {
return '';
}
@@ -256,7 +262,7 @@ suite('Workbench base editor', () => {
}
class TestEditorInput extends EditorInput {
constructor(private resource: URI, private id = 'testEditorInputForMementoTest') {
constructor(public resource: URI, private id = 'testEditorInputForMementoTest') {
super();
}
getTypeId() { return 'testEditorInputForMementoTest'; }
@@ -265,10 +271,6 @@ suite('Workbench base editor', () => {
matches(other: TestEditorInput): boolean {
return other && this.id === other.id && other instanceof TestEditorInput;
}
getResource(): URI {
return this.resource;
}
}
const rawMemento = Object.create(null);

View File

@@ -20,7 +20,7 @@ class ServiceAccessor {
class FileEditorInput extends EditorInput {
constructor(private resource: URI) {
constructor(public resource: URI) {
super();
}
@@ -28,10 +28,6 @@ class FileEditorInput extends EditorInput {
return 'editorResourceFileTest';
}
getResource(): URI {
return this.resource;
}
resolve(): Promise<IEditorModel | null> {
return Promise.resolve(null);
}
@@ -58,18 +54,18 @@ suite('Workbench editor', () => {
const untitled = instantiationService.createInstance(UntitledTextEditorInput, service.create());
assert.equal(toResource(untitled)!.toString(), untitled.getResource().toString());
assert.equal(toResource(untitled, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), untitled.getResource().toString());
assert.equal(toResource(untitled, { filterByScheme: Schemas.untitled })!.toString(), untitled.getResource().toString());
assert.equal(toResource(untitled, { filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.getResource().toString());
assert.equal(toResource(untitled)!.toString(), untitled.resource.toString());
assert.equal(toResource(untitled, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), untitled.resource.toString());
assert.equal(toResource(untitled, { filterByScheme: Schemas.untitled })!.toString(), untitled.resource.toString());
assert.equal(toResource(untitled, { filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.resource.toString());
assert.ok(!toResource(untitled, { filterByScheme: Schemas.file }));
const file = new FileEditorInput(URI.file('/some/path.txt'));
assert.equal(toResource(file)!.toString(), file.getResource().toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), file.getResource().toString());
assert.equal(toResource(file, { filterByScheme: Schemas.file })!.toString(), file.getResource().toString());
assert.equal(toResource(file, { filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), file.getResource().toString());
assert.equal(toResource(file)!.toString(), file.resource.toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), file.resource.toString());
assert.equal(toResource(file, { filterByScheme: Schemas.file })!.toString(), file.resource.toString());
assert.equal(toResource(file, { filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), file.resource.toString());
assert.ok(!toResource(file, { filterByScheme: Schemas.untitled }));
const diffEditorInput = new DiffEditorInput('name', 'description', untitled, file);
@@ -77,8 +73,8 @@ suite('Workbench editor', () => {
assert.ok(!toResource(diffEditorInput));
assert.ok(!toResource(diffEditorInput, { filterByScheme: Schemas.file }));
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), file.getResource().toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.file })!.toString(), file.getResource().toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), file.getResource().toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER })!.toString(), file.resource.toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: Schemas.file })!.toString(), file.resource.toString());
assert.equal(toResource(file, { supportSideBySide: SideBySideEditor.MASTER, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), file.resource.toString());
});
});

View File

@@ -73,6 +73,9 @@ function groupListener(group: EditorGroup): GroupEvents {
let index = 0;
class TestEditorInput extends EditorInput {
readonly resource = undefined;
constructor(public id: string) {
super();
}
@@ -93,6 +96,9 @@ class TestEditorInput extends EditorInput {
}
class NonSerializableTestEditorInput extends EditorInput {
readonly resource = undefined;
constructor(public id: string) {
super();
}
@@ -106,7 +112,7 @@ class NonSerializableTestEditorInput extends EditorInput {
class TestFileEditorInput extends EditorInput implements IFileEditorInput {
constructor(public id: string, private resource: URI) {
constructor(public id: string, public resource: URI) {
super();
}
getTypeId() { return 'testFileEditorInputForGroups'; }
@@ -114,7 +120,6 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput {
setEncoding(encoding: string) { }
getEncoding() { return undefined; }
setPreferredEncoding(encoding: string) { }
getResource(): URI { return this.resource; }
setForceOpenAsBinary(): void { }
setMode(mode: string) { }
setPreferredMode(mode: string) { }

View File

@@ -8,6 +8,8 @@ import { EditorInput } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
class MyEditorInput extends EditorInput {
readonly resource = undefined;
getTypeId(): string { return ''; }
resolve(): any { return null; }
}

View File

@@ -40,7 +40,7 @@ suite('Editor - Range decorations', () => {
model = aModel(URI.file('some_file'));
codeEditor = createTestCodeEditor({ model: model });
instantiationService.stub(IEditorService, 'activeEditor', { getResource: () => { return codeEditor.getModel()!.uri; } });
instantiationService.stub(IEditorService, 'activeEditor', { get resource() { return codeEditor.getModel()!.uri; } });
instantiationService.stub(IEditorService, 'activeTextEditorWidget', codeEditor);
testObject = instantiationService.createInstance(RangeHighlightDecorations);

View File

@@ -89,6 +89,8 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel';
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
import { Direction } from 'vs/base/browser/ui/grid/grid';
import { IProgressService, IProgressOptions, IProgressWindowOptions, IProgressNotificationOptions, IProgressCompositeOptions, IProgress, IProgressStep, emptyProgress } from 'vs/platform/progress/common/progress';
import { IWorkingCopyFileService, WorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
export import TestTextResourcePropertiesService = CommonWorkbenchTestServices.TestTextResourcePropertiesService;
export import TestContextService = CommonWorkbenchTestServices.TestContextService;
@@ -120,7 +122,6 @@ export class TestTextFileService extends BrowserTextFileService {
@IFilesConfigurationService filesConfigurationService: IFilesConfigurationService,
@ITextModelService textModelService: ITextModelService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@INotificationService notificationService: INotificationService,
@IRemotePathService remotePathService: IRemotePathService
) {
super(
@@ -136,7 +137,6 @@ export class TestTextFileService extends BrowserTextFileService {
filesConfigurationService,
textModelService,
codeEditorService,
notificationService,
remotePathService
);
}
@@ -172,9 +172,11 @@ export const TestEnvironmentService = new BrowserWorkbenchEnvironmentService(Obj
export function workbenchInstantiationService(overrides?: { textFileService?: (instantiationService: IInstantiationService) => ITextFileService }): ITestInstantiationService {
const instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()]));
instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService());
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
const contextKeyService = <IContextKeyService>instantiationService.createInstance(MockContextKeyService);
instantiationService.stub(IContextKeyService, contextKeyService);
instantiationService.stub(IProgressService, new TestProgressService());
const workspaceContextService = new TestContextService(TestWorkspace);
instantiationService.stub(IWorkspaceContextService, workspaceContextService);
const configService = new TestConfigurationService();
@@ -200,6 +202,7 @@ export function workbenchInstantiationService(overrides?: { textFileService?: (i
instantiationService.stub(IKeybindingService, new MockKeybindingService());
instantiationService.stub(IDecorationsService, new TestDecorationsService());
instantiationService.stub(IExtensionService, new TestExtensionService());
instantiationService.stub(IWorkingCopyFileService, instantiationService.createInstance(WorkingCopyFileService));
instantiationService.stub(ITextFileService, overrides?.textFileService ? overrides.textFileService(instantiationService) : <ITextFileService>instantiationService.createInstance(TestTextFileService));
instantiationService.stub(IHostService, <IHostService>instantiationService.createInstance(TestHostService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
@@ -212,11 +215,23 @@ export function workbenchInstantiationService(overrides?: { textFileService?: (i
instantiationService.stub(IEditorService, editorService);
instantiationService.stub(ICodeEditorService, new TestCodeEditorService());
instantiationService.stub(IViewletService, new TestViewletService());
instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService());
return instantiationService;
}
export class TestProgressService implements IProgressService {
_serviceBrand: undefined;
withProgress(
options: IProgressOptions | IProgressWindowOptions | IProgressNotificationOptions | IProgressCompositeOptions,
task: (progress: IProgress<IProgressStep>) => Promise<any>,
onDidCancel?: ((choice?: number | undefined) => void) | undefined
): Promise<any> {
return task(emptyProgress);
}
}
export class TestAccessibilityService implements IAccessibilityService {
_serviceBrand: undefined;
@@ -588,8 +603,8 @@ export class TestFileService implements IFileService {
_serviceBrand: undefined;
private readonly _onFileChanges: Emitter<FileChangesEvent>;
private readonly _onAfterOperation: Emitter<FileOperationEvent>;
private readonly _onDidFilesChange = new Emitter<FileChangesEvent>();
private readonly _onDidRunOperation = new Emitter<FileOperationEvent>();
readonly onWillActivateFileSystemProvider = Event.None;
readonly onDidChangeFileSystemProviderCapabilities = Event.None;
@@ -598,18 +613,13 @@ export class TestFileService implements IFileService {
private content = 'Hello Html';
private lastReadFileUri!: URI;
constructor() {
this._onFileChanges = new Emitter<FileChangesEvent>();
this._onAfterOperation = new Emitter<FileOperationEvent>();
}
setContent(content: string): void { this.content = content; }
getContent(): string { return this.content; }
getLastReadFileUri(): URI { return this.lastReadFileUri; }
get onFileChanges(): Event<FileChangesEvent> { return this._onFileChanges.event; }
fireFileChanges(event: FileChangesEvent): void { this._onFileChanges.fire(event); }
get onAfterOperation(): Event<FileOperationEvent> { return this._onAfterOperation.event; }
fireAfterOperation(event: FileOperationEvent): void { this._onAfterOperation.fire(event); }
get onDidFilesChange(): Event<FileChangesEvent> { return this._onDidFilesChange.event; }
fireFileChanges(event: FileChangesEvent): void { this._onDidFilesChange.fire(event); }
get onDidRunOperation(): Event<FileOperationEvent> { return this._onDidRunOperation.event; }
fireAfterOperation(event: FileOperationEvent): void { this._onDidRunOperation.fire(event); }
resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat>;
resolve(resource: URI, _options: IResolveMetadataFileOptions): Promise<IFileStatWithMetadata>;
resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat> {

View File

@@ -41,7 +41,7 @@ suite('Notifications', () => {
// Events
let called = 0;
item1.onDidExpansionChange(() => {
item1.onDidChangeExpansion(() => {
called++;
});
@@ -53,7 +53,7 @@ suite('Notifications', () => {
assert.equal(called, 2);
called = 0;
item1.onDidLabelChange(e => {
item1.onDidChangeLabel(e => {
if (e.kind === NotificationViewItemLabelKind.PROGRESS) {
called++;
}
@@ -65,7 +65,7 @@ suite('Notifications', () => {
assert.equal(called, 2);
called = 0;
item1.onDidLabelChange(e => {
item1.onDidChangeLabel(e => {
if (e.kind === NotificationViewItemLabelKind.MESSAGE) {
called++;
}
@@ -74,7 +74,7 @@ suite('Notifications', () => {
item1.updateMessage('message update');
called = 0;
item1.onDidLabelChange(e => {
item1.onDidChangeLabel(e => {
if (e.kind === NotificationViewItemLabelKind.SEVERITY) {
called++;
}
@@ -83,7 +83,7 @@ suite('Notifications', () => {
item1.updateSeverity(Severity.Error);
called = 0;
item1.onDidLabelChange(e => {
item1.onDidChangeLabel(e => {
if (e.kind === NotificationViewItemLabelKind.ACTIONS) {
called++;
}
@@ -105,29 +105,6 @@ suite('Notifications', () => {
let item6 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', { actions: [new Action('id', 'label')] }) })!;
assert.equal(item6.actions!.primary!.length, 1);
// Links
let item7 = NotificationViewItem.create({ severity: Severity.Info, message: 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and [Link 3](command:without.title) and [Invalid Link4](ftp://link4.com)' })!;
const links = item7.message.links;
assert.equal(links.length, 3);
assert.equal(links[0].name, 'Link 1');
assert.equal(links[0].href, 'http://link1.com');
assert.equal(links[0].title, 'http://link1.com');
assert.equal(links[0].length, '[Link 1](http://link1.com)'.length);
assert.equal(links[0].offset, 'Unable to '.length);
assert.equal(links[1].name, 'Link 2');
assert.equal(links[1].href, 'command:open.me');
assert.equal(links[1].title, 'Open This');
assert.equal(links[1].length, '[Link 2](command:open.me "Open This")'.length);
assert.equal(links[1].offset, 'Unable to [Link 1](http://link1.com) open '.length);
assert.equal(links[2].name, 'Link 3');
assert.equal(links[2].href, 'command:without.title');
assert.equal(links[2].title, 'Click to execute command \'without.title\'');
assert.equal(links[2].length, '[Link 3](command:without.title)'.length);
assert.equal(links[2].offset, 'Unable to [Link 1](http://link1.com) open [Link 2](command:open.me "Open This") and '.length);
// Filter
let item8 = NotificationViewItem.create({ severity: Severity.Error, message: 'Error Message' }, NotificationsFilter.SILENT)!;
assert.equal(item8.silent, true);
@@ -146,12 +123,12 @@ suite('Notifications', () => {
const model = new NotificationsModel();
let lastNotificationEvent!: INotificationChangeEvent;
model.onDidNotificationChange(e => {
model.onDidChangeNotification(e => {
lastNotificationEvent = e;
});
let lastStatusMessageEvent!: IStatusMessageChangeEvent;
model.onDidStatusMessageChange(e => {
model.onDidChangeStatusMessage(e => {
lastStatusMessageEvent = e;
});
@@ -162,19 +139,19 @@ suite('Notifications', () => {
let item1Handle = model.addNotification(item1);
assert.equal(lastNotificationEvent.item.severity, item1.severity);
assert.equal(lastNotificationEvent.item.message.value, item1.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item1.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD);
let item2Handle = model.addNotification(item2);
assert.equal(lastNotificationEvent.item.severity, item2.severity);
assert.equal(lastNotificationEvent.item.message.value, item2.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item2.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD);
model.addNotification(item3);
assert.equal(lastNotificationEvent.item.severity, item3.severity);
assert.equal(lastNotificationEvent.item.message.value, item3.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item3.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD);
@@ -189,27 +166,27 @@ suite('Notifications', () => {
assert.equal(called, 1);
assert.equal(model.notifications.length, 2);
assert.equal(lastNotificationEvent.item.severity, item1.severity);
assert.equal(lastNotificationEvent.item.message.value, item1.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item1.message);
assert.equal(lastNotificationEvent.index, 2);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE);
model.addNotification(item2Duplicate);
assert.equal(model.notifications.length, 2);
assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity);
assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item2Duplicate.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD);
item2Handle.close();
assert.equal(model.notifications.length, 1);
assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity);
assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item2Duplicate.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE);
model.notifications[0].expand();
assert.equal(lastNotificationEvent.item.severity, item3.severity);
assert.equal(lastNotificationEvent.item.message.value, item3.message);
assert.equal(lastNotificationEvent.item.message.linkedText.toString(), item3.message);
assert.equal(lastNotificationEvent.index, 0);
assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE);

View File

@@ -1,160 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/api/browser/mainThreadSaveParticipant';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
import { toResource } from 'vs/base/test/common/utils';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { ITextFileService, IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
import { SaveReason } from 'vs/workbench/common/editor';
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
class ServiceAccessor {
constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService) {
}
}
suite('MainThreadSaveParticipant', function () {
let instantiationService: IInstantiationService;
let accessor: ServiceAccessor;
setup(() => {
instantiationService = workbenchInstantiationService();
accessor = instantiationService.createInstance(ServiceAccessor);
});
teardown(() => {
(<TextFileEditorModelManager>accessor.textFileService.files).dispose();
});
test('insert final new line', async function () {
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'insertFinalNewline': true });
const participant = new FinalNewLineParticipant(configService, undefined!);
// No new line for empty lines
let lineContent = '';
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// No new line if last line already empty
lineContent = `Hello New Line${model.textEditorModel.getEOL()}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// New empty line added (single line)
lineContent = 'Hello New Line';
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`);
// New empty line added (multi line)
lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), `${lineContent}${model.textEditorModel.getEOL()}`);
});
test('trim final new lines', async function () {
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Trim New Line';
const eol = `${model.textEditorModel.getEOL()}`;
// No new line removal if last line is not new line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// No new line removal if last line is single new line
lineContent = `${textContent}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), lineContent);
// Remove new line (single line with two new lines)
lineContent = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
// Remove new lines (multiple lines with multiple new lines)
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
await participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${textContent}${eol}`);
});
test('trim final new lines bug#39750', async function () {
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Trim New Line';
// single line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
// apply edits and push to undo stack.
let textEdits = [{ range: new Range(1, 14, 1, 14), text: '.', forceMoveMarkers: false }];
model.textEditorModel.pushEditOperations([new Selection(1, 14, 1, 14)], textEdits, () => { return [new Selection(1, 15, 1, 15)]; });
// undo
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}`);
// trim final new lines should not mess the undo stack
await participant.participate(model, { reason: SaveReason.EXPLICIT });
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}.`);
});
test('trim final new lines bug#46075', async function () {
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined!);
const textContent = 'Test';
const eol = `${model.textEditorModel.getEOL()}`;
let content = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(content);
// save many times
for (let i = 0; i < 10; i++) {
await participant.participate(model, { reason: SaveReason.EXPLICIT });
}
// confirm trimming
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
// undo should go back to previous content immediately
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}${eol}`);
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
});
});

View File

@@ -22,7 +22,6 @@ import { IProductService } from 'vs/platform/product/common/productService';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { URI } from 'vs/base/common/uri';
import { IReadTextFileOptions, ITextFileStreamContent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel';
@@ -62,7 +61,6 @@ export class TestTextFileService extends NativeTextFileService {
@IFilesConfigurationService filesConfigurationService: IFilesConfigurationService,
@ITextModelService textModelService: ITextModelService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@INotificationService notificationService: INotificationService,
@IRemotePathService remotePathService: IRemotePathService
) {
super(
@@ -79,7 +77,6 @@ export class TestTextFileService extends NativeTextFileService {
filesConfigurationService,
textModelService,
codeEditorService,
notificationService,
remotePathService
);
}