/
ClipboardAddon.ts
99 lines (82 loc) · 2.63 KB
/
ClipboardAddon.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
* @license MIT
*/
import type { IDisposable, ITerminalAddon, Terminal } from '@xterm/xterm';
import { type IClipboardProvider, ClipboardSelectionType, type IBase64 } from '@xterm/addon-clipboard';
import { Base64 as JSBase64 } from 'js-base64';
export class ClipboardAddon implements ITerminalAddon {
private _terminal?: Terminal;
private _disposable?: IDisposable;
constructor(
private _base64: IBase64 = new Base64(),
private _provider: IClipboardProvider = new BrowserClipboardProvider()
) {}
public activate(terminal: Terminal): void {
this._terminal = terminal;
this._disposable = terminal.parser.registerOscHandler(52, data => this._setOrReportClipboard(data));
}
public dispose(): void {
return this._disposable?.dispose();
}
private _readText(sel: ClipboardSelectionType, data: string): void {
const b64 = this._base64.encodeText(data);
this._terminal?.input(`\x1b]52;${sel};${b64}\x07`, false);
}
private _setOrReportClipboard(data: string): boolean | Promise<boolean> {
const args = data.split(';');
if (args.length < 2) {
return true;
}
const pc = args[0] as ClipboardSelectionType;
const pd = args[1];
if (pd === '?') {
const text = this._provider.readText(pc);
// Report clipboard
if (text instanceof Promise) {
return text.then((data) => {
this._readText(pc, data);
return true;
});
}
this._readText(pc, text);
return true;
}
// Clear clipboard if text is not a base64 encoded string.
let text = '';
try {
text = this._base64.decodeText(pd);
} catch {}
const result = this._provider.writeText(pc, text);
if (result instanceof Promise) {
return result.then(() => true);
}
return true;
}
}
export class BrowserClipboardProvider implements IClipboardProvider {
public async readText(selection: ClipboardSelectionType): Promise<string> {
if (selection !== 'c') {
return Promise.resolve('');
}
return navigator.clipboard.readText();
}
public async writeText(selection: ClipboardSelectionType, text: string): Promise<void> {
if (selection !== 'c') {
return Promise.resolve();
}
return navigator.clipboard.writeText(text);
}
}
export class Base64 implements IBase64 {
public encodeText(data: string): string {
return JSBase64.encode(data);
}
public decodeText(data: string): string {
const text = JSBase64.decode(data);
if (!JSBase64.isValid(data) || JSBase64.encode(text) !== data) {
return '';
}
return text;
}
}