Change:
<!-- Do Not Delete This! bugreporttemplate --<!-- Please read our Rules of Conduct: --<!-- Please search existing issues to avoid creating duplicates. --<!-- Also please test using the latest insiders build to make sure your issue has not already been fixed: --<!-- Use Help Report Issue to prefill these. --- VSCode Version: Codespaces OS Version: MacOS Catalina and iPadOS 13 Steps to Reproduce: It seems the Clipboard API is not working, at least using Safari an extension using the which as documented, should be used on Remote Development: Codespaces and install the extension (My extension does exactly that) its command , which will select the word where the cursor is located and should copy the selected text to clipboard to other location command (or use shortcut) ’t work: instead of pasting the the newly selected/copied text, it pastes the previous clipboard content (not created using the extension) I tested on iPadOS 13 and MacOS Catalina and it fails. I tested on Edge (Chromium) and it works perfectly (I guess it should work on Chrome too) I didn’t test on Firefox (yet). BTW, I tried to debug my extension on Codespaces (on iPadOS), but it seems not possible/supported. I’m able to build the extension and hit the Debug button. The Debug toolbar appears but no window/tab appears. Is there a way to debug VSCode extensions right from Codespaces?. <!-- Launch with to check. --Does this issue occur when all extensions are disabled?: Yes
Updated the description and comments. Testing on Edge (Chromium) worked just fine.
Yes, it should open a new tab. Maybe it was blocked?
Hi , Sorry about not updating the description properly. I tested debugging again later (yesterday) and indeed it was blocked by Safari, but only on Desktop (macOS Catalina). On iPadOS, it doesn't display anything (neither a blocked windows warning/icon), so I couldn't debug, yet. I'll update the description. Thanks
I think the safari label should remain, because the issue is happening using Safari, both on MacOS and iPadOS.
It seems the Clipboard API is coming to Safari , we should reevaluate once it lands in Safari stable.
I tested the improvements of api in the latest Safari Technology Preview but it doesn't solve this particular problem. The copy/paste request is coming from the extension host instead of user action, Safari will then block it.
Just hit this in
verification steps: Open on Safari (bonus points for it being on iPad but it doesn't matter) Install the GHPR extension Go to a random line in a file Run the command Your clipboard should contain the copied permalink now. Bonus points: make sure Edge or Chrome still also work.
Hi , I’m glad to report that it is also working on iPadOS 15.2 and MacOS Big Sur I just tested my Copy Word extension (the reason why I opened this issue) and it is working perfectly. Thank you!

Discussion:
ensure(IOpenerService, () => new OpenerService(codeEditorService, commandService)); <del> ensure(IClipboardService, () => new BrowserClipboardService()); </del> <ins> ensure(IClipboardService, () => new BrowserClipboardService(layoutService, logService)); </ins> ensure(IContextMenuService, () => { const contextMenuService = new ContextMenuService(telemetryService, notificationService, contextViewService, keybindingService, themeService);

*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> import { $ } from 'vs/base/browser/dom'; </del> <ins> import { isWebKit } from 'vs/base/browser/browser'; import { $, addDisposableListener } from 'vs/base/browser/dom'; import { DeferredPromise } from 'vs/base/common/async'; import { Disposable } from 'vs/base/common/lifecycle'; </ins> import { URI } from 'vs/base/common/uri'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; <ins> import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { ILogService } from 'vs/platform/log/common/log'; </ins> <del> export class BrowserClipboardService implements IClipboardService { </del> <ins> export class BrowserClipboardService extends Disposable implements IClipboardService { </ins> declare readonly _serviceBrand: undefined; private readonly mapTextToType = new Map<string, string>(); // unsupported in web (only in-memory) <ins> constructor( @ILayoutService private readonly layoutService: ILayoutService, @ILogService private readonly logService: ILogService) { super(); if (isWebKit) { this.installWebKitWriteTextWorkaround(); } } private webKitPendingClipboardWritePromise: DeferredPromise<string> | undefined; // In Safari, it has the following note: // // "The request to write to the clipboard must be triggered during a user gesture. // A call to clipboard.write or clipboard.writeText outside the scope of a user // gesture(such as "click" or "touch" event handlers) will result in the immediate // rejection of the promise returned by the API call." // From: https://webkit.org/blog/10855/async-clipboard-api/ // // Since extensions run in a web worker, and handle gestures in an asynchronous way, // they are not classified by Safari as "in response to a user gesture" and will reject. // // This function sets up some handlers to work around that behavior. private installWebKitWriteTextWorkaround(): void { const handler = () => { const currentWritePromise = new DeferredPromise<string>(); // Cancel the previous promise since we just created a new one in response to this new event if (this.webKitPendingClipboardWritePromise && !this.webKitPendingClipboardWritePromise.isSettled) { this.webKitPendingClipboardWritePromise.cancel(); } this.webKitPendingClipboardWritePromise = currentWritePromise; // The ctor of ClipboardItem allows you to pass in a promise that will resolve to a string. // This allows us to pass in a Promise that will either be cancelled by another event or // resolved with the contents of the first call to this.writeText. // see https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#parameters navigator.clipboard.write([new ClipboardItem({ 'text/plain': currentWritePromise.p, })]).catch(async err => { if (!(err instanceof Error) || err.name !== 'NotAllowedError' || !currentWritePromise.isRejected) { this.logService.error(err); } }); }; this._register(addDisposableListener(this.layoutService.container, 'click', handler)); this._register(addDisposableListener(this.layoutService.container, 'keydown', handler)); } </ins> async writeText(text: string, type?: string): Promise<void> { // With type: only in-memory is supported

return; } <ins> if (this.webKitPendingClipboardWritePromise) { // For Safari, we complete this Promise which allows the call to `navigator.clipboard.write()` // above to resolve and successfully copy to the clipboard. If we let this continue, Safari // would throw an error because this call stack doesn't appear to originate from a user gesture. return this.webKitPendingClipboardWritePromise.complete(text); } </ins> // Guard access to navigator.clipboard with try/catch // as we have seen DOMExceptions in certain browsers // due to security policies.

import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices'; <ins> import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { TestLayoutService } from 'vs/workbench/test/browser/workbenchTestServices'; </ins> export class TestCell extends NotebookCellTextModel { constructor(

instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(IContextKeyService, instantiationService.createInstance(ContextKeyService)); instantiationService.stub(IListService, instantiationService.createInstance(ListService)); <del> instantiationService.stub(IClipboardService, new BrowserClipboardService()); </del> <ins> instantiationService.stub(ILayoutService, new TestLayoutService()); </ins> instantiationService.stub(ILogService, new NullLogService()); <ins> instantiationService.stub(IClipboardService, instantiationService.createInstance(BrowserClipboardService)); </ins> instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IWorkspaceTrustRequestService, new TestWorkspaceTrustRequestService(true));

import { once } from 'vs/base/common/functional'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; <del> import { isSafari } from 'vs/base/browser/browser'; </del> import { ILogService } from 'vs/platform/log/common/log'; <ins> import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; </ins> export class BrowserClipboardService extends BaseBrowserClipboardService {

@INotificationService private readonly notificationService: INotificationService, @IOpenerService private readonly openerService: IOpenerService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, <del> @ILogService private readonly logService: ILogService </del> <ins> @ILogService logService: ILogService, @ILayoutService layoutService: ILayoutService </ins> ) { <del> super(); </del> <ins> super(layoutService, logService); </ins> } override async readText(type?: string): Promise<string> {

return ''; // do not ask for input in tests (https://github.com/microsoft/vscode/issues/112264) } <del> if (isSafari) { this.logService.error(error); return ''; // Safari does not seem to provide anyway to enable cipboard access (https://github.com/microsoft/vscode-internalbacklog/issues/2162#issuecomment-852042867) } </del> return new Promise<string>(resolve => { // Inform user about permissions problem (https://github.com/microsoft/vscode/issues/112089)