# dsh-copy-file-button [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) > A **"copy the whole file"** button in the DSH file preview toolbar — one click puts the complete on-disk content on your clipboard. > 中文: [README.md](README.md) ## Why this exists DSH's right sidebar can preview a file, but copying the whole thing means select-all by hand — and the preview may hold only part of the file, or text truncated by a re-render. This button reads through the Host's file authority, so it copies **the real bytes on disk**, not whatever text the preview happens to be showing. ## What it does Adds a copy button to the `sidebar.right.tab.document.actions` slot — the right end of the file-preview header row, alongside the viewer menu, wrap toggle, reload, and the open-in-VS-Code split button. - **Copy source**: `remote.workspaceFiles.readBytes(...)` — the same Host read authority the preview itself uses, so the bytes are the on-disk originals. - **A check mark only after verified success**: the clipboard is **read back and compared** after writing. `execCommand('copy')` can report success while writing nothing, and a document that lost focus makes `clipboard.writeText` reject — either way a naive implementation shows a check mark over an empty clipboard. Only a matching read-back counts as copied. - **Fallback path**: when `navigator.clipboard` is unavailable or fails, it falls back to a temporary `textarea` plus `execCommand('copy')`, restoring the previous selection afterwards. ## Edge cases | Case | Behavior | |---|---| | Binary file | Probes the first 8 KB for a NUL byte; refuses with "This is not a text file" | | File too large | Reports "File is too large to copy at once" rather than copying a truncated prefix | | Empty file | Reports "The file is empty" | | Read failure | Shows the actual error instead of pretending success | | Unknown data shape | Reports the real type and size (e.g. `string(1024)`) instead of guessing | ## Two implementation pitfalls 1. **Data crossing the Host bridge is not a `Uint8Array`.** The schema declares `Uint8Array`, but after cross-process structured serialization what actually arrives is a **base64 string** (the document preview decodes it with `atob` itself). Calling `new Uint8Array(someString)` **silently yields an empty array** — precisely how "reports copied, clipboard is empty" happens. The code accepts `Uint8Array` / base64 / `ArrayBuffer` / array-like / `{type:'Buffer',data:[...]}` alike. 2. **Strip the UTF-8 BOM.** If the first decoded character is `U+FEFF` it is dropped, so the copied text does not start with an invisible character. ## Install ```sh # from GitHub dsh plugin --profile desktop add github:/dsh-copy-file-button # or from a local checkout dsh plugin --profile desktop add link:/path/to/dsh-copy-file-button ``` Then restart DSH. The client half needs one page refresh to load. ## Internationalization Ships with `locale/en.json`; the button label follows DSH's language setting. Chinese and English strings are built in — adding a language is just another JSON file under `locale/`. ## Uninstall Remove the entry from your profile's `package.json` (`dependencies` and `dsh.profile.bundles`), delete the `node_modules` link, and restart. ## License MIT