From 2d067226b969b13a824d6bbe18f6edcca0b71022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Battistella=20Nadas?= Date: Tue, 9 Jun 2026 17:07:01 +0200 Subject: [PATCH] revert: drop clipboard yank/paste and modal dropdowns The vim clipboard integration was unreliable across browsers (library "+" register broken on Firefox; custom navigator.clipboard actions worked on Chrome but hit chip prompts and Firefox config edge cases). The modal dropdown layer added more state than it saved keystrokes. Pulling both back out. What remains of the vim work: - CodeMirror + @replit/codemirror-vim in the input buffer (i/Esc, hjkl, word/line motions, yy/p via vim's internal register, undo, /, :) - Shift-H / Shift-L focus navigation across controls, including the H/L override inside the editor so it works from any focus --- CHANGELOG.md | 8 +--- static/index.html | 109 ++-------------------------------------------- 2 files changed, 4 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99862f0..0027d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,8 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### 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. +- 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` (vim's internal register), 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. -- `yy` / `Y` and visual-mode `y` in the editor copy to the system clipboard via custom `navigator.clipboard.writeText()` actions (the library's `+` register is broken on Firefox). Bare `y` (e.g. `yw`, `y$`) still uses vim's internal register — that path would need a deeper hook into the library's register system. -- `p` / `P` in vim normal mode paste from the system clipboard at / before the cursor via `navigator.clipboard.readText()`. Browsers may show a one-time permission prompt or chip; granting clipboard-read for the origin makes future calls silent. On Firefox, ensure `dom.events.asyncClipboard.readText` is `true` (default in recent versions) or the read will be blocked. -- Vim-style modal navigation on the From / To / Model dropdowns (default NORMAL): - - `j` / `k` move selectedIndex down / up (works whether the dropdown is open or collapsed; uses document-level capture-phase listener so Firefox plays along) - - `/` or `i` enters search mode — letter keys then do native typeahead; accent-coloured border indicates it - - `Esc` returns to normal mode; blur also resets so the next focus starts in normal - 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 2259bdc..53bbfd1 100644 --- a/static/index.html +++ b/static/index.html @@ -179,12 +179,6 @@ font-family: ui-monospace, SFMono-Regular, Menlo, monospace; } - /* Vim search-mode indicator on the language/model dropdowns - (default is normal mode — j/k navigate; / or i enters search). */ - select.vim-search { - border-color: var(--accent); - box-shadow: 0 0 0 1px var(--accent); - } @@ -518,111 +512,14 @@ moveFocus(k === "l" ? 1 : -1); }); - // Vim customisations: focus navigation + system-clipboard yank/paste. - // Override H/L (normally "viewport top/bottom") to exit the editor across - // controls, matching the Shift-H/L contract the document handler uses. - // Custom yank/paste via navigator.clipboard — the library's "+" register - // path is unreliable on Firefox, so we own the clipboard I/O ourselves. - // Limitation: bare `y` (yw, y$, etc.) still goes to vim's internal - // register; only yy / Y / visual `y` reach the system clipboard. + // Override vim's H/L (normally "viewport top/bottom") so they exit the + // editor to the previous/next control, matching the Shift-H/L contract + // the document handler uses elsewhere. 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" }); - - Vim.defineAction("finrodYankLine", () => { - const line = editor.state.doc.lineAt(editor.state.selection.main.head); - const text = editor.state.doc.sliceString(line.from, line.to); - navigator.clipboard.writeText(text) - .catch(e => console.warn("Clipboard write failed:", e)); - }); - Vim.defineAction("finrodYankSelection", () => { - const { from, to } = editor.state.selection.main; - if (from === to) return; - const text = editor.state.sliceDoc(from, to); - navigator.clipboard.writeText(text) - .catch(e => console.warn("Clipboard write failed:", e)); - }); - async function pasteAt(after) { - let text; - try { - text = await navigator.clipboard.readText(); - } catch (e) { - console.warn("Clipboard read failed:", e); - return; - } - 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 }, - }); - } - Vim.defineAction("finrodPasteAfter", () => pasteAt(true)); - Vim.defineAction("finrodPasteBefore", () => pasteAt(false)); - - Vim.mapCommand("yy", "action", "finrodYankLine", {}, { context: "normal" }); - Vim.mapCommand("Y", "action", "finrodYankLine", {}, { context: "normal" }); - Vim.mapCommand("y", "action", "finrodYankSelection", {}, { context: "visual" }); - Vim.mapCommand("p", "action", "finrodPasteAfter", {}, { context: "normal" }); - Vim.mapCommand("P", "action", "finrodPasteBefore", {}, { context: "normal" }); - } - - // Modal vim-style behavior on the language/model dropdowns. - // default: NORMAL mode — j/k move selectedIndex (vim everywhere) - // `/` or `i`: enter search mode — letter keys do native typeahead - // Esc: back to normal mode - // blur: reset to normal mode on next focus - // Uses a document-level CAPTURE listener so events fire whether the - // dropdown is open or collapsed (Firefox doesn't bubble keydown - // reliably from a collapsed