From 014a0be9e2aa3e7a49919ad02815ae608ee76d63 Mon Sep 17 00:00:00 2001 From: ori Date: Fri, 12 Jun 2026 17:22:51 +0300 Subject: [PATCH 1/3] fix: show startup toast when vim is disabled, align :vim title When vim mode is persisted as disabled via /vim toggle, OpenCode starts with all keys passing through and no indication why. Add a 3-second toast on startup so users know vim is off and how to re-enable it. Also rename the toggle command title from /vim to :vim for consistency with :q, :quit, :wq in the command palette. --- CHANGELOG.md | 2 ++ src/index.ts | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be3a671..542d1d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,12 +11,14 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version ### Added - `/vim` slash command to toggle vim mode on/off. State is persisted via `api.kv` so the preference survives restarts. When disabled, all keys pass through unmodified. +- Startup toast when vim mode is disabled, so users know why keybindings aren't active and how to re-enable (`/vim`). ### Fixed - `api.kv.set` call in `/vim` toggle now uses optional chaining (`api.kv?.set?.()`) to avoid crashing on OpenCode versions without `api.kv`. - Disabled check moved before autocomplete handling so Escape/Enter are not intercepted when vim is disabled. - Toggling vim off now resets to insert mode and clears pending operator/char/count state, preventing stale state on re-enable and fixing cursor style. +- `:vim` toggle command now uses `:` prefix in the palette, consistent with `:q`/`:quit`/`:wq`. ## [0.13.0] — 2026-06-09 diff --git a/src/index.ts b/src/index.ts index 214e56d..073dcc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,9 @@ const plugin: TuiPluginModule = { // Load persisted disabled state const persistedDisabled = (await api.kv?.get?.("vimcode.disabled")) as boolean | undefined; state.disabled = persistedDisabled ?? false; + if (state.disabled) { + api.ui?.toast?.({ message: "Vim mode disabled (use /vim to re-enable)", variant: "info", duration: 3000 }); + } // Track whether the previous key was the leader, so the follow-up // key also passes through to OpenCode's leader system. @@ -237,7 +240,7 @@ const plugin: TuiPluginModule = { }, { name: "vimcode.vim", - title: "/vim", + title: ":vim", category: "Vim", namespace: "palette", desc: "Toggle vim mode on/off", From e0e2504bd82aca95d03ebbacf5eb2b6d864b404c Mon Sep 17 00:00:00 2001 From: ori Date: Fri, 12 Jun 2026 17:23:57 +0300 Subject: [PATCH 2/3] refactor: deduplicate exit commands in registerLayer --- src/index.ts | 46 +++++++++++++--------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/src/index.ts b/src/index.ts index 073dcc7..b3e3791 100644 --- a/src/index.ts +++ b/src/index.ts @@ -203,41 +203,21 @@ const plugin: TuiPluginModule = { // Register all commands via registerLayer (migrated from the deprecated // api.command?.register API). Commands appear in the command palette and // are accessible as slash commands. + const exitRun = async () => { + setTimeout(() => api.keymap.dispatchCommand("app.exit"), 0); + }; + const exitCommands = ["q", "quit", "wq"].map((cmd) => ({ + name: `vimcode.${cmd}`, + title: `:${cmd}`, + category: "Vim", + namespace: "palette", + desc: cmd === "wq" ? "Exit OpenCode (write and quit)" : "Exit OpenCode", + slashName: cmd, + run: exitRun, + })); api.keymap.registerLayer?.({ commands: [ - { - name: "vimcode.q", - title: ":q", - category: "Vim", - namespace: "palette", - desc: "Exit OpenCode", - slashName: "q", - run: async () => { - setTimeout(() => api.keymap.dispatchCommand("app.exit"), 0); - }, - }, - { - name: "vimcode.quit", - title: ":quit", - category: "Vim", - namespace: "palette", - desc: "Exit OpenCode", - slashName: "quit", - run: async () => { - setTimeout(() => api.keymap.dispatchCommand("app.exit"), 0); - }, - }, - { - name: "vimcode.wq", - title: ":wq", - category: "Vim", - namespace: "palette", - desc: "Exit OpenCode (write and quit)", - slashName: "wq", - run: async () => { - setTimeout(() => api.keymap.dispatchCommand("app.exit"), 0); - }, - }, + ...exitCommands, { name: "vimcode.vim", title: ":vim", From 09460d50f9d3396274a680fa87c51c0a608cf022 Mon Sep 17 00:00:00 2001 From: ori Date: Fri, 12 Jun 2026 22:34:39 +0300 Subject: [PATCH 3/3] docs: tighten changelog entries --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 542d1d0..1a5bcea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,15 +10,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version ### Added -- `/vim` slash command to toggle vim mode on/off. State is persisted via `api.kv` so the preference survives restarts. When disabled, all keys pass through unmodified. -- Startup toast when vim mode is disabled, so users know why keybindings aren't active and how to re-enable (`/vim`). +- `/vim` toggle command to disable/enable vim mode. Persisted across restarts. +- Startup toast when vim is disabled so users know why keybindings aren't active. ### Fixed -- `api.kv.set` call in `/vim` toggle now uses optional chaining (`api.kv?.set?.()`) to avoid crashing on OpenCode versions without `api.kv`. -- Disabled check moved before autocomplete handling so Escape/Enter are not intercepted when vim is disabled. -- Toggling vim off now resets to insert mode and clears pending operator/char/count state, preventing stale state on re-enable and fixing cursor style. -- `:vim` toggle command now uses `:` prefix in the palette, consistent with `:q`/`:quit`/`:wq`. +- Optional chaining on `api.kv.set` to avoid crashes on older OpenCode versions. +- Escape/Enter no longer intercepted when vim is disabled. +- Toggling vim off resets mode and clears pending state. +- `:vim` palette title uses `:` prefix, consistent with `:q`/`:quit`/`:wq`. ## [0.13.0] — 2026-06-09