Skip to content

Commit 06fc826

Browse files
authored
Copy paste api should not fail on invalid provider (microsoft#182535)
1 parent e47a286 commit 06fc826

File tree

2 files changed

+44
-10
lines changed

2 files changed

+44
-10
lines changed

extensions/vscode-api-tests/src/singlefolder-tests/documentPaste.test.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ const textPlain = 'text/plain';
4949
const str = await existing.asString();
5050
// text/plain includes the trailing new line in this case
5151
// On windows, this will always be `\r\n` even if the document uses `\n`
52-
const eol = str.match(/\r?\n$/);
53-
const reversed = reverseString(str.slice(0, -eol![0].length));
52+
const eol = str.match(/\r?\n$/)?.[0] ?? '\n';
53+
const reversed = reverseString(str.slice(0, -eol.length));
5454
dataTransfer.set(textPlain, new vscode.DataTransferItem(reversed + '\n'));
5555
}
5656
}
@@ -170,7 +170,32 @@ const textPlain = 'text/plain';
170170
const newDocContent = getNextDocumentText(disposables, doc);
171171
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
172172
assert.strictEqual(await newDocContent, 'cba\ndef');
173+
}));
174+
175+
176+
test('One failing provider should not effect other', usingDisposables(async (disposables) => {
177+
const file = await createRandomFile('abc\ndef');
178+
const doc = await vscode.workspace.openTextDocument(file);
179+
180+
const editor = await vscode.window.showTextDocument(doc);
181+
editor.selections = [new vscode.Selection(0, 0, 0, 3)];
182+
183+
disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
184+
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
185+
dataTransfer.set(textPlain, new vscode.DataTransferItem('xyz'));
186+
}
187+
}, { copyMimeTypes: [textPlain] }));
173188

189+
disposables.push(vscode.languages.registerDocumentPasteEditProvider({ language: 'plaintext' }, new class implements vscode.DocumentPasteEditProvider {
190+
async prepareDocumentPaste(_document: vscode.TextDocument, _ranges: readonly vscode.Range[], _dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken): Promise<void> {
191+
throw new Error('Expected testing error from bad provider');
192+
}
193+
}, { copyMimeTypes: [textPlain] }));
194+
195+
await vscode.commands.executeCommand('editor.action.clipboardCopyAction');
196+
const newDocContent = getNextDocumentText(disposables, doc);
197+
await vscode.commands.executeCommand('editor.action.clipboardPasteAction');
198+
assert.strictEqual(await newDocContent, 'xyz\ndef');
174199
}));
175200
});
176201

@@ -181,10 +206,9 @@ function reverseString(str: string) {
181206
function getNextDocumentText(disposables: vscode.Disposable[], doc: vscode.TextDocument): Promise<string> {
182207
return new Promise<string>(resolve => {
183208
disposables.push(vscode.workspace.onDidChangeTextDocument(e => {
184-
if (e.document === doc) {
185-
resolve(doc.getText());
209+
if (e.document.uri.fsPath === doc.uri.fsPath) {
210+
resolve(e.document.getText());
186211
}
187212
}));
188213
});
189214
}
190-

src/vs/editor/contrib/dropOrPasteInto/browser/copyPasteController.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,13 @@ export class CopyPasteController extends Disposable implements IEditorContributi
165165
});
166166

167167
const promise = createCancelablePromise(async token => {
168-
const results = coalesce(await Promise.all(providers.map(provider => {
169-
return provider.prepareDocumentPaste!(model, ranges, dataTransfer, token);
168+
const results = coalesce(await Promise.all(providers.map(async provider => {
169+
try {
170+
return await provider.prepareDocumentPaste!(model, ranges, dataTransfer, token);
171+
} catch (err) {
172+
console.error(err);
173+
return undefined;
174+
}
170175
})));
171176

172177
// Values from higher priority providers should overwrite values from lower priority ones.
@@ -391,9 +396,14 @@ export class CopyPasteController extends Disposable implements IEditorContributi
391396

392397
private async getPasteEdits(providers: readonly DocumentPasteEditProvider[], dataTransfer: VSDataTransfer, model: ITextModel, selections: readonly Selection[], token: CancellationToken): Promise<DocumentPasteEdit[]> {
393398
const result = await raceCancellation(
394-
Promise.all(
395-
providers.map(provider => provider.provideDocumentPasteEdits?.(model, selections, dataTransfer, token))
396-
).then(coalesce),
399+
Promise.all(providers.map(provider => {
400+
try {
401+
return provider.provideDocumentPasteEdits?.(model, selections, dataTransfer, token);
402+
} catch (err) {
403+
console.error(err);
404+
return undefined;
405+
}
406+
})).then(coalesce),
397407
token);
398408
result?.sort((a, b) => b.priority - a.priority);
399409
return result ?? [];

0 commit comments

Comments
 (0)