update at 2026-07-15 11:04:39
This commit is contained in:
@@ -1,276 +0,0 @@
|
|||||||
# vim-im-switch-select.vim
|
|
||||||
|
|
||||||
> 使用 `im-select` 而不是 `fcitx-remote` 的 Vim 输入法自动切换插件
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
|
|
||||||
`vim-im-switch-select.vim` 是 `vim-im-switch.vim` 的变体版本,使用 `im-select` 工具而不是 `fcitx-remote` 来控制输入法切换。
|
|
||||||
|
|
||||||
## 主要区别
|
|
||||||
|
|
||||||
| 特性 | vim-im-switch.vim | vim-im-switch-select.vim |
|
|
||||||
|------|------------------|-------------------------|
|
|
||||||
| 输入法工具 | fcitx-remote | im-select |
|
|
||||||
| 适用平台 | macOS, Linux | 主要是 macOS |
|
|
||||||
| 获取当前输入法 | `fcitx-remote -n` | `im-select` |
|
|
||||||
| 切换输入法 | `fcitx-remote -s <IM>` | `im-select <IM>` |
|
|
||||||
| 全局变量前缀 | `g:fcitx_*` | `g:imselect_*` |
|
|
||||||
| 函数前缀 | `Fcitx*` | `IMSelect*` |
|
|
||||||
|
|
||||||
## 功能特性
|
|
||||||
|
|
||||||
✅ **自动切换输入法**:在 Normal 模式和 Insert 模式之间切换时自动切换输入法
|
|
||||||
✅ **提前保存状态**:使用 `InsertLeavePre` 在离开 Insert 前保存输入法状态
|
|
||||||
✅ **异步静默处理**:使用 `job_start()` 异步执行,并屏蔽命令输出,避免阻塞和乱码
|
|
||||||
✅ **macOS 稳定恢复**:进入 Insert 后延迟恢复中文输入源,并进行一次兜底重试
|
|
||||||
|
|
||||||
## 安装要求
|
|
||||||
|
|
||||||
### 1. 安装 im-select
|
|
||||||
|
|
||||||
本项目已经包含了 `im-select` 可执行文件(适用于 macOS ARM64)。
|
|
||||||
|
|
||||||
如果你需要其他版本,可以从这里获取:
|
|
||||||
- [im-select GitHub](https://github.com/daipeihust/im-select)
|
|
||||||
|
|
||||||
或者使用项目中的 `im-select` 文件:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 确保 im-select 有执行权限
|
|
||||||
chmod +x /path/to/vim-im-switch/im-select
|
|
||||||
|
|
||||||
# 将 im-select 添加到 PATH(可选)
|
|
||||||
sudo cp /path/to/vim-im-switch/im-select /usr/local/bin/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 验证 im-select 安装
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 如果在项目目录中
|
|
||||||
./im-select
|
|
||||||
|
|
||||||
# 如果在 PATH 中
|
|
||||||
im-select
|
|
||||||
```
|
|
||||||
|
|
||||||
应该输出当前的输入法名称,例如:
|
|
||||||
```
|
|
||||||
com.apple.keylayout.ABC
|
|
||||||
```
|
|
||||||
|
|
||||||
## 安装插件
|
|
||||||
|
|
||||||
### 方法 1:复制到 Vim 插件目录
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p ~/.vim/plugin
|
|
||||||
cp vim-im-switch-select.vim ~/.vim/plugin/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法 2:在 .vimrc 中 source
|
|
||||||
|
|
||||||
```vim
|
|
||||||
" 在 .vimrc 中添加
|
|
||||||
source /Users/gavin/vim-im-switch/vim-im-switch-select.vim
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法 3:使用插件管理器
|
|
||||||
|
|
||||||
**vim-plug**:
|
|
||||||
```vim
|
|
||||||
Plug 'yourusername/vim-im-switch', { 'rtp': 'vim-im-switch-select.vim' }
|
|
||||||
```
|
|
||||||
|
|
||||||
## 配置
|
|
||||||
|
|
||||||
在 `.vimrc` 中添加配置(可选):
|
|
||||||
|
|
||||||
```vim
|
|
||||||
" 英文输入法 ID(默认值)
|
|
||||||
let g:imselect_english_im = 'com.apple.keylayout.ABC'
|
|
||||||
|
|
||||||
" 中文输入法 ID(默认值:系统自带简体拼音)
|
|
||||||
" macOS 更新后建议显式配置,不依赖自动检测
|
|
||||||
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 如何获取输入法 ID
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 切换到你想要的输入法,然后运行:
|
|
||||||
./im-select
|
|
||||||
# 或
|
|
||||||
im-select
|
|
||||||
```
|
|
||||||
|
|
||||||
常见的输入法 ID:
|
|
||||||
- 美国英文:`com.apple.keylayout.ABC`
|
|
||||||
- 简体拼音:`com.apple.inputmethod.SCIM.ITABC`
|
|
||||||
- 搜狗输入法:`com.sogou.inputmethod.sogou`
|
|
||||||
- 百度输入法:`com.baidu.inputmethod.BaiduIM.pinyin`
|
|
||||||
- 微信输入法:`com.tencent.inputmethod.wetype.pinyin`
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
|
|
||||||
插件安装后会自动工作,无需手动操作:
|
|
||||||
|
|
||||||
1. **进入 Insert 模式** (`i`, `a`, `o` 等)
|
|
||||||
- 延迟切换到中文输入法
|
|
||||||
- 约 200ms 后再次确认中文输入法,降低 macOS 状态未刷新导致的偶发失败
|
|
||||||
|
|
||||||
2. **退出 Insert 模式** (`ESC`)
|
|
||||||
- 在 `InsertLeavePre` 提前保存当前输入法状态
|
|
||||||
- 在 `InsertLeave` 自动切换到英文输入法
|
|
||||||
|
|
||||||
3. **macOS 行为说明**
|
|
||||||
- `im-select` 控制的是 macOS 输入源 ID
|
|
||||||
- 新版 macOS 中文输入法可能存在“图标为中文但内部仍输入英文”的状态
|
|
||||||
- 当前稳定版不模拟 `Ctrl-Space` / `Caps Lock`,避免快捷键被 Vim 接收导致退出 Insert 模式
|
|
||||||
|
|
||||||
## 测试
|
|
||||||
|
|
||||||
### 运行自动化测试
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 测试 im-select 功能
|
|
||||||
./test-im-select.sh
|
|
||||||
|
|
||||||
# 在 Vim 中测试插件
|
|
||||||
./run-vim-test.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 手动测试步骤
|
|
||||||
|
|
||||||
1. 启动 Vim 并打开测试文件:
|
|
||||||
```bash
|
|
||||||
vim test-im-switch.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 按 `i` 进入 Insert 模式
|
|
||||||
|
|
||||||
3. 切换到中文输入法,输入一些中文
|
|
||||||
|
|
||||||
4. 按 `ESC` 退出到 Normal 模式
|
|
||||||
- 观察输入法是否切换到英文
|
|
||||||
|
|
||||||
5. 再次按 `i` 进入 Insert 模式
|
|
||||||
- 观察输入法是否自动恢复到中文
|
|
||||||
|
|
||||||
6. 在 Insert 模式下,手动切换到英文输入法,输入一些英文
|
|
||||||
|
|
||||||
7. 按 `ESC` 退出到 Normal 模式
|
|
||||||
|
|
||||||
8. 再次按 `i` 进入 Insert 模式
|
|
||||||
- 当前稳定版会恢复到配置的中文输入法
|
|
||||||
- 如果需要保持英文,请临时禁用插件或调整 `g:imselect_chinese_im` 策略
|
|
||||||
|
|
||||||
## 调试
|
|
||||||
|
|
||||||
### 查看插件是否加载
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:echo exists('g:imselect_loaded')
|
|
||||||
" 应该输出 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### 查看保存的输入法状态
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:echo g:imselect_last_insert_im_name
|
|
||||||
" 输出上次 Insert 模式的输入法名称
|
|
||||||
```
|
|
||||||
|
|
||||||
### 手动测试函数
|
|
||||||
|
|
||||||
```vim
|
|
||||||
" 切换到英文
|
|
||||||
:call IMSelect2en()
|
|
||||||
|
|
||||||
" 恢复输入法
|
|
||||||
:call IMSelect2zh()
|
|
||||||
```
|
|
||||||
|
|
||||||
### 查看 Vim 消息
|
|
||||||
|
|
||||||
```vim
|
|
||||||
:messages
|
|
||||||
```
|
|
||||||
|
|
||||||
## 故障排除
|
|
||||||
|
|
||||||
### 插件没有效果
|
|
||||||
|
|
||||||
1. **检查 im-select 是否可执行**:
|
|
||||||
```bash
|
|
||||||
which im-select
|
|
||||||
# 或
|
|
||||||
ls -l ./im-select
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **检查 Vim 版本是否支持 job_start()**:
|
|
||||||
```vim
|
|
||||||
:echo has('job')
|
|
||||||
" 应该输出 1
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **检查是否有错误消息**:
|
|
||||||
```vim
|
|
||||||
:messages
|
|
||||||
```
|
|
||||||
|
|
||||||
### 输入法切换延迟
|
|
||||||
|
|
||||||
- 这是正常的,因为进入 Insert 后使用了 `timer_start()` 延迟恢复
|
|
||||||
- 当前稳定版会在进入 Insert 后约 80ms 切中文,并在约 200ms 后兜底确认
|
|
||||||
- 如果机器较慢或 macOS 状态刷新较慢,可以在插件中适当调大延迟值
|
|
||||||
|
|
||||||
### 输入法图标是中文但实际输入英文
|
|
||||||
|
|
||||||
这是新版 macOS 中文输入法可能出现的内部状态问题:`im-select` 已经把输入源切到中文,但中文输入法内部仍处于英文输入状态。
|
|
||||||
|
|
||||||
当前稳定版采取的处理方式:
|
|
||||||
|
|
||||||
1. 不模拟 `Ctrl-Space`、`Caps Lock`、`Shift` 等按键,避免这些按键被 Vim 接收后影响模式。
|
|
||||||
2. 进入 Insert 后延迟切换中文输入源。
|
|
||||||
3. 再进行一次中文输入源兜底确认。
|
|
||||||
|
|
||||||
如果仍偶发出现该问题,优先调整延迟时间,不建议重新加入系统快捷键模拟。
|
|
||||||
|
|
||||||
### 输入法 ID 不正确
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 切换到你的中文输入法,然后运行:
|
|
||||||
./im-select
|
|
||||||
|
|
||||||
# 将输出的 ID 配置到 .vimrc:
|
|
||||||
let g:imselect_chinese_im = '你的输入法ID'
|
|
||||||
```
|
|
||||||
|
|
||||||
## 与原版的兼容性
|
|
||||||
|
|
||||||
`vim-im-switch-select.vim` 和 `vim-im-switch.vim` 可以共存,但不建议同时使用。它们使用不同的:
|
|
||||||
- 全局变量名(`g:imselect_*` vs `g:fcitx_*`)
|
|
||||||
- 函数名(`IMSelect*` vs `Fcitx*`)
|
|
||||||
- 自动命令组名(`IMSelect` vs `Fcitx`)
|
|
||||||
|
|
||||||
## 文件清单
|
|
||||||
|
|
||||||
- `vim-im-switch-select.vim` - 插件主文件
|
|
||||||
- `im-select` - im-select 可执行文件(macOS ARM64)
|
|
||||||
- `test-im-select.sh` - 自动化测试脚本
|
|
||||||
- `run-vim-test.sh` - Vim 交互测试脚本
|
|
||||||
- `test-im-switch.txt` - 测试文件
|
|
||||||
- `README-im-select.md` - 本说明文件
|
|
||||||
|
|
||||||
## 参考链接
|
|
||||||
|
|
||||||
- [im-select GitHub](https://github.com/daipeihust/im-select)
|
|
||||||
- [原版 vim-im-switch 项目](https://github.com/yourusername/vim-im-switch)
|
|
||||||
|
|
||||||
## 许可证
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**如有问题或建议,欢迎提交 Issue!**
|
|
||||||
511
README.md
511
README.md
@@ -1,353 +1,286 @@
|
|||||||
# Vim 输入法自动切换插件
|
# Vim 输入法自动切换插件
|
||||||
|
|
||||||
[](./CHANGELOG.md)
|
面向 macOS 原生 Vim 的输入法自动切换方案:
|
||||||
[](#安装要求)
|
|
||||||
[](./LICENSE.txt)
|
|
||||||
|
|
||||||
[English](./README_en.md) | 中文
|
- Normal 模式固定英文输入法
|
||||||
|
- Insert 模式恢复同一 Vim 进程内上次使用的中/英状态
|
||||||
|
- macOS 上优先使用 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()`
|
||||||
|
- `im-select` 仅作为 fallback
|
||||||
|
|
||||||
[感谢 github 中的 vim-im-switch这个项目](https://github.com/yourusername/vim-im-switch)
|
> 说明:本次 Hammerspoon 方案和行为调整只针对原生 Vim 插件 `vim-im-switch-select.vim`。Obsidian 插件逻辑不变。
|
||||||
这个项目不能满足需求,在这个项目基础上改进。
|
|
||||||
|
|
||||||
作者:Gavin Chan
|
## Obsidian 插件说明
|
||||||
|
|
||||||
> 🚀 **智能输入法管理工具** - 为 Vim 用户打造的无感知输入法切换体验
|
本仓库仍包含 Obsidian 插件入口 `main.ts`,用于在 Obsidian 启用 Vim keymap 时切换输入法。
|
||||||
|
|
||||||
这是为 **原生 Vim** 和 **Obsidian 编辑器** 的 Vim 模式设计的智能输入法自动切换插件,包含:
|
当前 Obsidian 插件逻辑保持原样:
|
||||||
- 🎯 **Obsidian 插件**:适用于 Obsidian 编辑器的 Vim 模式
|
|
||||||
- ⚡ **Vim 插件**:适用于原生 Vim/NeoVim 编辑器
|
|
||||||
- 🌍 **跨平台支持**:macOS、Linux、Windows 全平台兼容
|
|
||||||
|
|
||||||
## ✨ 功能亮点
|
- 通过 `fcitx-remote` 执行输入法查询和切换。
|
||||||
|
- 监听 Obsidian / CodeMirror 的 Vim 模式变化。
|
||||||
|
- Normal / Visual 模式切到英文输入法。
|
||||||
|
- Insert / Replace 模式恢复上次 Insert 状态。
|
||||||
|
- 配置项仍使用 `manifest.json` / 插件设置页中的 `fcitx-remote` 路径和输入法 ID。
|
||||||
|
|
||||||
- 🔄 **自动切换输入法**:在 Vim 的 Normal 模式和 Insert 模式之间切换时,自动切换输入法
|
本次 Hammerspoon `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()` 方案只应用在原生 Vim 插件 `vim-im-switch-select.vim`,没有改造 Obsidian 插件。
|
||||||
- 🧠 **智能状态记忆**:记住上次 Insert 模式退出时的输入法状态,下次进入时自动恢复
|
|
||||||
- 🎭 **无感知体验**:完全静默切换,无 UI 闪烁或延迟
|
|
||||||
- 🌐 **中英混合友好**:完美支持中英文混合输入场景
|
|
||||||
- ⚡ **多重保障机制**:三层检测确保切换的可靠性
|
|
||||||
|
|
||||||
## 核心特性
|
## 当前稳定策略
|
||||||
### 1. 模式切换自动化
|
|
||||||
- 进入 Normal 模式(按 ESC 或其他命令)→ 自动切换到英文输入法
|
|
||||||
- 进入 Insert 模式(按 i, a, o 等)→ 自动恢复上次的输入法状态
|
|
||||||
|
|
||||||
### 2. 输入法状态记忆
|
### 模式行为
|
||||||
- 退出 Insert 模式时,自动检测并保存当前的输入法(中文/英文)
|
|
||||||
- 下次进入 Insert 模式时,自动恢复到上次保存的输入法状态
|
|
||||||
- 支持中英文混合输入场景
|
|
||||||
|
|
||||||
### 3. 智能检测机制
|
| Vim 状态 | 行为 |
|
||||||
插件采用**三重检测机制**确保可靠性:
|
|---|---|
|
||||||
|
| Vim 启动后 | 延迟切到英文 `ABC` |
|
||||||
|
| 进入 Insert | 恢复本次 Vim 进程内上次 Insert 的中/英状态;首次默认中文 |
|
||||||
|
| 离开 Insert / `Esc` | 先记录 Insert 中最后的中/英状态,再切到英文 `ABC` |
|
||||||
|
|
||||||
| 检测方式 | 优先级 | 说明 |
|
示例:
|
||||||
|---------|--------|------|
|
|
||||||
| 🎯 **键盘事件监听** | 最高 | 使用事件捕获模式监听 ESC 和 Insert 按键,响应最快 |
|
|
||||||
| 🔧 **CodeMirror 事件** | 中等 | 监听 vim-mode-change 事件,处理非按键触发的模式切换 |
|
|
||||||
| 🔄 **定时轮询** | 兜底 | 100ms 轮询检测模式变化,作为最后保障机制 |
|
|
||||||
|
|
||||||
### 4. 技术特性
|
```text
|
||||||
- ⚡ **异步处理**:使用 `job_start()` 异步执行,避免 UI 阻塞
|
第一次进入 Insert -> 中文
|
||||||
- 🛡️ **防抖机制**:100ms 防抖避免重复处理
|
Insert 中手动切到英文 -> Esc -> 再次 Insert -> 英文
|
||||||
- 🎯 **事件捕获优化**:使用 capture 模式确保最快响应
|
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 拼音内部状态不一致。
|
||||||
|
|
||||||
## 安装要求
|
## 安装要求
|
||||||
|
|
||||||
#### macOS
|
### 1. Hammerspoon
|
||||||
1. 安装 [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx):
|
|
||||||
```bash
|
安装并运行 Hammerspoon。
|
||||||
brew install fcitx-remote-for-osx
|
|
||||||
|
在 `~/.hammerspoon/init.lua` 中启用 IPC:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require("hs.ipc")
|
||||||
|
hs.ipc.cliInstall()
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 验证安装:
|
Reload Hammerspoon config 后,确认命令可用:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
fcitx-remote -n
|
hs -c 'hs.keycodes.setLayout("ABC")'
|
||||||
# 应该输出当前输入法的名称,如:com.apple.keylayout.ABC
|
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Linux
|
两条命令都应返回:
|
||||||
通过你的包管理器安装 `fcitx`:
|
|
||||||
```bash
|
|
||||||
# Ubuntu/Debian
|
|
||||||
sudo apt-get install fcitx
|
|
||||||
|
|
||||||
# Fedora
|
```text
|
||||||
sudo dnf install fcitx
|
true
|
||||||
|
|
||||||
# Arch Linux
|
|
||||||
sudo pacman -S fcitx
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Windows
|
如果出现:
|
||||||
使用项目内置的 AutoHotkey 脚本:
|
|
||||||
1. 安装 [AutoHotkey](https://www.autohotkey.com/)
|
|
||||||
2. 使用项目中的 `fcitx-remote.ahk` 脚本
|
|
||||||
3. 或下载编译好的版本:[fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe)
|
|
||||||
4. 将 exe 文件放到系统 PATH 路径中
|
|
||||||
|
|
||||||
## 安装插件
|
```text
|
||||||
|
can't access Hammerspoon message port Hammerspoon; is it running with the ipc module loaded?
|
||||||
### Obsidian 插件安装
|
|
||||||
|
|
||||||
1. 下载插件文件到 Obsidian 插件目录:
|
|
||||||
```bash
|
|
||||||
cd /path/to/your/vault/.obsidian/plugins/
|
|
||||||
git clone https://github.com/yourusername/vim-im-switch.git
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 在 Obsidian 中启用插件:
|
说明 Hammerspoon IPC 未启用或配置尚未 reload。
|
||||||
- 打开设置 → 社区插件 → 浏览
|
|
||||||
- 找到 "Vim Input Method Switch"
|
|
||||||
- 点击启用
|
|
||||||
|
|
||||||
3. 配置输入法(可选):
|
### 2. im-select fallback(可选但建议保留)
|
||||||
- 打开插件设置
|
|
||||||
- 设置英文输入法(默认:`com.apple.keylayout.ABC`)
|
|
||||||
- 设置中文输入法(默认:自动检测)
|
|
||||||
|
|
||||||
### Vim 插件安装
|
当 `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 目录:
|
||||||
|
|
||||||
1. 复制插件文件到 Vim 配置目录:
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p ~/.vim/plugin
|
mkdir -p ~/.vim/plugin
|
||||||
cp vim-im-switch.vim ~/.vim/plugin/
|
cp vim-im-switch-select.vim ~/.vim/plugin/
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 重启 Vim,插件会自动加载
|
或在 `.vimrc` 中 source:
|
||||||
|
|
||||||
3. 配置输入法(可选):
|
|
||||||
在 `.vimrc` 中添加:
|
|
||||||
```vim
|
```vim
|
||||||
" 英文输入法 ID(默认值)
|
source /path/to/vim-im-switch-select.vim
|
||||||
let g:fcitx_english_im = 'com.apple.keylayout.ABC'
|
|
||||||
|
|
||||||
" 中文输入法 ID(可选,插件会自动检测)
|
|
||||||
" let g:fcitx_chinese_im = 'com.tencent.inputmethod.wetype.pinyin'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 使用插件管理器安装
|
## 配置
|
||||||
|
|
||||||
|
默认配置适用于 macOS ABC + Apple 简体拼音:
|
||||||
|
|
||||||
**vim-plug**:
|
|
||||||
```vim
|
```vim
|
||||||
Plug 'yourusername/vim-im-switch'
|
" 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'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Vundle**:
|
延迟配置:
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
Plugin 'yourusername/vim-im-switch'
|
" 进入 Insert 后延迟恢复,默认 80ms
|
||||||
|
let g:imselect_restore_delay = 80
|
||||||
|
|
||||||
|
" 恢复后再次确认目标状态,默认 200ms
|
||||||
|
let g:imselect_confirm_delay = 200
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🚀 一键部署(推荐)
|
|
||||||
|
|
||||||
使用部署脚本同时安装 Obsidian 插件和 Vim 插件:
|
|
||||||
```bash
|
|
||||||
# 克隆项目
|
|
||||||
git clone https://github.com/yourusername/vim-im-switch.git
|
|
||||||
cd vim-im-switch
|
|
||||||
|
|
||||||
# 构建并部署
|
|
||||||
npm install
|
|
||||||
./deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
> 💡 **提示**: v2.0.2 修复了终端 Vim 中的标题闪烁问题,详见 [更新日志](./CHANGELOG.md)
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
|
|
||||||
### 基本使用场景
|
|
||||||
|
|
||||||
1. **中文输入**:
|
|
||||||
```
|
|
||||||
按 i → 进入 Insert 模式 → 输入法切换到中文(如果上次是中文)
|
|
||||||
输入中文内容
|
|
||||||
按 ESC → 退出到 Normal 模式 → 输入法切换到英文
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **英文输入**:
|
|
||||||
```
|
|
||||||
按 i → 进入 Insert 模式 → 输入法保持英文(如果上次是英文)
|
|
||||||
输入英文内容
|
|
||||||
按 ESC → 退出到 Normal 模式 → 输入法保持英文
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **中英混合**:
|
|
||||||
```
|
|
||||||
按 i → 自动恢复上次的输入法
|
|
||||||
输入中文,然后手动切换到英文继续输入
|
|
||||||
按 ESC → 保存当前输入法状态(英文)
|
|
||||||
按 i → 自动恢复英文输入法
|
|
||||||
```
|
|
||||||
|
|
||||||
### 支持的 Vim 命令
|
|
||||||
|
|
||||||
- **进入 Insert 模式**:`i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
|
|
||||||
- **退出 Insert 模式**:`ESC`, 以及其他触发 Normal 模式的命令
|
|
||||||
|
|
||||||
## 工作原理
|
## 工作原理
|
||||||
|
|
||||||
```mermaid
|
核心事件:
|
||||||
graph TD
|
|
||||||
A[Normal 模式<br/>英文输入法] -->|按 i/a/o 等| B[检测模式切换]
|
|
||||||
B --> C[恢复上次保存的<br/>输入法状态]
|
|
||||||
C --> D[Insert 模式<br/>自动恢复的输入法:<br/>中文/英文]
|
|
||||||
D -->|按 ESC| E[保存当前输入法<br/>状态 中/英]
|
|
||||||
E --> F[切换到英文输入法]
|
|
||||||
F --> A
|
|
||||||
|
|
||||||
style A fill:#e1f5ff,stroke:#01579b,stroke-width:2px
|
|
||||||
style D fill:#fff9c4,stroke:#f57f17,stroke-width:2px
|
|
||||||
style E fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
|
|
||||||
style F fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
|
|
||||||
```
|
|
||||||
|
|
||||||
插件维护一个状态机,跟踪 Vim 模式和输入法状态,在模式转换时自动切换输入法,同时保留用户偏好设置。
|
|
||||||
|
|
||||||
## 🔧 故障排除
|
|
||||||
|
|
||||||
### 快速诊断
|
|
||||||
使用内置诊断脚本:
|
|
||||||
```bash
|
|
||||||
./diagnose-im.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 常见问题
|
|
||||||
|
|
||||||
#### 🚫 插件没有效果
|
|
||||||
1. **检查依赖**:确认 fcitx-remote 是否正确安装
|
|
||||||
```bash
|
|
||||||
# macOS
|
|
||||||
fcitx-remote -n
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
which fcitx-remote
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
fcitx-remote.exe
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **检查日志**:
|
|
||||||
- **Obsidian**: 开发者控制台 (Ctrl+Shift+I)
|
|
||||||
- **Vim**: `:messages` 命令
|
|
||||||
|
|
||||||
3. **验证配置**:确认输入法名称与系统设置匹配
|
|
||||||
|
|
||||||
#### ⚠️ 输入法切换不正确
|
|
||||||
1. **获取正确的输入法名称**:
|
|
||||||
```bash
|
|
||||||
# 切换到中文输入法后执行
|
|
||||||
fcitx-remote -n
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **手动测试**:
|
|
||||||
```bash
|
|
||||||
# 切换到英文
|
|
||||||
fcitx-remote -s com.apple.keylayout.ABC
|
|
||||||
|
|
||||||
# 切换到中文(替换为你的输入法名称)
|
|
||||||
fcitx-remote -s com.tencent.inputmethod.wetype.pinyin
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **检查冲突**:暂时禁用其他 Vim 插件测试
|
|
||||||
|
|
||||||
#### 🐛 其他问题
|
|
||||||
- **权限问题**:确保 fcitx-remote 有执行权限
|
|
||||||
- **路径问题**:检查 fcitx-remote 是否在 PATH 中
|
|
||||||
- **版本兼容**:确认 Vim 版本支持 `job_start()` (Vim 8+)
|
|
||||||
|
|
||||||
## 🛠️ 开发指南
|
|
||||||
|
|
||||||
### 环境要求
|
|
||||||
- Node.js 14+
|
|
||||||
- TypeScript 4.2+
|
|
||||||
- Rollup (构建工具)
|
|
||||||
|
|
||||||
### 构建项目
|
|
||||||
```bash
|
|
||||||
# 安装依赖
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# 开发模式(监听文件变化)
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# 生产构建
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
### 项目结构
|
|
||||||
```
|
|
||||||
vim-im-switch/
|
|
||||||
├── main.ts # Obsidian 插件主文件
|
|
||||||
├── vim-im-switch.vim # Vim 插件文件
|
|
||||||
├── fcitx-remote.ahk # Windows 支持脚本
|
|
||||||
├── fcitx-remote-for-osx/ # macOS 支持工具
|
|
||||||
├── deploy.sh # 一键部署脚本
|
|
||||||
├── diagnose-im.sh # 诊断脚本
|
|
||||||
└── vim-im-switch-plugin/ # 构建输出目录
|
|
||||||
```
|
|
||||||
|
|
||||||
### 调试方法
|
|
||||||
|
|
||||||
#### Obsidian 插件调试
|
|
||||||
插件会在控制台输出关键日志:
|
|
||||||
```
|
|
||||||
🚀 [VimIMSwitch] Loading plugin...
|
|
||||||
🔤 [VimIMSwitch] ESC → English (saved Chinese)
|
|
||||||
🈳 [VimIMSwitch] → Chinese
|
|
||||||
❌ [VimIMSwitch] Error: ...
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Vim 插件调试
|
|
||||||
```vim
|
```vim
|
||||||
" 查看插件消息
|
InsertLeavePre -> 记录 Insert 中最后的中/英状态
|
||||||
:messages
|
InsertLeave -> 切到英文 ABC
|
||||||
|
InsertEnter -> 延迟恢复上次 Insert 中/英状态
|
||||||
" 检查插件是否加载
|
VimEnter -> 启动后延迟切到英文 ABC
|
||||||
:echo exists('g:fcitx_remote')
|
|
||||||
|
|
||||||
" 手动测试函数
|
|
||||||
:call Fcitx2en()
|
|
||||||
:call Fcitx2zh()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 贡献指南
|
关键点:
|
||||||
1. Fork 项目
|
|
||||||
2. 创建功能分支:`git checkout -b feature/amazing-feature`
|
|
||||||
3. 提交更改:`git commit -m 'Add amazing feature'`
|
|
||||||
4. 推送分支:`git push origin feature/amazing-feature`
|
|
||||||
5. 提交 Pull Request
|
|
||||||
|
|
||||||
## 📋 版本历史
|
- `InsertLeavePre` 必须早于 `InsertLeave` 保存状态,否则 `InsertLeave` 已经切到英文。
|
||||||
|
- timer 回调会检查目标状态,避免快速 `i<Esc>` 后延迟回调把 Normal 模式切回中文。
|
||||||
|
- Hammerspoon 是主路径;`im-select` 只在 `hs` 不可用时 fallback。
|
||||||
|
- 状态记忆是 script-local 内存,只在当前 Vim 进程内有效。
|
||||||
|
|
||||||
| 版本 | 日期 | 主要更新 |
|
## 手工测试
|
||||||
|------|------|----------|
|
|
||||||
| [v2.0.3](./CHANGELOG.md#203---2025-11-09) | 2025-11-09 | 修复 Normal 模式 ESC 键问题 |
|
|
||||||
| [v2.0.2](./CHANGELOG.md#202---2025-11-04) | 2025-11-04 | 修复终端兼容性问题 |
|
|
||||||
| [v2.0.0](./CHANGELOG.md#200---2025-11-04) | 2025-11-04 | 新增 Vim 原生插件支持 |
|
|
||||||
| [v1.0.8](./CHANGELOG.md#108---2025-01-04) | 2025-01-04 | 智能状态记忆功能 |
|
|
||||||
| [v1.0.0](./CHANGELOG.md#100---2024-06-01) | 2024-06-01 | 首次发布 |
|
|
||||||
|
|
||||||
查看 [完整更新日志](./CHANGELOG.md) 获取详细的版本更新历史。
|
1. 打开 Vim:
|
||||||
|
|
||||||
## 🔗 相关链接
|
```bash
|
||||||
|
vim test-im-switch.txt
|
||||||
|
```
|
||||||
|
|
||||||
- 📖 [English Documentation](./README_en.md)
|
2. 第一次按 `i` 进入 Insert:应切到中文。
|
||||||
- 📝 [更新日志](./CHANGELOG.md)
|
3. 输入中文,按 `Esc`:应切到英文 `ABC`。
|
||||||
- 🛠️ [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)
|
4. 再按 `i`:应恢复中文。
|
||||||
- 🐛 [问题反馈](https://github.com/yourusername/vim-im-switch
|
5. Insert 中手动切到英文,输入英文,按 `Esc`。
|
||||||
|
6. 再按 `i`:应恢复英文。
|
||||||
|
7. Insert 中手动切回中文,按 `Esc`,再按 `i`:应恢复中文。
|
||||||
|
8. 退出 Vim 后重新打开:第一次 Insert 默认中文,这是当前已知限制。
|
||||||
|
|
||||||
## 🙏 致谢
|
## 验证命令
|
||||||
|
|
||||||
感谢以下项目和贡献者:
|
Vimscript 加载检查:
|
||||||
- [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx) - macOS 输入法控制工具
|
|
||||||
- [Obsidian](https://obsidian.md/) - 强大的知识管理工具
|
|
||||||
- [Vim](https://www.vim.org/) / [NeoVim](https://neovim.io/) - 经典的文本编辑器
|
|
||||||
|
|
||||||
---
|
```bash
|
||||||
|
vim -Nu NONE -n -es -S "/path/to/vim-im-switch-select.vim" -c 'qa'
|
||||||
|
```
|
||||||
|
|
||||||
<div align="center">
|
Hammerspoon 检查:
|
||||||
|
|
||||||
**如果这个项目对你有帮助,请给个 ⭐ Star!**
|
```bash
|
||||||
|
hs -c 'hs.keycodes.setLayout("ABC")'
|
||||||
|
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
|
||||||
|
```
|
||||||
|
|
||||||
Made with ❤️ for Vim users
|
## 已知限制
|
||||||
|
|
||||||
</div>
|
### 跨 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 稳定插件 |
|
||||||
|
| `README.md` | 当前说明文档 |
|
||||||
|
| `main.ts` | Obsidian 插件入口 |
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 进入 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
|
||||||
|
|||||||
21
t.md
Normal file
21
t.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
jkfsd
|
||||||
|
及开发京东上看
|
||||||
|
开接口饭店司机
|
||||||
|
可激发卡的接口
|
||||||
|
|
||||||
|
福建省多孔菌科
|
||||||
|
及开发水电接口
|
||||||
|
激发开水大家
|
||||||
|
空间饭店
|
||||||
|
jkfd
|
||||||
|
kjfd
|
||||||
|
开娇娇饭店
|
||||||
|
kjfdk
|
||||||
|
空间发快递
|
||||||
|
jfdk
|
||||||
|
kj
|
||||||
|
|
||||||
|
激发开水大家看
|
||||||
|
|
||||||
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 测试 vim-im-switch-select.vim 插件
|
|
||||||
|
|
||||||
echo "=========================================="
|
|
||||||
echo "测试 vim-im-switch-select.vim 插件"
|
|
||||||
echo "=========================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 检查 im-select 是否可用
|
|
||||||
echo "1. 检查 im-select 是否存在..."
|
|
||||||
if [ -x "./im-select" ]; then
|
|
||||||
echo "✓ 找到 im-select 可执行文件"
|
|
||||||
IM_SELECT_CMD="./im-select"
|
|
||||||
elif command -v im-select &> /dev/null; then
|
|
||||||
echo "✓ 系统中已安装 im-select"
|
|
||||||
IM_SELECT_CMD="im-select"
|
|
||||||
else
|
|
||||||
echo "✗ 未找到 im-select"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "2. 获取当前输入法..."
|
|
||||||
CURRENT_IM=$($IM_SELECT_CMD)
|
|
||||||
echo " 当前输入法: $CURRENT_IM"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "3. 测试切换到英文输入法..."
|
|
||||||
$IM_SELECT_CMD com.apple.keylayout.ABC
|
|
||||||
sleep 0.5
|
|
||||||
NEW_IM=$($IM_SELECT_CMD)
|
|
||||||
if [ "$NEW_IM" = "com.apple.keylayout.ABC" ]; then
|
|
||||||
echo "✓ 成功切换到英文: $NEW_IM"
|
|
||||||
else
|
|
||||||
echo "✗ 切换失败,当前: $NEW_IM"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "4. 测试恢复原输入法..."
|
|
||||||
$IM_SELECT_CMD "$CURRENT_IM"
|
|
||||||
sleep 0.5
|
|
||||||
RESTORED_IM=$($IM_SELECT_CMD)
|
|
||||||
if [ "$RESTORED_IM" = "$CURRENT_IM" ]; then
|
|
||||||
echo "✓ 成功恢复到原输入法: $RESTORED_IM"
|
|
||||||
else
|
|
||||||
echo "✗ 恢复失败,当前: $RESTORED_IM"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "5. 检查 vim-im-switch-select.vim 文件..."
|
|
||||||
if [ -f "vim-im-switch-select.vim" ]; then
|
|
||||||
echo "✓ vim-im-switch-select.vim 文件存在"
|
|
||||||
echo ""
|
|
||||||
echo " 文件大小: $(wc -c < vim-im-switch-select.vim) 字节"
|
|
||||||
echo " 函数统计:"
|
|
||||||
grep -c "^function!" vim-im-switch-select.vim | xargs echo " 函数数量:"
|
|
||||||
else
|
|
||||||
echo "✗ vim-im-switch-select.vim 文件不存在"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=========================================="
|
|
||||||
echo "测试完成!"
|
|
||||||
echo "=========================================="
|
|
||||||
echo ""
|
|
||||||
echo "使用方法:"
|
|
||||||
echo "1. 复制插件到 Vim 配置目录:"
|
|
||||||
echo " cp vim-im-switch-select.vim ~/.vim/plugin/"
|
|
||||||
echo ""
|
|
||||||
echo "2. 或在 .vimrc 中添加:"
|
|
||||||
echo " source /Users/gavin/vim-im-switch/vim-im-switch-select.vim"
|
|
||||||
echo ""
|
|
||||||
echo "3. 可选配置(在 .vimrc 中):"
|
|
||||||
echo " let g:imselect_english_im = 'com.apple.keylayout.ABC'"
|
|
||||||
echo " let g:imselect_chinese_im = '$CURRENT_IM'"
|
|
||||||
echo ""
|
|
||||||
echo "4. 测试插件:"
|
|
||||||
echo " vim test-im-switch.txt"
|
|
||||||
echo ""
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
测试输入法切换功能
|
|
||||||
Test IM Switch Functionality
|
|
||||||
|
|
||||||
使用说明:
|
|
||||||
1. 在 Vim 中加载此文件
|
|
||||||
2. 按 i 进入 Insert 模式
|
|
||||||
3. 输入中文内容
|
|
||||||
4. 按 ESC 退出到 Normal 模式(应该切换到英文输入法)
|
|
||||||
5. 再次按 i 进入 Insert 模式(应该恢复到中文输入法)
|
|
||||||
|
|
||||||
测试记录:
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
" vim-im-switch-select.vim - 智能记忆输入法状态 (使用 im-select)
|
" vim-im-switch-select.vim - macOS Vim 输入法切换
|
||||||
" Author: Gavin Chan
|
" Author: Gavin Chan
|
||||||
" Modified by: codefalling, enhanced with smart IM state memory
|
" Modified by: codefalling, enhanced with smart IM state memory
|
||||||
" Version: 2.0.0
|
" Version: 2.3.1
|
||||||
" Description: 记住退出 Insert 模式时的输入法状态,下次进入时自动恢复
|
" Description: Normal 模式固定英文,Insert 模式恢复同进程内上次中/英状态
|
||||||
" 使用 im-select 而不是 fcitx-remote 切换输入法
|
|
||||||
" ---------------------------------------------------------------------
|
" ---------------------------------------------------------------------
|
||||||
" Load Once:
|
" Load Once:
|
||||||
if exists('g:imselect_loaded')
|
if exists('g:imselect_loaded')
|
||||||
@@ -21,19 +20,18 @@ endif
|
|||||||
if exists('$SSH_TTY')
|
if exists('$SSH_TTY')
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
if !executable("im-select")
|
|
||||||
|
let s:hs_cmd = executable('hs') ? exepath('hs') : ''
|
||||||
|
let s:imselect_cmd = executable('im-select') ? exepath('im-select') : ''
|
||||||
|
if s:hs_cmd ==# '' && s:imselect_cmd ==# ''
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
let s:imselect_cmd = exepath('im-select')
|
|
||||||
let s:keepcpo = &cpo
|
let s:keepcpo = &cpo
|
||||||
let g:imselect_loaded = 1
|
let g:imselect_loaded = 1
|
||||||
set cpo&vim
|
set cpo&vim
|
||||||
|
|
||||||
" ---------------------------------------------------------------------
|
" im-select fallback 使用输入源 ID;Hammerspoon 主路径使用 layout/method 名称。
|
||||||
" 全局变量:记住上次 Insert 模式的输入法名称
|
|
||||||
let g:imselect_last_insert_im_name = ''
|
|
||||||
|
|
||||||
" 英文和中文输入法的 ID(可以通过 im-select 获取)
|
|
||||||
if !exists('g:imselect_english_im')
|
if !exists('g:imselect_english_im')
|
||||||
let g:imselect_english_im = 'com.apple.keylayout.ABC'
|
let g:imselect_english_im = 'com.apple.keylayout.ABC'
|
||||||
endif
|
endif
|
||||||
@@ -42,71 +40,167 @@ if !exists('g:imselect_chinese_im')
|
|||||||
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
|
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if !exists('g:imselect_hs_english_layout')
|
||||||
|
let g:imselect_hs_english_layout = 'ABC'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('g:imselect_hs_chinese_method')
|
||||||
|
let g:imselect_hs_chinese_method = 'Pinyin – Simplified'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('g:imselect_restore_delay')
|
||||||
|
let g:imselect_restore_delay = 80
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists('g:imselect_confirm_delay')
|
||||||
|
let g:imselect_confirm_delay = 200
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:restore_timer = -1
|
||||||
|
let s:confirm_timer = -1
|
||||||
|
let s:target = ''
|
||||||
|
" 只在当前 Vim 进程内记忆;退出 Vim 后会重新默认中文。
|
||||||
|
let s:last_insert_target = 'chinese'
|
||||||
|
|
||||||
" ---------------------------------------------------------------------
|
" ---------------------------------------------------------------------
|
||||||
" Functions:
|
" Functions:
|
||||||
|
|
||||||
function! IMSelectCurrentIM() abort
|
function! IMSelectCurrentIM() abort
|
||||||
|
if s:imselect_cmd ==# ''
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
return substitute(system(shellescape(s:imselect_cmd) . ' 2>/dev/null'), '[\r\n]', '', 'g')
|
return substitute(system(shellescape(s:imselect_cmd) . ' 2>/dev/null'), '[\r\n]', '', 'g')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function! s:CancelTimer(timer) abort
|
||||||
|
if a:timer != -1
|
||||||
|
silent! call timer_stop(a:timer)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CancelInsertTimers() abort
|
||||||
|
call s:CancelTimer(s:restore_timer)
|
||||||
|
call s:CancelTimer(s:confirm_timer)
|
||||||
|
let s:restore_timer = -1
|
||||||
|
let s:confirm_timer = -1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RunHammerspoon(lua) abort
|
||||||
|
if s:hs_cmd ==# ''
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
silent! call system(shellescape(s:hs_cmd) . ' -c ' . shellescape(a:lua) . ' >/dev/null 2>&1')
|
||||||
|
return v:shell_error == 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:HammerspoonOutput(lua) abort
|
||||||
|
if s:hs_cmd ==# ''
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
return substitute(system(shellescape(s:hs_cmd) . ' -c ' . shellescape(a:lua) . ' 2>/dev/null'), '[\r\n]', '', 'g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! IMSelectSwitch(im) abort
|
function! IMSelectSwitch(im) abort
|
||||||
if has('job')
|
if a:im ==# '' || s:imselect_cmd ==# ''
|
||||||
silent! call job_start([s:imselect_cmd, a:im], {'out_io': 'null', 'err_io': 'null'})
|
return
|
||||||
|
endif
|
||||||
|
silent! call system(shellescape(s:imselect_cmd) . ' ' . shellescape(a:im) . ' >/dev/null 2>&1')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SwitchToEnglish() abort
|
||||||
|
" Hammerspoon 能直接设置 layout;比只切 source ID 更贴近 macOS 实际输入状态。
|
||||||
|
if s:RunHammerspoon('hs.keycodes.setLayout(' . string(g:imselect_hs_english_layout) . ')')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call IMSelectSwitch(g:imselect_english_im)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SwitchToChinese() abort
|
||||||
|
" Apple 拼音可能出现 source ID 已切中文但 layout 仍为 ABC 的坏状态;setMethod 可避免该问题。
|
||||||
|
if s:RunHammerspoon('hs.keycodes.setMethod(' . string(g:imselect_hs_chinese_method) . ')')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call IMSelectSwitch(g:imselect_chinese_im)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SwitchToTarget(target) abort
|
||||||
|
if a:target ==# 'english'
|
||||||
|
call s:SwitchToEnglish()
|
||||||
else
|
else
|
||||||
silent! call system(shellescape(s:imselect_cmd) . ' ' . shellescape(a:im) . ' >/dev/null 2>&1 &')
|
call s:SwitchToChinese()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:DetectInsertTarget() abort
|
||||||
|
let layout = s:HammerspoonOutput('print(hs.keycodes.currentLayout() or "")')
|
||||||
|
let method = s:HammerspoonOutput('print(hs.keycodes.currentMethod() or "")')
|
||||||
|
|
||||||
|
if layout ==# g:imselect_hs_english_layout && method ==# ''
|
||||||
|
let s:last_insert_target = 'english'
|
||||||
|
elseif method ==# g:imselect_hs_chinese_method || layout ==# g:imselect_hs_chinese_method
|
||||||
|
let s:last_insert_target = 'chinese'
|
||||||
|
else
|
||||||
|
let current_im = IMSelectCurrentIM()
|
||||||
|
if current_im ==# g:imselect_english_im
|
||||||
|
let s:last_insert_target = 'english'
|
||||||
|
elseif current_im ==# g:imselect_chinese_im
|
||||||
|
let s:last_insert_target = 'chinese'
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! IMSelectStart() abort
|
function! IMSelectStart() abort
|
||||||
call IMSelectSwitch(g:imselect_english_im)
|
let s:target = 'english'
|
||||||
|
call s:CancelInsertTimers()
|
||||||
|
call s:SwitchToEnglish()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! IMSelectEnsureTarget(timer) abort
|
function! s:ConfirmTarget(timer) abort
|
||||||
if g:imselect_last_insert_im_name != ''
|
let s:confirm_timer = -1
|
||||||
call IMSelectSwitch(g:imselect_last_insert_im_name)
|
call s:SwitchToTarget(s:target)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RestoreInsertTarget(timer) abort
|
||||||
|
let s:restore_timer = -1
|
||||||
|
" 防止快速 i<Esc> 后,延迟 timer 又把 Normal 模式切回中文。
|
||||||
|
if s:target !=# s:last_insert_target
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call s:SwitchToTarget(s:last_insert_target)
|
||||||
|
if g:imselect_confirm_delay > 0
|
||||||
|
let s:confirm_timer = timer_start(g:imselect_confirm_delay, function('s:ConfirmTarget'))
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" 离开 Insert 模式前:保存当前输入法名称
|
" 必须在 InsertLeavePre 保存;InsertLeave 中会立即切到英文。
|
||||||
function! IMSelectRemember() abort
|
function! IMSelectRemember() abort
|
||||||
let current_im = IMSelectCurrentIM()
|
call s:DetectInsertTarget()
|
||||||
if current_im != ''
|
|
||||||
let g:imselect_last_insert_im_name = current_im
|
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" 离开 Insert 模式:切换到英文
|
|
||||||
function! IMSelect2en() abort
|
function! IMSelect2en() abort
|
||||||
call IMSelectSwitch(g:imselect_english_im)
|
let s:target = 'english'
|
||||||
|
call s:CancelInsertTimers()
|
||||||
|
call s:SwitchToEnglish()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" 恢复 Insert 模式输入法
|
|
||||||
function! IMSelectRestore(timer) abort
|
|
||||||
if g:imselect_last_insert_im_name == ''
|
|
||||||
let g:imselect_last_insert_im_name = g:imselect_chinese_im
|
|
||||||
endif
|
|
||||||
call IMSelectSwitch(g:imselect_last_insert_im_name)
|
|
||||||
call timer_start(200, function('IMSelectEnsureTarget'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" 进入 Insert 模式:延迟恢复保存的输入法
|
|
||||||
function! IMSelect2zh() abort
|
function! IMSelect2zh() abort
|
||||||
call timer_start(80, function('IMSelectRestore'))
|
let s:target = s:last_insert_target
|
||||||
|
call s:CancelInsertTimers()
|
||||||
|
if g:imselect_restore_delay > 0
|
||||||
|
let s:restore_timer = timer_start(g:imselect_restore_delay, function('s:RestoreInsertTarget'))
|
||||||
|
else
|
||||||
|
call s:RestoreInsertTarget(-1)
|
||||||
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
" ---------------------------------------------------------------------
|
" ---------------------------------------------------------------------
|
||||||
" Autocmds:
|
" Autocmds:
|
||||||
|
|
||||||
" 绑定自动命令
|
|
||||||
function! BindIMSelectAu()
|
function! BindIMSelectAu()
|
||||||
augroup IMSelect
|
augroup IMSelect
|
||||||
autocmd!
|
autocmd!
|
||||||
" 离开 Insert 模式前:先保存输入法状态
|
|
||||||
autocmd InsertLeavePre * call IMSelectRemember()
|
autocmd InsertLeavePre * call IMSelectRemember()
|
||||||
" 离开 Insert 模式:切换到英文
|
|
||||||
autocmd InsertLeave * call IMSelect2en()
|
autocmd InsertLeave * call IMSelect2en()
|
||||||
" 进入 Insert 模式:恢复上次的输入法状态
|
|
||||||
autocmd InsertEnter * call IMSelect2zh()
|
autocmd InsertEnter * call IMSelect2zh()
|
||||||
" Vim 启动后:切换到英文
|
|
||||||
autocmd VimEnter * call timer_start(100, {-> IMSelectStart()})
|
autocmd VimEnter * call timer_start(100, {-> IMSelectStart()})
|
||||||
augroup END
|
augroup END
|
||||||
endfunction
|
endfunction
|
||||||
@@ -115,11 +209,11 @@ function! UnBindIMSelectAu()
|
|||||||
augroup IMSelect
|
augroup IMSelect
|
||||||
autocmd!
|
autocmd!
|
||||||
augroup END
|
augroup END
|
||||||
|
call s:CancelInsertTimers()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
call BindIMSelectAu()
|
call BindIMSelectAu()
|
||||||
|
|
||||||
" 多光标支持:在选择多个光标前后的处理
|
|
||||||
function! IMSelect_multiple_cursors_before()
|
function! IMSelect_multiple_cursors_before()
|
||||||
call UnBindIMSelectAu()
|
call UnBindIMSelectAu()
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
" fcitx-osx.vim - 智能记忆输入法状态
|
|
||||||
" Author: Gavin Chan
|
|
||||||
" Modified by: codefalling, enhanced with smart IM state memory
|
|
||||||
" Version: 2.0.0
|
|
||||||
" Description: 记住退出 Insert 模式时的输入法状态,下次进入时自动恢复
|
|
||||||
" ---------------------------------------------------------------------
|
|
||||||
" Load Once:
|
|
||||||
if exists('g:fcitx_remote')
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
if &ttimeoutlen <= 0 || &ttimeoutlen > 50
|
|
||||||
set ttimeoutlen=50
|
|
||||||
endif
|
|
||||||
|
|
||||||
if (has("win32") || has("win95") || has("win64") || has("win16"))
|
|
||||||
" Windows 下不要载入
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
if exists('$SSH_TTY')
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
if !executable("fcitx-remote")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let s:keepcpo = &cpo
|
|
||||||
let g:loaded_fcitx = 1
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
" ---------------------------------------------------------------------
|
|
||||||
" 全局变量:记住上次 Insert 模式的输入法名称
|
|
||||||
let g:fcitx_last_insert_im_name = ''
|
|
||||||
|
|
||||||
" 英文和中文输入法的 ID(可以通过 fcitx-remote -n 获取)
|
|
||||||
if !exists('g:fcitx_english_im')
|
|
||||||
let g:fcitx_english_im = 'com.apple.keylayout.ABC'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists('g:fcitx_chinese_im')
|
|
||||||
let g:fcitx_chinese_im = 'auto-detect' " 将自动检测
|
|
||||||
endif
|
|
||||||
|
|
||||||
" ---------------------------------------------------------------------
|
|
||||||
" Functions:
|
|
||||||
|
|
||||||
function! FcitxCurrentIM() abort
|
|
||||||
return substitute(system('fcitx-remote -n 2>/dev/null'), '[\r\n]', '', 'g')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! FcitxSwitch(im) abort
|
|
||||||
silent! call system('fcitx-remote -s ' . shellescape(a:im) . ' >/dev/null 2>&1')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! FcitxStart() abort
|
|
||||||
call FcitxSwitch(g:fcitx_english_im)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" 离开 Insert 模式:保存当前输入法名称,然后切换到英文
|
|
||||||
function! Fcitx2en() abort
|
|
||||||
let current_im = FcitxCurrentIM()
|
|
||||||
if current_im != ''
|
|
||||||
let g:fcitx_last_insert_im_name = current_im
|
|
||||||
endif
|
|
||||||
call FcitxSwitch(g:fcitx_english_im)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" 进入 Insert 模式:根据保存的输入法名称恢复
|
|
||||||
function! Fcitx2zh() abort
|
|
||||||
if g:fcitx_last_insert_im_name == '' || g:fcitx_last_insert_im_name == g:fcitx_english_im
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call FcitxSwitch(g:fcitx_last_insert_im_name)
|
|
||||||
endfunction
|
|
||||||
" ---------------------------------------------------------------------
|
|
||||||
" Autocmds:
|
|
||||||
|
|
||||||
" 绑定自动命令
|
|
||||||
function! BindAu()
|
|
||||||
augroup Fcitx
|
|
||||||
autocmd!
|
|
||||||
" 离开 Insert 模式:保存输入法状态并切换到英文
|
|
||||||
autocmd InsertLeave * call Fcitx2en()
|
|
||||||
" 进入 Insert 模式:恢复上次的输入法状态
|
|
||||||
autocmd InsertEnter * call Fcitx2zh()
|
|
||||||
" Vim 启动后:切换到英文
|
|
||||||
autocmd VimEnter * call timer_start(100, {-> FcitxStart()})
|
|
||||||
augroup END
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! UnBindAu()
|
|
||||||
augroup Fcitx
|
|
||||||
autocmd!
|
|
||||||
augroup END
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call BindAu()
|
|
||||||
|
|
||||||
" 多光标支持:在选择多个光标前后的处理
|
|
||||||
function! Multiple_cursors_before()
|
|
||||||
call UnBindAu()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! Multiple_cursors_after()
|
|
||||||
call Fcitx2en()
|
|
||||||
call BindAu()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" ---------------------------------------------------------------------
|
|
||||||
" Restoration And Modelines:
|
|
||||||
let &cpo=s:keepcpo
|
|
||||||
unlet s:keepcpo
|
|
||||||
|
|
||||||
let g:fcitx_remote = 1
|
|
||||||
|
|
||||||
" vim:fdm=expr:fde=getline(v\:lnum-1)=~'\\v"\\s*-{20,}'?'>1'\:1
|
|
||||||
Reference in New Issue
Block a user