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();