-
Notifications
You must be signed in to change notification settings - Fork 10.5k
fix:solved the copy issue in TUI #14101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -19,6 +19,26 @@ function writeOsc52(text: string): void { | |||||||||||||||||||||||||||||
| process.stdout.write(sequence) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| type CopyMethod = { | ||||||||||||||||||||||||||||||
| name: string | ||||||||||||||||||||||||||||||
| copy: (text: string) => Promise<void> | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| async function spawnCopy(name: string, cmd: string[], text: string): Promise<void> { | ||||||||||||||||||||||||||||||
| const proc = Bun.spawn(cmd, { | ||||||||||||||||||||||||||||||
| stdin: "pipe", | ||||||||||||||||||||||||||||||
| stdout: "ignore", | ||||||||||||||||||||||||||||||
| stderr: "pipe", | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| proc.stdin.write(text) | ||||||||||||||||||||||||||||||
| proc.stdin.end() | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const err = proc.stderr ? await new Response(proc.stderr).text().catch(() => "") : "" | ||||||||||||||||||||||||||||||
| const code = await proc.exited | ||||||||||||||||||||||||||||||
| if (code === 0) return | ||||||||||||||||||||||||||||||
| throw new Error(`${name} exited with code ${code}${err ? `: ${err.trim()}` : ""}`) | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export namespace Clipboard { | ||||||||||||||||||||||||||||||
| export interface Content { | ||||||||||||||||||||||||||||||
| data: string | ||||||||||||||||||||||||||||||
|
|
@@ -72,88 +92,137 @@ export namespace Clipboard { | |||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const getCopyMethod = lazy(() => { | ||||||||||||||||||||||||||||||
| const getCopyMethods = lazy(() => { | ||||||||||||||||||||||||||||||
| const os = platform() | ||||||||||||||||||||||||||||||
| const list: CopyMethod[] = [] | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (os === "darwin" && Bun.which("osascript")) { | ||||||||||||||||||||||||||||||
| console.log("clipboard: using osascript") | ||||||||||||||||||||||||||||||
| return async (text: string) => { | ||||||||||||||||||||||||||||||
| const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"') | ||||||||||||||||||||||||||||||
| await $`osascript -e 'set the clipboard to "${escaped}"'`.nothrow().quiet() | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| console.log("clipboard: enabled osascript") | ||||||||||||||||||||||||||||||
| list.push({ | ||||||||||||||||||||||||||||||
| name: "osascript", | ||||||||||||||||||||||||||||||
| copy: async (text: string) => { | ||||||||||||||||||||||||||||||
| const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"') | ||||||||||||||||||||||||||||||
| const result = await $`osascript -e 'set the clipboard to "${escaped}"'`.nothrow().quiet() | ||||||||||||||||||||||||||||||
| if (result.exitCode === 0) return | ||||||||||||||||||||||||||||||
| throw new Error("osascript failed") | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| throw new Error("osascript failed") | |
| const stderr = | |
| result.stderr && result.stderr.length | |
| ? new TextDecoder().decode(result.stderr).trim() | |
| : "" | |
| throw new Error( | |
| `osascript exited with code ${result.exitCode}${stderr ? `: ${stderr}` : ""}`, | |
| ) |
Copilot
AI
Feb 18, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clipboardy is always added as a copy method, even when a native method (wl-copy/xclip/xsel/powershell/etc.) is enabled. Since clipboardy typically shells out to the same underlying tools, this can cause redundant attempts (and duplicated errors) before failing, and can add extra latency. Consider only adding the clipboardy fallback when no OS-specific methods were added, or otherwise de-duplicating so each backend is tried at most once.
| list.push({ | |
| name: "clipboardy", | |
| copy: async (text: string) => { | |
| await clipboardy.write(text) | |
| }, | |
| }) | |
| if (list.length === 0) { | |
| list.push({ | |
| name: "clipboardy", | |
| copy: async (text: string) => { | |
| await clipboardy.write(text) | |
| }, | |
| }) | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch branch logs
${error}which often becomes "[object Object]" and drops stack traces. Consider normalizing the error (e.g.,error instanceof Error ? error.stack ?? error.message : String(error)) so clipboard failures are diagnosable from logs.