Skip to content

Commit

Permalink
Try to use real clipboard to store copied resources on web (#224240)
Browse files Browse the repository at this point in the history
For web, our clipboard for resources currently is in-memory only. This prevents copying data between windows and can also cause us to get into odd states where the in-memory clipboard no longer matches what's the real clipboard

This change tried to migrate resources to use the  real clipboard thanks the custom web clipboard types: w3c/clipboard-apis#175

This feature only works in Chromium at the moment, but I believe other browsers have expressed intent to implement it too
  • Loading branch information
mjbvz authored Jul 30, 2024
1 parent 25b6584 commit 9a186dd
Showing 1 changed file with 57 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/vs/platform/clipboard/browser/clipboardService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';

/**
* Custom mime type used for storing a list of uris in the clipboard.
*
* Requires support for custom web clipboards https://github.com/w3c/clipboard-apis/pull/175
*/
const vscodeResourcesMime = 'application/vnd.code.resources';

export class BrowserClipboardService extends Disposable implements IClipboardService {

declare readonly _serviceBrand: undefined;
Expand Down Expand Up @@ -172,6 +179,26 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
private static readonly MAX_RESOURCE_STATE_SOURCE_LENGTH = 1000;

async writeResources(resources: URI[]): Promise<void> {
// Guard access to navigator.clipboard with try/catch
// as we have seen DOMExceptions in certain browsers
// due to security policies.
try {
await getActiveWindow().navigator.clipboard.write([
new ClipboardItem({
[`web ${vscodeResourcesMime}`]: new Blob([
JSON.stringify(resources.map(x => x.toJSON()))
], {
type: vscodeResourcesMime
})
})
]);

// Continue to write to the in-memory clipboard as well.
// This is needed because some browsers allow the paste but then can't read the custom resources.
} catch (error) {
// Noop
}

if (resources.length === 0) {
this.clearResources();
} else {
Expand All @@ -181,6 +208,22 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}

async readResources(): Promise<URI[]> {
// Guard access to navigator.clipboard with try/catch
// as we have seen DOMExceptions in certain browsers
// due to security policies.
try {
const items = await getActiveWindow().navigator.clipboard.read();
for (const item of items) {
if (item.types.includes(`web ${vscodeResourcesMime}`)) {
const blob = await item.getType(`web ${vscodeResourcesMime}`);
const resources = (JSON.parse(await blob.text()) as URI[]).map(x => URI.from(x));
return resources;
}
}
} catch (error) {
// Noop
}

const resourcesStateHash = await this.computeResourcesStateHash();
if (this.resourcesStateHash !== resourcesStateHash) {
this.clearResources(); // state mismatch, resources no longer valid
Expand All @@ -204,6 +247,20 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}

async hasResources(): Promise<boolean> {
// Guard access to navigator.clipboard with try/catch
// as we have seen DOMExceptions in certain browsers
// due to security policies.
try {
const items = await getActiveWindow().navigator.clipboard.read();
for (const item of items) {
if (item.types.includes(`web ${vscodeResourcesMime}`)) {
return true;
}
}
} catch (error) {
// Noop
}

return this.resources.length > 0;
}

Expand Down

0 comments on commit 9a186dd

Please sign in to comment.