Use canonical uris when applying bulk edits (#159067)

* Use canonical uris when applying bulk edits

* move `reviveWorkspaceEditDto` into mainThreadBulkEdit
* make `reviveWorkspaceEditDto` require the uri ident service
* add test

fixes https://github.com/microsoft/vscode/issues/158845

* revive first, otherwise the `is` checks don't work

* fix tests
This commit is contained in:
Johannes Rieken
2022-09-06 14:51:11 +02:00
committed by GitHub
parent ba6d0bd1d9
commit e0ccceeb04
9 changed files with 124 additions and 33 deletions

View File

@@ -57,6 +57,7 @@ import 'vs/editor/contrib/inlayHints/browser/inlayHintsController';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
import { assertType } from 'vs/base/common/types';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
function assertRejects(fn: () => Promise<any>, message: string = 'Expected rejection') {
return fn().then(() => assert.ok(false, message), _err => assert.ok(true));
@@ -95,6 +96,11 @@ suite('ExtHostLanguageFeatureCommands', function () {
// Use IInstantiationService to get typechecking when instantiating
rpcProtocol = new TestRPCProtocol();
const services = new ServiceCollection();
services.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {
override asCanonicalUri(uri: URI): URI {
return uri;
}
});
services.set(ILanguageFeaturesService, new SyncDescriptor(LanguageFeaturesService));
services.set(IExtensionService, new class extends mock<IExtensionService>() {
override async activateByEvent() {

View File

@@ -54,6 +54,7 @@ import { OutlineModel } from 'vs/editor/contrib/documentSymbols/browser/outlineM
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
import { CodeActionTriggerSource } from 'vs/editor/contrib/codeAction/browser/types';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
suite('ExtHostLanguageFeatures', function () {
@@ -88,6 +89,11 @@ suite('ExtHostLanguageFeatures', function () {
const instantiationService = new TestInstantiationService();
instantiationService.stub(IMarkerService, MarkerService);
instantiationService.set(ILanguageFeaturesService, languageFeaturesService);
instantiationService.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {
override asCanonicalUri(uri: URI): URI {
return uri;
}
});
inst = instantiationService;
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IWorkspaceTextEditDto } from 'vs/workbench/api/common/extHost.protocol';
import { mock } from 'vs/base/test/common/mock';
import { Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
import { reviveWorkspaceEditDto } from 'vs/workbench/api/browser/mainThreadBulkEdits';
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
import { IWorkspaceTextEdit } from 'vs/editor/common/languages';
suite('MainThreadBulkEdits', function () {
test('"Rename failed to apply edits" in monorepo with pnpm #158845', function () {
const fileService = new class extends mock<IFileService>() {
override onDidChangeFileSystemProviderCapabilities = Event.None;
override onDidChangeFileSystemProviderRegistrations = Event.None;
override hasProvider(uri: URI) {
return true;
}
override hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean {
// if (resource.scheme === 'case' && capability === FileSystemProviderCapabilities.PathCaseSensitive) {
// return false;
// }
// NO capabilities, esp not being case-sensitive
return false;
}
};
const uriIdentityService = new UriIdentityService(fileService);
const edits: IWorkspaceTextEditDto[] = [
{ resource: URI.from({ scheme: 'case', path: '/hello/WORLD/foo.txt' }), textEdit: { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, text: 'sss' }, versionId: undefined },
{ resource: URI.from({ scheme: 'case', path: '/heLLO/world/fOO.txt' }), textEdit: { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, text: 'sss' }, versionId: undefined },
{ resource: URI.from({ scheme: 'case', path: '/other/path.txt' }), textEdit: { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, text: 'sss' }, versionId: undefined },
{ resource: URI.from({ scheme: 'foo', path: '/other/path.txt' }), textEdit: { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }, text: 'sss' }, versionId: undefined },
];
const out = reviveWorkspaceEditDto({ edits }, uriIdentityService);
assert.strictEqual((<IWorkspaceTextEdit>out.edits[0]).resource.path, '/hello/WORLD/foo.txt');
assert.strictEqual((<IWorkspaceTextEdit>out.edits[1]).resource.path, '/hello/WORLD/foo.txt'); // the FIRST occurrence defined the shape!
assert.strictEqual((<IWorkspaceTextEdit>out.edits[2]).resource.path, '/other/path.txt');
assert.strictEqual((<IWorkspaceTextEdit>out.edits[3]).resource.path, '/other/path.txt');
});
});

View File

@@ -46,7 +46,6 @@ import { TestNotificationService } from 'vs/platform/notification/test/common/te
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TestTextResourcePropertiesService, TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
import { extUri } from 'vs/base/common/resources';
import { ITextSnapshot } from 'vs/editor/common/model';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -57,6 +56,7 @@ import { LanguageFeatureDebounceService } from 'vs/editor/common/services/langua
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
import { MainThreadBulkEdits } from 'vs/workbench/api/browser/mainThreadBulkEdits';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
suite('MainThreadEditors', () => {
@@ -113,6 +113,7 @@ suite('MainThreadEditors', () => {
services.set(IModelService, modelService);
services.set(ICodeEditorService, new TestCodeEditorService(themeService));
services.set(IFileService, new TestFileService());
services.set(IUriIdentityService, new SyncDescriptor(UriIdentityService));
services.set(IEditorService, new TestEditorService());
services.set(ILifecycleService, new TestLifecycleService());
services.set(IWorkingCopyService, new TestWorkingCopyService());
@@ -181,9 +182,6 @@ suite('MainThreadEditors', () => {
return undefined;
}
});
services.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {
override get extUri() { return extUri; }
});
const instaService = new InstantiationService(services);