# Vim 输入法自动切换插件 面向 macOS 原生 Vim 的输入法自动切换方案: - Normal 模式固定英文输入法 - Insert 模式恢复同一 Vim 进程内上次使用的中/英状态 - macOS 上优先使用 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()` - `im-select` 仅作为 fallback > 说明:本次 Hammerspoon 方案和行为调整只针对原生 Vim 插件 `vim-im-switch-select.vim`。Obsidian 插件逻辑不变。 ## Obsidian 插件说明 本仓库仍包含 Obsidian 插件入口 `main.ts`,用于在 Obsidian 启用 Vim keymap 时切换输入法。 当前 Obsidian 插件逻辑保持原样: - 通过 `fcitx-remote` 执行输入法查询和切换。 - 监听 Obsidian / CodeMirror 的 Vim 模式变化。 - Normal / Visual 模式切到英文输入法。 - Insert / Replace 模式恢复上次 Insert 状态。 - 配置项仍使用 `manifest.json` / 插件设置页中的 `fcitx-remote` 路径和输入法 ID。 本次 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()` 方案只应用在原生 Vim 插件 `vim-im-switch-select.vim`,没有改造 Obsidian 插件。 ## 当前稳定策略 ### 模式行为 | Vim 状态 | 行为 | |---|---| | Vim 启动后 | 延迟切到英文 `ABC` | | 进入 Insert | 恢复本次 Vim 进程内上次 Insert 的中/英状态;首次默认中文 | | 离开 Insert / `Esc` | 先记录 Insert 中最后的中/英状态,再切到英文 `ABC` | 示例: ```text 第一次进入 Insert -> 中文 Insert 中手动切到英文 -> Esc -> 再次 Insert -> 英文 Insert 中手动切回中文 -> Esc -> 再次 Insert -> 中文 退出 Vim 后重新打开 -> 记忆重置,第一次 Insert 默认中文 ``` ### 为什么使用 Hammerspoon 之前只用 `im-select` 切换 macOS input source ID 时,Apple 拼音可能出现: ```text 当前输入源ID: com.apple.inputmethod.SCIM.ITABC 当前键盘布局: ABC 当前输入法Method: Pinyin – Simplified ``` 表现为菜单栏显示中文输入法,但实际仍输入英文。 Hammerspoon 可以直接设置 layout/method: ```lua hs.keycodes.setLayout("ABC") hs.keycodes.setMethod("Pinyin – Simplified") ``` 这能避免只切 source ID 导致的 Apple 拼音内部状态不一致。 ## 安装要求 ### 1. Hammerspoon 安装并运行 Hammerspoon。 在 `~/.hammerspoon/init.lua` 中启用 IPC: ```lua require("hs.ipc") hs.ipc.cliInstall() ``` Reload Hammerspoon config 后,确认命令可用: ```bash hs -c 'hs.keycodes.setLayout("ABC")' hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")' ``` 两条命令都应返回: ```text true ``` 如果出现: ```text can't access Hammerspoon message port Hammerspoon; is it running with the ipc module loaded? ``` 说明 Hammerspoon IPC 未启用或配置尚未 reload。 ### 2. im-select fallback(可选但建议保留) 当 `hs` 不可用时,插件会退回使用 `im-select`: ```bash im-select im-select com.apple.keylayout.ABC im-select com.apple.inputmethod.SCIM.ITABC ``` 常见输入源 ID: | 输入法 | ID | |---|---| | ABC | `com.apple.keylayout.ABC` | | Apple 简体拼音 | `com.apple.inputmethod.SCIM.ITABC` | ## 安装 Vim 插件 复制插件到 Vim plugin 目录: ```bash mkdir -p ~/.vim/plugin cp vim-im-switch-select.vim ~/.vim/plugin/ ``` 或在 `.vimrc` 中 source: ```vim source /path/to/vim-im-switch-select.vim ``` ## 配置 默认配置适用于 macOS ABC + Apple 简体拼音: ```vim " Hammerspoon 主路径:英文键盘布局名 let g:imselect_hs_english_layout = 'ABC' " Hammerspoon 主路径:中文输入法 Method 名 let g:imselect_hs_chinese_method = 'Pinyin – Simplified' " im-select fallback:英文输入源 ID let g:imselect_english_im = 'com.apple.keylayout.ABC' " im-select fallback:中文输入源 ID let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC' ``` 延迟配置: ```vim " 进入 Insert 后延迟恢复,默认 80ms let g:imselect_restore_delay = 80 " 恢复后再次确认目标状态,默认 200ms let g:imselect_confirm_delay = 200 ``` ## 工作原理 核心事件: ```vim InsertLeavePre -> 记录 Insert 中最后的中/英状态 InsertLeave -> 切到英文 ABC InsertEnter -> 延迟恢复上次 Insert 中/英状态 VimEnter -> 启动后延迟切到英文 ABC ``` 关键点: - `InsertLeavePre` 必须早于 `InsertLeave` 保存状态,否则 `InsertLeave` 已经切到英文。 - timer 回调会检查目标状态,避免快速 `i` 后延迟回调把 Normal 模式切回中文。 - Hammerspoon 是主路径;`im-select` 只在 `hs` 不可用时 fallback。 - 状态记忆是 script-local 内存,只在当前 Vim 进程内有效。 ## 手工测试 1. 打开 Vim: ```bash vim test-im-switch.txt ``` 2. 第一次按 `i` 进入 Insert:应切到中文。 3. 输入中文,按 `Esc`:应切到英文 `ABC`。 4. 再按 `i`:应恢复中文。 5. Insert 中手动切到英文,输入英文,按 `Esc`。 6. 再按 `i`:应恢复英文。 7. Insert 中手动切回中文,按 `Esc`,再按 `i`:应恢复中文。 8. 退出 Vim 后重新打开:第一次 Insert 默认中文,这是当前已知限制。 ## 验证命令 Vimscript 加载检查: ```bash vim -Nu NONE -n -es -S "/path/to/vim-im-switch-select.vim" -c 'qa' ``` Hammerspoon 检查: ```bash hs -c 'hs.keycodes.setLayout("ABC")' hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")' ``` ## 已知限制 ### 跨 Vim 进程不持久记忆 当前插件只在同一次 Vim 进程内记忆 Insert 中最后的中/英状态。 ```text Insert 中切到英文 -> Esc -> 再 Insert -> 英文 退出 Vim -> 重新 vi -> 第一次 Insert 默认中文 ``` 这是当前已知问题,暂不做文件持久化。 ### 依赖 Hammerspoon 运行 稳定路径依赖: - Hammerspoon 正在运行 - `hs` CLI 可用 - `hs.ipc` 已启用 - 输入法名称 `Pinyin – Simplified` 与系统一致 如果 Hammerspoon 不可用,插件会 fallback 到 `im-select`,但 fallback 只能切 input source ID,不能完全解决 Apple 拼音内部状态问题。 ### 不模拟 CapsLock / Ctrl-Space 当前实现不模拟 `Caps Lock`、`Ctrl-Space`、`Shift` 等系统快捷键。 原因:这些按键可能被 Vim 接收,导致退出 Insert 或产生额外副作用;之前调试也证明模拟 Caps 不稳定。 ## 主要文件 | 文件 | 说明 | |---|---| | `vim-im-switch-select.vim` | 当前原生 Vim 稳定插件 | | `main.ts` | Obsidian 插件入口 | | `README.md` | 中文说明文档 | | `README_en.md` | English documentation | | `CHANGELOG.md` / `CHANGELOG_en.md` | 更新日志 | | `COMPARISON.md` | 原生 Vim 插件与 Obsidian 插件对比 | | `RELEASE.md` | 发布说明 | ## 故障排除 ### 进入 Insert 仍然输入英文 先确认 Hammerspoon method 设置有效: ```bash hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")' ``` 如果返回 `true` 后仍异常,检查 Hammerspoon 日志或系统输入法名称是否不是 `Pinyin – Simplified`。 ### `hs -c` 报 IPC 错误 在 `~/.hammerspoon/init.lua` 加入: ```lua require("hs.ipc") hs.ipc.cliInstall() ``` 然后 reload Hammerspoon。 ### fallback 输入法 ID 不正确 切到目标输入法后运行: ```bash im-select ``` 将输出值配置到: ```vim let g:imselect_chinese_im = '你的输入法ID' ``` ## License MIT License