feat: vim p/P paste from system clipboard
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.
This commit is contained in:
@@ -10,6 +10,7 @@ Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||||||
### Added
|
### 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`, 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.
|
- `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.
|
- 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
|
### Changed
|
||||||
|
|||||||
@@ -513,12 +513,34 @@
|
|||||||
|
|
||||||
// Override vim's H/L (normally "viewport top/bottom") so they exit the
|
// 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
|
// 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) {
|
if (!isCoarsePointer) {
|
||||||
Vim.defineAction("finrodFocusPrev", () => moveFocus(-1));
|
Vim.defineAction("finrodFocusPrev", () => moveFocus(-1));
|
||||||
Vim.defineAction("finrodFocusNext", () => moveFocus(1));
|
Vim.defineAction("finrodFocusNext", () => moveFocus(1));
|
||||||
Vim.mapCommand("H", "action", "finrodFocusPrev", {}, { context: "normal" });
|
Vim.mapCommand("H", "action", "finrodFocusPrev", {}, { context: "normal" });
|
||||||
Vim.mapCommand("L", "action", "finrodFocusNext", {}, { 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();
|
fillLangs();
|
||||||
|
|||||||
Reference in New Issue
Block a user