@tooee/clipboard 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/clipboard.d.ts +8 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +158 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
- package/src/clipboard.ts +179 -0
- package/src/index.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ClipboardContent {
|
|
2
|
+
data: string;
|
|
3
|
+
mime: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function readClipboard(): Promise<ClipboardContent | undefined>;
|
|
6
|
+
export declare function readClipboardText(): Promise<string | undefined>;
|
|
7
|
+
export declare function copyToClipboard(text: string): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CA+D3E;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA6BrE;AAyED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjE"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { $ } from "bun";
|
|
2
|
+
import { platform, release, tmpdir } from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
export async function readClipboard() {
|
|
5
|
+
const os = platform();
|
|
6
|
+
if (os === "darwin") {
|
|
7
|
+
const tmpfile = path.join(tmpdir(), "tooee-clipboard.png");
|
|
8
|
+
try {
|
|
9
|
+
await $ `osascript -e 'set imageData to the clipboard as "PNGf"' -e 'set fileRef to open for access POSIX file "${tmpfile}" with write permission' -e 'set eof fileRef to 0' -e 'write imageData to fileRef' -e 'close access fileRef'`
|
|
10
|
+
.nothrow()
|
|
11
|
+
.quiet();
|
|
12
|
+
const file = Bun.file(tmpfile);
|
|
13
|
+
const buffer = await file.arrayBuffer();
|
|
14
|
+
if (buffer.byteLength > 0) {
|
|
15
|
+
return {
|
|
16
|
+
data: Buffer.from(buffer).toString("base64"),
|
|
17
|
+
mime: "image/png",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Image read failed, try text below
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await $ `rm -f "${tmpfile}"`.nothrow().quiet();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (os === "win32" || release().includes("WSL")) {
|
|
29
|
+
const script = "Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [System.Convert]::ToBase64String($ms.ToArray()) }";
|
|
30
|
+
const base64 = await $ `powershell.exe -command "${script}"`.nothrow().text();
|
|
31
|
+
if (base64) {
|
|
32
|
+
const imageBuffer = Buffer.from(base64.trim(), "base64");
|
|
33
|
+
if (imageBuffer.length > 0) {
|
|
34
|
+
return { data: imageBuffer.toString("base64"), mime: "image/png" };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (os === "linux") {
|
|
39
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
|
|
40
|
+
const wayland = await $ `wl-paste -t image/png`.nothrow().arrayBuffer();
|
|
41
|
+
if (wayland && wayland.byteLength > 0) {
|
|
42
|
+
return {
|
|
43
|
+
data: Buffer.from(wayland).toString("base64"),
|
|
44
|
+
mime: "image/png",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (Bun.which("xclip")) {
|
|
49
|
+
const x11 = await $ `xclip -selection clipboard -t image/png -o`.nothrow().arrayBuffer();
|
|
50
|
+
if (x11 && x11.byteLength > 0) {
|
|
51
|
+
return {
|
|
52
|
+
data: Buffer.from(x11).toString("base64"),
|
|
53
|
+
mime: "image/png",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const text = await readClipboardText();
|
|
59
|
+
if (text) {
|
|
60
|
+
return { data: text, mime: "text/plain" };
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
export async function readClipboardText() {
|
|
65
|
+
const os = platform();
|
|
66
|
+
if (os === "darwin") {
|
|
67
|
+
const result = await $ `pbpaste`.nothrow().quiet().text();
|
|
68
|
+
return result || undefined;
|
|
69
|
+
}
|
|
70
|
+
if (os === "linux") {
|
|
71
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
|
|
72
|
+
const result = await $ `wl-paste`.nothrow().quiet().text();
|
|
73
|
+
return result || undefined;
|
|
74
|
+
}
|
|
75
|
+
if (Bun.which("xclip")) {
|
|
76
|
+
const result = await $ `xclip -selection clipboard -o`.nothrow().quiet().text();
|
|
77
|
+
return result || undefined;
|
|
78
|
+
}
|
|
79
|
+
if (Bun.which("xsel")) {
|
|
80
|
+
const result = await $ `xsel --clipboard --output`.nothrow().quiet().text();
|
|
81
|
+
return result || undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (os === "win32") {
|
|
85
|
+
const result = await $ `powershell -command "Get-Clipboard"`.nothrow().quiet().text();
|
|
86
|
+
return result || undefined;
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
let copyMethod = null;
|
|
91
|
+
function getCopyMethod() {
|
|
92
|
+
if (copyMethod)
|
|
93
|
+
return copyMethod;
|
|
94
|
+
const os = platform();
|
|
95
|
+
if (os === "darwin" && Bun.which("osascript")) {
|
|
96
|
+
copyMethod = async (text) => {
|
|
97
|
+
const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
98
|
+
await $ `osascript -e 'set the clipboard to "${escaped}"'`.nothrow().quiet();
|
|
99
|
+
};
|
|
100
|
+
return copyMethod;
|
|
101
|
+
}
|
|
102
|
+
if (os === "linux") {
|
|
103
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-copy")) {
|
|
104
|
+
copyMethod = async (text) => {
|
|
105
|
+
const proc = Bun.spawn(["wl-copy"], {
|
|
106
|
+
stdin: "pipe",
|
|
107
|
+
stdout: "ignore",
|
|
108
|
+
stderr: "ignore",
|
|
109
|
+
});
|
|
110
|
+
proc.stdin.write(text);
|
|
111
|
+
proc.stdin.end();
|
|
112
|
+
await proc.exited.catch(() => undefined);
|
|
113
|
+
};
|
|
114
|
+
return copyMethod;
|
|
115
|
+
}
|
|
116
|
+
if (Bun.which("xclip")) {
|
|
117
|
+
copyMethod = async (text) => {
|
|
118
|
+
const proc = Bun.spawn(["xclip", "-selection", "clipboard"], {
|
|
119
|
+
stdin: "pipe",
|
|
120
|
+
stdout: "ignore",
|
|
121
|
+
stderr: "ignore",
|
|
122
|
+
});
|
|
123
|
+
proc.stdin.write(text);
|
|
124
|
+
proc.stdin.end();
|
|
125
|
+
await proc.exited.catch(() => undefined);
|
|
126
|
+
};
|
|
127
|
+
return copyMethod;
|
|
128
|
+
}
|
|
129
|
+
if (Bun.which("xsel")) {
|
|
130
|
+
copyMethod = async (text) => {
|
|
131
|
+
const proc = Bun.spawn(["xsel", "--clipboard", "--input"], {
|
|
132
|
+
stdin: "pipe",
|
|
133
|
+
stdout: "ignore",
|
|
134
|
+
stderr: "ignore",
|
|
135
|
+
});
|
|
136
|
+
proc.stdin.write(text);
|
|
137
|
+
proc.stdin.end();
|
|
138
|
+
await proc.exited.catch(() => undefined);
|
|
139
|
+
};
|
|
140
|
+
return copyMethod;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (os === "win32") {
|
|
144
|
+
copyMethod = async (text) => {
|
|
145
|
+
const escaped = text.replace(/"/g, '""');
|
|
146
|
+
await $ `powershell -command "Set-Clipboard -Value \"${escaped}\""`.nothrow().quiet();
|
|
147
|
+
};
|
|
148
|
+
return copyMethod;
|
|
149
|
+
}
|
|
150
|
+
copyMethod = async () => {
|
|
151
|
+
// Silent no-op — no clipboard support available
|
|
152
|
+
};
|
|
153
|
+
return copyMethod;
|
|
154
|
+
}
|
|
155
|
+
export async function copyToClipboard(text) {
|
|
156
|
+
await getCopyMethod()(text);
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../src/clipboard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClF,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tooee/clipboard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Cross-platform clipboard operations for Tooee",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Gareth Andrew",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/gingerhendrix/tooee.git",
|
|
10
|
+
"directory": "packages/clipboard"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/gingerhendrix/tooee",
|
|
13
|
+
"bugs": "https://github.com/gingerhendrix/tooee/issues",
|
|
14
|
+
"keywords": ["tui", "terminal", "cli", "opentui", "clipboard"],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"@tooee/source": "./src/index.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": ["dist", "src"],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/bun": "^1.3.5",
|
|
30
|
+
"typescript": "^5.8.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/clipboard.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { $ } from "bun"
|
|
2
|
+
import { platform, release, tmpdir } from "os"
|
|
3
|
+
import path from "path"
|
|
4
|
+
|
|
5
|
+
export interface ClipboardContent {
|
|
6
|
+
data: string
|
|
7
|
+
mime: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function readClipboard(): Promise<ClipboardContent | undefined> {
|
|
11
|
+
const os = platform()
|
|
12
|
+
|
|
13
|
+
if (os === "darwin") {
|
|
14
|
+
const tmpfile = path.join(tmpdir(), "tooee-clipboard.png")
|
|
15
|
+
try {
|
|
16
|
+
await $`osascript -e 'set imageData to the clipboard as "PNGf"' -e 'set fileRef to open for access POSIX file "${tmpfile}" with write permission' -e 'set eof fileRef to 0' -e 'write imageData to fileRef' -e 'close access fileRef'`
|
|
17
|
+
.nothrow()
|
|
18
|
+
.quiet()
|
|
19
|
+
const file = Bun.file(tmpfile)
|
|
20
|
+
const buffer = await file.arrayBuffer()
|
|
21
|
+
if (buffer.byteLength > 0) {
|
|
22
|
+
return {
|
|
23
|
+
data: Buffer.from(buffer).toString("base64"),
|
|
24
|
+
mime: "image/png",
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
// Image read failed, try text below
|
|
29
|
+
} finally {
|
|
30
|
+
await $`rm -f "${tmpfile}"`.nothrow().quiet()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (os === "win32" || release().includes("WSL")) {
|
|
35
|
+
const script =
|
|
36
|
+
"Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [System.Convert]::ToBase64String($ms.ToArray()) }"
|
|
37
|
+
const base64 = await $`powershell.exe -command "${script}"`.nothrow().text()
|
|
38
|
+
if (base64) {
|
|
39
|
+
const imageBuffer = Buffer.from(base64.trim(), "base64")
|
|
40
|
+
if (imageBuffer.length > 0) {
|
|
41
|
+
return { data: imageBuffer.toString("base64"), mime: "image/png" }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (os === "linux") {
|
|
47
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
|
|
48
|
+
const wayland = await $`wl-paste -t image/png`.nothrow().arrayBuffer()
|
|
49
|
+
if (wayland && wayland.byteLength > 0) {
|
|
50
|
+
return {
|
|
51
|
+
data: Buffer.from(wayland).toString("base64"),
|
|
52
|
+
mime: "image/png",
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (Bun.which("xclip")) {
|
|
57
|
+
const x11 = await $`xclip -selection clipboard -t image/png -o`.nothrow().arrayBuffer()
|
|
58
|
+
if (x11 && x11.byteLength > 0) {
|
|
59
|
+
return {
|
|
60
|
+
data: Buffer.from(x11).toString("base64"),
|
|
61
|
+
mime: "image/png",
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const text = await readClipboardText()
|
|
68
|
+
if (text) {
|
|
69
|
+
return { data: text, mime: "text/plain" }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function readClipboardText(): Promise<string | undefined> {
|
|
76
|
+
const os = platform()
|
|
77
|
+
|
|
78
|
+
if (os === "darwin") {
|
|
79
|
+
const result = await $`pbpaste`.nothrow().quiet().text()
|
|
80
|
+
return result || undefined
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (os === "linux") {
|
|
84
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-paste")) {
|
|
85
|
+
const result = await $`wl-paste`.nothrow().quiet().text()
|
|
86
|
+
return result || undefined
|
|
87
|
+
}
|
|
88
|
+
if (Bun.which("xclip")) {
|
|
89
|
+
const result = await $`xclip -selection clipboard -o`.nothrow().quiet().text()
|
|
90
|
+
return result || undefined
|
|
91
|
+
}
|
|
92
|
+
if (Bun.which("xsel")) {
|
|
93
|
+
const result = await $`xsel --clipboard --output`.nothrow().quiet().text()
|
|
94
|
+
return result || undefined
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (os === "win32") {
|
|
99
|
+
const result = await $`powershell -command "Get-Clipboard"`.nothrow().quiet().text()
|
|
100
|
+
return result || undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return undefined
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let copyMethod: ((text: string) => Promise<void>) | null = null
|
|
107
|
+
|
|
108
|
+
function getCopyMethod(): (text: string) => Promise<void> {
|
|
109
|
+
if (copyMethod) return copyMethod
|
|
110
|
+
|
|
111
|
+
const os = platform()
|
|
112
|
+
|
|
113
|
+
if (os === "darwin" && Bun.which("osascript")) {
|
|
114
|
+
copyMethod = async (text: string) => {
|
|
115
|
+
const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
|
|
116
|
+
await $`osascript -e 'set the clipboard to "${escaped}"'`.nothrow().quiet()
|
|
117
|
+
}
|
|
118
|
+
return copyMethod
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (os === "linux") {
|
|
122
|
+
if (process.env["WAYLAND_DISPLAY"] && Bun.which("wl-copy")) {
|
|
123
|
+
copyMethod = async (text: string) => {
|
|
124
|
+
const proc = Bun.spawn(["wl-copy"], {
|
|
125
|
+
stdin: "pipe",
|
|
126
|
+
stdout: "ignore",
|
|
127
|
+
stderr: "ignore",
|
|
128
|
+
})
|
|
129
|
+
proc.stdin.write(text)
|
|
130
|
+
proc.stdin.end()
|
|
131
|
+
await proc.exited.catch(() => undefined)
|
|
132
|
+
}
|
|
133
|
+
return copyMethod
|
|
134
|
+
}
|
|
135
|
+
if (Bun.which("xclip")) {
|
|
136
|
+
copyMethod = async (text: string) => {
|
|
137
|
+
const proc = Bun.spawn(["xclip", "-selection", "clipboard"], {
|
|
138
|
+
stdin: "pipe",
|
|
139
|
+
stdout: "ignore",
|
|
140
|
+
stderr: "ignore",
|
|
141
|
+
})
|
|
142
|
+
proc.stdin.write(text)
|
|
143
|
+
proc.stdin.end()
|
|
144
|
+
await proc.exited.catch(() => undefined)
|
|
145
|
+
}
|
|
146
|
+
return copyMethod
|
|
147
|
+
}
|
|
148
|
+
if (Bun.which("xsel")) {
|
|
149
|
+
copyMethod = async (text: string) => {
|
|
150
|
+
const proc = Bun.spawn(["xsel", "--clipboard", "--input"], {
|
|
151
|
+
stdin: "pipe",
|
|
152
|
+
stdout: "ignore",
|
|
153
|
+
stderr: "ignore",
|
|
154
|
+
})
|
|
155
|
+
proc.stdin.write(text)
|
|
156
|
+
proc.stdin.end()
|
|
157
|
+
await proc.exited.catch(() => undefined)
|
|
158
|
+
}
|
|
159
|
+
return copyMethod
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (os === "win32") {
|
|
164
|
+
copyMethod = async (text: string) => {
|
|
165
|
+
const escaped = text.replace(/"/g, '""')
|
|
166
|
+
await $`powershell -command "Set-Clipboard -Value \"${escaped}\""`.nothrow().quiet()
|
|
167
|
+
}
|
|
168
|
+
return copyMethod
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
copyMethod = async () => {
|
|
172
|
+
// Silent no-op — no clipboard support available
|
|
173
|
+
}
|
|
174
|
+
return copyMethod
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function copyToClipboard(text: string): Promise<void> {
|
|
178
|
+
await getCopyMethod()(text)
|
|
179
|
+
}
|
package/src/index.ts
ADDED