From a058665b5b4c96086347dd96e1341af3168f3f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Battistella=20Nadas?= Date: Tue, 9 Jun 2026 16:41:52 +0200 Subject: [PATCH] feat: vim p/P paste from system clipboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vim's default p/P pastes from its internal unnamed register, which is useless when the text to translate lives in another app's clipboard. Override both in normal mode to read navigator.clipboard .readText() and insert at (after) or before the cursor. Caveats: requires browser clipboard permission (prompted on first use), HTTPS or localhost. Both already satisfied — finrod is served over the wildcard TLS cert. --- CHANGELOG.md | 1 + static/index.html | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 938d03c..fa074ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Vim bindings in the input via CodeMirror 6 + `@replit/codemirror-vim` (loaded from esm.sh, no build step). Supports `i`/`Esc`, `hjkl`, word/line motions, `dd`/`yy`/`p`, undo/redo, `/` search, `:` command line. Auto-disabled on touch devices (detected via `(pointer: coarse)`) where modal editing fights the virtual keyboard. - `Shift-H` / `Shift-L` cycle focus across the page controls (source → target → model → editor → button) like `Shift-Tab` / `Tab`. Also overridden in vim normal mode (replacing vim's viewport-top/bottom default) so the same shortcut works to leave the editor. +- `p` / `P` in vim normal mode paste from the system clipboard at / before the cursor (vim's default registers are skipped — the realistic source for a translator is another app, not an in-editor yank). - On page load, the model dropdown defaults to whichever model Ollama already has hot — skips the 5-15 s disk-reload pain on the first translation. After load it follows the user's manual selection. ### Changed diff --git a/static/index.html b/static/index.html index 2df7e16..decd64f 100644 --- a/static/index.html +++ b/static/index.html @@ -513,12 +513,34 @@ // Override vim's H/L (normally "viewport top/bottom") so they exit the // editor to the previous/next control, matching the same Shift-H/L - // contract the document handler uses elsewhere. + // contract the document handler uses elsewhere. Also override p/P in + // normal mode to paste from the system clipboard (vim's default p + // pastes from its internal register — useless when the source text + // comes from another app). if (!isCoarsePointer) { Vim.defineAction("finrodFocusPrev", () => moveFocus(-1)); Vim.defineAction("finrodFocusNext", () => moveFocus(1)); Vim.mapCommand("H", "action", "finrodFocusPrev", {}, { context: "normal" }); Vim.mapCommand("L", "action", "finrodFocusNext", {}, { context: "normal" }); + + async function pasteFromClipboard(after) { + try { + const text = await navigator.clipboard.readText(); + if (!text) return; + const sel = editor.state.selection.main; + const pos = after ? sel.to : sel.from; + editor.dispatch({ + changes: { from: pos, insert: text }, + selection: { anchor: pos + text.length }, + }); + } catch (e) { + console.warn("Clipboard read failed:", e); + } + } + Vim.defineAction("finrodPasteAfter", () => pasteFromClipboard(true)); + Vim.defineAction("finrodPasteBefore", () => pasteFromClipboard(false)); + Vim.mapCommand("p", "action", "finrodPasteAfter", {}, { context: "normal" }); + Vim.mapCommand("P", "action", "finrodPasteBefore", {}, { context: "normal" }); } fillLangs();