Skip to content

Commit

Permalink
Cannot paste content copied from outside on VS Code Web (#200641) (#2…
Browse files Browse the repository at this point in the history
…00782)

* Cannot paste content copied from outside on VS Code Web (#200641)

* add a limit
  • Loading branch information
bpasero authored Dec 14, 2023
1 parent 789c802 commit b487098
Showing 1 changed file with 48 additions and 8 deletions.
56 changes: 48 additions & 8 deletions src/vs/platform/clipboard/browser/clipboardService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { isSafari, isWebkitWebView } from 'vs/base/browser/browser';
import { $, addDisposableListener, getActiveDocument } from 'vs/base/browser/dom';
import { DeferredPromise } from 'vs/base/common/async';
import { Event } from 'vs/base/common/event';
import { hash } from 'vs/base/common/hash';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
Expand All @@ -17,12 +18,12 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer

declare readonly _serviceBrand: undefined;

private readonly mapTextToType = new Map<string, string>(); // unsupported in web (only in-memory)

constructor(
@ILayoutService private readonly layoutService: ILayoutService,
@ILogService private readonly logService: ILogService) {
@ILogService private readonly logService: ILogService
) {
super();

if (isSafari || isWebkitWebView) {
this.installWebKitWriteTextWorkaround();
}
Expand Down Expand Up @@ -71,8 +72,13 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}, { container: this.layoutService.mainContainer, disposables: this._store }));
}

private readonly mapTextToType = new Map<string, string>(); // unsupported in web (only in-memory)

async writeText(text: string, type?: string): Promise<void> {

// Clear resources given we are writing text
this.writeResources([]);

// With type: only in-memory is supported
if (type) {
this.mapTextToType.set(type, text);
Expand All @@ -97,6 +103,10 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}

// Fallback to textarea and execCommand solution
this.fallbackWriteText(text);
}

private fallbackWriteText(text: string): void {
const activeDocument = getActiveDocument();
const activeElement = activeDocument.activeElement;

Expand All @@ -116,8 +126,6 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}

activeDocument.body.removeChild(textArea);

return;
}

async readText(type?: string): Promise<string> {
Expand All @@ -134,9 +142,9 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
return await navigator.clipboard.readText();
} catch (error) {
console.error(error);

return '';
}

return '';
}

private findText = ''; // unsupported in web (only in-memory)
Expand All @@ -150,16 +158,48 @@ export class BrowserClipboardService extends Disposable implements IClipboardSer
}

private resources: URI[] = []; // unsupported in web (only in-memory)
private resourcesStateHash: number | undefined = undefined;

private static readonly MAX_RESOURCE_STATE_SOURCE_LENGTH = 1000;

async writeResources(resources: URI[]): Promise<void> {
this.resources = resources;
if (resources.length === 0) {
this.clearResources();
} else {
this.resources = resources;
this.resourcesStateHash = await this.computeResourcesStateHash();
}
}

async readResources(): Promise<URI[]> {
const resourcesStateHash = await this.computeResourcesStateHash();
if (this.resourcesStateHash !== resourcesStateHash) {
this.clearResources(); // state mismatch, resources no longer valid
}

return this.resources;
}

private async computeResourcesStateHash(): Promise<number | undefined> {
if (this.resources.length === 0) {
return undefined; // no resources, no hash needed
}

// Resources clipboard is managed in-memory only and thus
// fails to invalidate when clipboard data is changing.
// As such, we compute the hash of the current clipboard
// and use that to later validate the resources clipboard.

const clipboardText = await this.readText();
return hash(clipboardText.substring(0, BrowserClipboardService.MAX_RESOURCE_STATE_SOURCE_LENGTH));
}

async hasResources(): Promise<boolean> {
return this.resources.length > 0;
}

private clearResources(): void {
this.resources = [];
this.resourcesStateHash = undefined;
}
}

0 comments on commit b487098

Please sign in to comment.