feat: wire native Rust clipboard into codebase
feat: wire native Rust clipboard into codebase
This commit is contained in:
commit
9c7cf20d07
4 changed files with 25 additions and 85 deletions
|
|
@ -44,9 +44,6 @@
|
|||
"undici": "^7.19.1",
|
||||
"yaml": "^2.8.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@mariozechner/clipboard": "^0.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/diff": "^7.0.2",
|
||||
"@types/hosted-git-info": "^3.0.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { spawnSync } from "child_process";
|
||||
|
||||
import { clipboard } from "./clipboard-native.js";
|
||||
import { readImageFromClipboard as nativeReadImage } from "@gsd/native/clipboard";
|
||||
import { loadPhoton } from "./photon.js";
|
||||
|
||||
export type ClipboardImage = {
|
||||
|
|
@ -175,19 +175,20 @@ export async function readClipboardImage(options?: {
|
|||
let image: ClipboardImage | null = null;
|
||||
|
||||
if (platform === "linux" && isWaylandSession(env)) {
|
||||
// Wayland: use CLI tools (wl-paste/xclip) since native arboard
|
||||
// may not have access to the Wayland compositor from a terminal.
|
||||
image = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();
|
||||
} else {
|
||||
if (!clipboard || !clipboard.hasImage()) {
|
||||
// macOS, Windows, Linux X11: use native Rust clipboard (arboard)
|
||||
try {
|
||||
const nativeImage = await nativeReadImage();
|
||||
if (!nativeImage || nativeImage.data.length === 0) {
|
||||
return null;
|
||||
}
|
||||
image = { bytes: nativeImage.data, mimeType: nativeImage.mimeType };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
const imageData = await clipboard.getImageBinary();
|
||||
if (!imageData || imageData.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);
|
||||
image = { bytes, mimeType: "image/png" };
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
import { createRequire } from "module";
|
||||
|
||||
export type ClipboardModule = {
|
||||
hasImage: () => boolean;
|
||||
getImageBinary: () => Promise<Array<number>>;
|
||||
};
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
let clipboard: ClipboardModule | null = null;
|
||||
|
||||
const hasDisplay = process.platform !== "linux" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
||||
|
||||
if (!process.env.TERMUX_VERSION && hasDisplay) {
|
||||
try {
|
||||
clipboard = require("@mariozechner/clipboard") as ClipboardModule;
|
||||
} catch {
|
||||
clipboard = null;
|
||||
}
|
||||
}
|
||||
|
||||
export { clipboard };
|
||||
/**
|
||||
* Re-export native clipboard utilities from @gsd/native.
|
||||
*
|
||||
* This module exists for backward compatibility. Prefer importing
|
||||
* directly from "@gsd/native/clipboard" in new code.
|
||||
*/
|
||||
export {
|
||||
copyToClipboard,
|
||||
readTextFromClipboard,
|
||||
readImageFromClipboard,
|
||||
} from "@gsd/native/clipboard";
|
||||
|
|
|
|||
|
|
@ -1,61 +1,13 @@
|
|||
import { execSync, spawn } from "child_process";
|
||||
import { platform } from "os";
|
||||
import { isWaylandSession } from "./clipboard-image.js";
|
||||
import { copyToClipboard as nativeCopy } from "@gsd/native/clipboard";
|
||||
|
||||
export function copyToClipboard(text: string): void {
|
||||
// Always emit OSC 52 - works over SSH/mosh, harmless locally
|
||||
const encoded = Buffer.from(text).toString("base64");
|
||||
process.stdout.write(`\x1b]52;c;${encoded}\x07`);
|
||||
|
||||
// Also try native tools (best effort for local sessions)
|
||||
const p = platform();
|
||||
const options = { input: text, timeout: 5000 };
|
||||
|
||||
// Use native clipboard for local sessions (best effort)
|
||||
try {
|
||||
if (p === "darwin") {
|
||||
execSync("pbcopy", options);
|
||||
} else if (p === "win32") {
|
||||
execSync("clip", options);
|
||||
} else {
|
||||
// Linux. Try Termux, Wayland, or X11 clipboard tools.
|
||||
if (process.env.TERMUX_VERSION) {
|
||||
try {
|
||||
execSync("termux-clipboard-set", options);
|
||||
return;
|
||||
} catch {
|
||||
// Fall back to Wayland or X11 tools.
|
||||
}
|
||||
}
|
||||
|
||||
const isWayland = isWaylandSession();
|
||||
if (isWayland) {
|
||||
try {
|
||||
// Verify wl-copy exists (spawn errors are async and won't be caught)
|
||||
execSync("which wl-copy", { stdio: "ignore" });
|
||||
// wl-copy with execSync hangs due to fork behavior; use spawn instead
|
||||
const proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
|
||||
proc.stdin.on("error", () => {
|
||||
// Ignore EPIPE errors if wl-copy exits early
|
||||
});
|
||||
proc.stdin.write(text);
|
||||
proc.stdin.end();
|
||||
proc.unref();
|
||||
} catch {
|
||||
// Fall back to xclip/xsel (works on XWayland)
|
||||
try {
|
||||
execSync("xclip -selection clipboard", options);
|
||||
} catch {
|
||||
execSync("xsel --clipboard --input", options);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
execSync("xclip -selection clipboard", options);
|
||||
} catch {
|
||||
execSync("xsel --clipboard --input", options);
|
||||
}
|
||||
}
|
||||
}
|
||||
nativeCopy(text);
|
||||
} catch {
|
||||
// Ignore - OSC 52 already emitted as fallback
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue