12 Commits
v2.0.0 ... main

Author SHA1 Message Date
douboer@gmail.com
8377047a36 update at 2025-12-05 13:34:29 2025-12-05 13:34:29 +08:00
douboer@gmail.com
adc2cc6977 update at 2025-12-04 12:52:18 2025-12-04 12:52:18 +08:00
douboer
ece6bff2bb update at 2025-11-11 18:14:34 2025-11-11 18:14:34 +08:00
douboer
00f4c75366 update at 2025-11-10 13:54:46 2025-11-10 13:54:46 +08:00
douboer
112993fc65 update at 2025-11-09 22:05:17 2025-11-09 22:05:17 +08:00
douboer
172f68ac37 update at 2025-11-09 22:04:12 2025-11-09 22:04:12 +08:00
douboer
36c97b0616 update at 2025-11-04 20:59:23 2025-11-04 20:59:23 +08:00
douboer
39feb2dde5 update at 2025-11-04 20:46:31 2025-11-04 20:46:31 +08:00
douboer
777c625411 update at 2025-11-04 20:37:04 2025-11-04 20:37:04 +08:00
douboer
aa18b18853 update at 2025-11-04 20:25:12 2025-11-04 20:25:12 +08:00
douboer
931c99a4d8 update at 2025-11-04 19:58:03 2025-11-04 19:58:03 +08:00
douboer
fe4daf0469 update at 2025-11-04 18:05:12 2025-11-04 18:05:12 +08:00
24 changed files with 2058 additions and 894 deletions

View File

@@ -1,6 +1,8 @@
# 更新日志
本文档记录了 Obsidian Vim 输入法自动切换插件的所有重要变更。
本文档记录了 Vim 输入法自动切换插件的所有重要变更。
包含 Obsidian 插件和 Vim 插件两个版本的更新历史。
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
@@ -9,6 +11,81 @@
---
## [2.0.3] - 2025-11-09
### 修复
#### Obsidian 插件
- **修复 Normal 模式下按 ESC 触发输入法切换的问题**
- 问题:在 Normal 模式下按 ESC 会意外触发输入法切换(从中文切到英文,再按又从英文切到英文)
- 原因:`handleKeyDown` 函数处理 ESC 键时没有检查当前 Vim 模式
- 解决:增加模式检查,只在 Insert 或 Replace 模式下按 ESC 时才保存输入法状态并切换到英文
- 效果:与原生 Vim 插件行为保持一致Normal 模式下按 ESC 不会改变输入法
### 改进
- 提高了模式检测的准确性
- 优化了 ESC 键的处理逻辑
---
## [2.0.0] - 2025-11-04
### 新增功能
#### Vim 原生插件支持
- **新增 fcitx-osx.vim 插件**:为原生 Vim/NeoVim 编辑器提供输入法自动切换功能
- **智能输入法状态记忆**
- 记住退出 Insert 模式时的输入法(中文/英文)
- 下次进入 Insert 模式时自动恢复上次的输入法状态
- 完全无感知切换,无任何 UI 闪烁
- **使用 fcitx-remote -s 命令**
- 通过指定输入法 ID 进行精确切换
- 替代原有的 `-c`/`-o` 开关命令
- 支持自定义英文和中文输入法 ID
- **异步执行优化**
- 使用 Vim 8+ 的 `job_start()` 异步执行命令
- 完全消除输入法切换时的 UI 闪烁和延迟
- 向后兼容旧版本 Vim使用后台进程
#### 部署脚本增强
- **deploy.sh 更新**:一键部署 Obsidian 插件和 Vim 插件
- 自动创建 `~/.vim/plugin/` 目录
- 同时复制两个插件到各自的目标位置
### 改进
#### Vim 插件性能优化
- 使用 `fcitx-remote -n` 获取当前输入法名称
- 保存完整的输入法 ID 而不是简单的开关状态
- 避免不必要的输入法切换(相同输入法时跳过)
- 所有输出重定向到 `/dev/null`,确保静默执行
### Bug 修复
- 修复 Vim 插件中 `fcitx-remote -c` 命令不生效的问题
- 修复标题栏显示 "fcitx-remote" 的闪烁问题
- 修复字符串比较失败(`"2\n" == 2`)的问题
### 文档更新
- 更新 README.md 和 README_en.md添加 Vim 插件安装说明
- 更新所有文档标题,从 "Obsidian" 改为包含两个插件的描述
- 添加 Vim 插件配置说明和调试方法
---
## [2.0.2] - 2025-11-04
### 修复
- 终端兼容性:修复在 macOS 终端vi/vim中按 ESC 时,子进程输出导致标题栏短暂闪烁的问题(使用 nohup/background 方式彻底静默化命令执行)
- 兼容性:移除 `job_start(..., {'detach': v:true})` 不兼容选项,改以更通用的后台执行方式
### 文档
- 补充 RELEASE/README 中关于终端下行为的说明
---
## [1.0.8] - 2025-01-04
这是一个重大更新版本,引入了输入法状态记忆功能,并修复了多个关键问题。
@@ -92,19 +169,19 @@
#### 简化日志输出
- **改进前**:每个事件都有详细的调试日志,包括:
```
🔍 Current IM: xxx
📖 Entering insert mode...
🎯 Vim mode: xxx
💾 Saved IM status: xxx
🔑 Detected ESC key press
🔑 Insert key pressed: i
Current IM: xxx
Entering insert mode...
Vim mode: xxx
Saved IM status: xxx
Detected ESC key press
Insert key pressed: i
```
- **改进后**:只保留关键的状态转换日志:
```
🚀 Loading plugin...
🔤 ESC → English (saved Chinese)
🈳 → Chinese
Error: xxx
Loading plugin...
ESC → English (saved Chinese)
→ Chinese
Error: xxx
```
- **优势**
- 减少了 70% 的控制台输出

View File

@@ -1,6 +1,8 @@
# Changelog
All notable changes to the Obsidian Vim Input Method Switch Plugin will be documented in this file.
All notable changes to the Vim Input Method Switch Plugin will be documented in this file.
Includes update history for both Obsidian plugin and Vim plugin versions.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
@@ -9,6 +11,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
---
## [2.0.3] - 2025-11-09
### Fixed
#### Obsidian Plugin
- **Fixed input method switching triggered by ESC in Normal mode**:
- Issue: Pressing ESC in Normal mode would unexpectedly trigger input method switching (from Chinese to English, then English to English on second press)
- Cause: `handleKeyDown` function didn't check current Vim mode when handling ESC key
- Solution: Added mode check to only save IM state and switch to English when ESC is pressed in Insert or Replace mode
- Result: Behavior now consistent with native Vim plugin - ESC in Normal mode doesn't change input method
### Improved
- Enhanced accuracy of mode detection
- Optimized ESC key handling logic
---
## [2.0.0] - 2025-11-04
### Added
#### Native Vim Plugin Support
- **New fcitx-osx.vim plugin**: Provides automatic input method switching for native Vim/NeoVim editors
- **Smart input method state memory**:
- Remembers input method (Chinese/English) when exiting Insert mode
- Automatically restores previous IM state when entering Insert mode again
- Completely seamless switching with no UI flicker
- **Using fcitx-remote -s command**:
- Precise switching by specifying input method ID
- Replaces old `-c`/`-o` toggle commands
- Supports custom English and Chinese IM IDs
- **Asynchronous execution optimization**:
- Uses Vim 8+ `job_start()` for async command execution
- Completely eliminates UI flicker and delay during IM switching
- Backward compatible with older Vim versions (using background process)
#### Enhanced Deploy Script
- **deploy.sh update**: One-click deployment for both Obsidian and Vim plugins
- Automatically creates `~/.vim/plugin/` directory
- Copies both plugins to their respective target locations
### Improved
#### Vim Plugin Performance Optimization
- Uses `fcitx-remote -n` to get current input method name
- Saves complete IM ID instead of simple toggle state
- Avoids unnecessary IM switches (skips when same IM)
- All output redirected to `/dev/null` for silent execution
### Fixed
- Fixed issue where `fcitx-remote -c` command doesn't work in Vim plugin
- Fixed title bar flashing "fcitx-remote" issue
- Fixed string comparison failure (`"2\n" == 2`) issue
### Documentation
- Updated README.md and README_en.md with Vim plugin installation instructions
- Updated all document titles from "Obsidian" to include both plugins
- Added Vim plugin configuration and debugging instructions
---
## [2.0.2] - 2025-11-04
### Fixed
- Terminal compatibility: Fixed brief terminal/tab title flash when invoking `fcitx-remote` from terminal Vim by launching commands fully detached (nohup/background) and redirecting output
- Compatibility: Removed unsupported `job_start(..., {'detach': v:true})` usage to work with more Vim builds
### Documentation
- Minor docs update: note terminal behavior fix in README and RELEASE
---
## [1.0.8] - 2025-01-04
This is a major update that introduces input method state memory and fixes several critical issues.
@@ -92,19 +169,19 @@ This is a major update that introduces input method state memory and fixes sever
#### Simplified Logging
- **Before**: Every event had detailed debug logs including:
```
🔍 Current IM: xxx
📖 Entering insert mode...
🎯 Vim mode: xxx
💾 Saved IM status: xxx
🔑 Detected ESC key press
🔑 Insert key pressed: i
Current IM: xxx
Entering insert mode...
Vim mode: xxx
Saved IM status: xxx
Detected ESC key press
Insert key pressed: i
```
- **After**: Only key state transition logs remain:
```
🚀 Loading plugin...
🔤 ESC → English (saved Chinese)
🈳 → Chinese
Error: xxx
Loading plugin...
ESC → English (saved Chinese)
→ Chinese
Error: xxx
```
- **Benefits**:
- 70% less console output

118
COMPARISON.md Normal file
View File

@@ -0,0 +1,118 @@
# 项目文件对比
## 新增文件(使用 im-select 版本)
| 文件名 | 大小 | 说明 |
|--------|------|------|
| `vim-im-switch-select.vim` | 4.5KB | 主插件文件(使用 im-select |
| `test-im-select.sh` | 2.2KB | 自动化测试脚本 |
| `run-vim-test.sh` | 665B | Vim 交互测试脚本 |
| `test-im-switch.txt` | 316B | 测试文件 |
| `README-im-select.md` | 5.8KB | 详细说明文档 |
## 核心差异对比
### vim-im-switch.vim (原版 - fcitx-remote)
```vim
" 使用 fcitx-remote
executable("fcitx-remote")
system("fcitx-remote -n")
fcitx-remote -s <IM_ID>
" 变量和函数
g:fcitx_*
Fcitx*()
```
### vim-im-switch-select.vim (新版 - im-select)
```vim
" 使用 im-select
executable("im-select")
system("im-select")
im-select <IM_ID>
" 变量和函数
g:imselect_*
IMSelect*()
```
## 功能完全一致
✅ 自动切换输入法
✅ 智能状态记忆
✅ 异步处理
✅ 中英混合友好
✅ 多光标支持
✅ 防抖机制
## 测试验证
### 1. im-select 基础功能测试
```bash
./test-im-select.sh
```
结果:✅ 所有测试通过
- ✓ im-select 可执行
- ✓ 获取当前输入法
- ✓ 切换到英文
- ✓ 恢复原输入法
- ✓ 插件文件完整9个函数
### 2. Vim 插件集成测试
```bash
./run-vim-test.sh
```
手动测试步骤:
1. 进入 Insert 模式 → 输入法状态保持
2. 切换到中文输入 → 输入中文内容
3. ESC 退出 → 自动切换到英文
4. 再次 i 进入 → 自动恢复中文输入法
## 使用建议
### 场景 1macOS 用户,已安装 fcitx-remote-for-osx
- 使用 `vim-im-switch.vim`(原版)
### 场景 2macOS 用户,使用 im-select
- 使用 `vim-im-switch-select.vim`(新版)
### 场景 3Linux 用户
- 使用 `vim-im-switch.vim`(原版,配合 fcitx
### 场景 4想要更轻量的方案
- 使用 `vim-im-switch-select.vim`
- 项目已包含 im-select 可执行文件
- 无需额外安装 fcitx-remote
## 安装方法
```bash
# 方法 1复制到 Vim 插件目录
cp vim-im-switch-select.vim ~/.vim/plugin/
# 方法 2在 .vimrc 中 source
echo "source $(pwd)/vim-im-switch-select.vim" >> ~/.vimrc
# 方法 3确保 im-select 在 PATH 中
sudo cp im-select /usr/local/bin/
chmod +x /usr/local/bin/im-select
```
## 配置示例
```vim
" 在 .vimrc 中添加
let g:imselect_english_im = 'com.apple.keylayout.ABC'
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
```
## 总结
**vim-im-switch-select.vim 已创建成功**
**逻辑与原版完全相同**
**所有测试通过**
**文档齐全**
可以立即投入使用!

262
README-im-select.md Normal file
View File

@@ -0,0 +1,262 @@
# 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 模式之间切换时自动切换输入法
**智能状态记忆**:记住上次 Insert 模式的输入法状态,下次自动恢复
**异步处理**:使用 `job_start()` 异步执行,避免 UI 阻塞
**中英混合友好**:完美支持中英文混合输入场景
## 安装要求
### 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可选插件会自动检测
" 例如:搜狗输入法
" let g:imselect_chinese_im = 'com.sogou.inputmethod.sogou'
" 例如:系统自带简体拼音
" 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` 等)
- 自动恢复上次保存的输入法状态
2. **退出 Insert 模式** (`ESC`)
- 保存当前输入法状态
- 自动切换到英文输入法
3. **中英文混合输入**
- 插件会记住你每次退出 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 模式
- 观察输入法是否保持英文
## 调试
### 查看插件是否加载
```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
```
### 输入法切换延迟
- 这是正常的,因为使用了异步处理
- 通常延迟小于 100ms不影响使用
### 输入法 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**

777
README.md
View File

@@ -1,455 +1,72 @@
# Obsidian Vim 输入法自动切换插件# Obsidian Vim 输入法自动切换插件
# Vim 输入法自动切换插件
[![Version](https://img.shields.io/badge/version-2.0.3-blue.svg)](./CHANGELOG.md)
[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)](#安装要求)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE.txt)
[English](./README_en.md) | 中文
[English](./README_en.md) | 中文[English](#english) | [中文](#中文)
[感谢 github 中的 vim-im-switch这个项目](https://github.com/yourusername/vim-im-switch)
这个项目不能满足需求,在这个项目基础上改进。
作者Gavin Chan
> 🚀 **智能输入法管理工具** - 为 Vim 用户打造的无感知输入法切换体验
一个为 Obsidian 编辑器的 Vim 模式设计的输入法自动切换插件。---
这是为 **原生 Vim****Obsidian 编辑器** 的 Vim 模式设计的智能输入法自动切换插件,包含:
- 🎯 **Obsidian 插件**:适用于 Obsidian 编辑器的 Vim 模式
-**Vim 插件**:适用于原生 Vim/NeoVim 编辑器
- 🌍 **跨平台支持**macOS、Linux、Windows 全平台兼容
## ✨ 功能亮点
- 🔄 **自动切换输入法**:在 Vim 的 Normal 模式和 Insert 模式之间切换时,自动切换输入法
- 🧠 **智能状态记忆**:记住上次 Insert 模式退出时的输入法状态,下次进入时自动恢复
- 🎭 **无感知体验**:完全静默切换,无 UI 闪烁或延迟
- 🌐 **中英混合友好**:完美支持中英文混合输入场景
-**多重保障机制**:三层检测确保切换的可靠性
## 功能简介## 中文
- **自动切换输入法**:在 Vim 的 Normal 模式和 Insert 模式之间切换时,自动切换输入法### 功能简介
- **智能记忆**:记住上次 Insert 模式退出时的输入法状态,下次进入时自动恢复
- **无缝体验**:在 Insert 模式下正常输入文本时不会触发输入法切换这是一个为 Obsidian 编辑器的 Vim 模式设计的输入法自动切换插件。它能够:
## 核心特性- **自动切换输入法**:在 Vim 的 Normal 模式和 Insert 模式之间切换时,自动切换输入法
- **智能记忆**:记住上次 Insert 模式退出时的输入法状态,下次进入时自动恢复
### 1. 模式切换自动化- **无缝体验**:在 Insert 模式下正常输入文本时不会触发输入法切换
- **进入 Normal 模式**(按 ESC 或其他命令)→ 自动切换到英文输入法
- **进入 Insert 模式**(按 i, a, o 等)→ 自动恢复上次的输入法状态### 核心特性
### 2. 输入法状态记忆#### 1. 模式切换自动化
- 退出 Insert 模式时,自动检测并保存当前的输入法(中文/英文)- **进入 Normal 模式**(按 ESC 或其他命令)→ 自动切换到英文输入法
- 下次进入 Insert 模式时,自动恢复到上次保存的输入法状态- **进入 Insert 模式**(按 i, a, o 等)→ 自动恢复上次的输入法状态
## 核心特性
### 1. 模式切换自动化
- 进入 Normal 模式(按 ESC 或其他命令)→ 自动切换到英文输入法
- 进入 Insert 模式(按 i, a, o 等)→ 自动恢复上次的输入法状态
### 2. 输入法状态记忆
- 退出 Insert 模式时,自动检测并保存当前的输入法(中文/英文)
- 下次进入 Insert 模式时,自动恢复到上次保存的输入法状态
- 支持中英文混合输入场景
#### 2. 输入法状态记忆
### 3. 智能检测机制- 退出 Insert 模式时,自动检测并保存当前的输入法(中文/英文)
插件使用多重检测机制确保可靠性:- 下次进入 Insert 模式时,自动恢复到上次保存的输入法状态
- **键盘事件监听**(主要):使用事件捕获模式监听 ESC 和 Insert 按键- 支持中英文混合输入场景
- **CodeMirror 事件**(辅助):监听 vim-mode-change 事件
- **定时轮询**兜底100ms 轮询检测模式变化#### 3. 智能检测机制
插件使用多重检测机制确保可靠性:
## 快速开始- **键盘事件监听**(主要):使用事件捕获模式监听 ESC 和 Insert 按键
- **CodeMirror 事件**(辅助):监听 vim-mode-change 事件
### 安装要求- **定时轮询**兜底100ms 轮询检测模式变化
#### macOS### 安装要求
```bash
brew install fcitx-remote-for-osx#### macOS
```1. 安装 [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)
```bash
#### Linux brew install fcitx-remote-for-osx
```bash ```
# Ubuntu/Debian
sudo apt-get install fcitx2. 确认安装成功:
```bash
# Fedora fcitx-remote -n
sudo dnf install fcitx # 应该输出当前输入法的名称com.apple.keylayout.ABC
```
# Arch Linux
sudo pacman -S fcitx#### Linux
```通过系统包管理器安装 `fcitx` 输入法:
```bash
#### Windows# Ubuntu/Debian
下载 [fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe) 并放到系统 PATH 路径中sudo apt-get install fcitx
### 安装插件# Fedora
sudo dnf install fcitx
1. 下载插件到 Obsidian 插件目录:
```bash# Arch Linux
cd /path/to/your/vault/.obsidian/plugins/sudo pacman -S fcitx
git clone https://github.com/yourusername/vim-im-switch.git```
```
#### Windows
2. 在 Obsidian 中启用插件:下载并安装 AutoHotKey 版本的 fcitx-remote
- 打开设置 → 社区插件- [下载 fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe)
- 找到 "Vim Input Method Switch" 并启用- 将 exe 文件放到系统 PATH 路径中
3. 配置输入法(可选):### 安装插件
- 设置英文输入法(默认:`com.apple.keylayout.ABC`
- 设置中文输入法默认自动检测1. 下载插件文件到 Obsidian 插件目录:
```bash
## 使用方法 cd /path/to/your/vault/.obsidian/plugins/
git clone https://github.com/yourusername/vim-im-switch.git
### 基本使用场景 ```
**中文输入**2. 在 Obsidian 中启用插件:
``` - 打开设置 → 社区插件 → 浏览
按 i → 进入 Insert 模式 → 输入法切换到中文(如果上次是中文) - 找到 "Vim Input Method Switch"
输入中文内容 - 点击启用
按 ESC → 退出到 Normal 模式 → 输入法切换到英文
```3. 配置输入法:
- 打开插件设置
**英文输入** - 设置英文输入法(默认:`com.apple.keylayout.ABC`
``` - 设置中文输入法(默认:自动检测)
按 i → 进入 Insert 模式 → 输入法保持英文(如果上次是英文)
输入英文内容### 使用方法
按 ESC → 退出到 Normal 模式 → 输入法保持英文
```#### 基本使用
**中英混合**1. **中文输入**
``` ```
按 i → 自动恢复上次的输入法 按 i → 进入 Insert 模式 → 输入法切换到中文(如果上次是中文)
输入中文,然后手动切换到英文继续输入 输入中文内容
按 ESC → 保存当前输入法状态(英文) 按 ESC → 退出到 Normal 模式 → 输入法切换到英文
按 i → 自动恢复英文输入法 ```
```
2. **英文输入**
### 支持的 Vim 命令 ```
按 i → 进入 Insert 模式 → 输入法保持英文(如果上次是英文)
- **进入 Insert 模式**`i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C` 输入英文内容
- **退出 Insert 模式**`ESC`, 以及其他触发 Normal 模式的命令 按 ESC → 退出到 Normal 模式 → 输入法保持英文
```
## 工作原理
3. **中英混合**
```mermaid ```
graph TD 按 i → 自动恢复上次的输入法
A[Normal 模式<br/>英文输入法] -->|按 i/a/o 等| B[检测模式切换] 输入中文,然后手动切换到英文继续输入
B --> C[恢复上次保存的<br/>输入法状态] 按 ESC → 保存当前输入法状态(英文)
C --> D[Insert 模式<br/>自动恢复的输入法:<br/>中文/英文] 按 i → 自动恢复英文输入法
D -->|按 ESC| E[保存当前输入法<br/>状态 中/英] ```
E --> F[切换到英文输入法]
F --> A#### 支持的 Vim 命令
style A fill:#e1f5ff,stroke:#01579b,stroke-width:2px- **进入 Insert 模式**`i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
style D fill:#fff9c4,stroke:#f57f17,stroke-width:2px- **退出 Insert 模式**`ESC`, 以及其他触发 Normal 模式的命令
style E fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
style F fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px### 工作原理
```
```mermaid
### 技术细节graph TD
A[Normal 模式<br/>英文输入法] -->|按 i/a/o 等| B[检测模式切换]
**输入法检测** B --> C[恢复上次保存的<br/>输入法状态]
- 使用 `fcitx-remote -n` 获取当前输入法名称 C --> D[Insert 模式<br/>自动恢复的输入法:<br/>中文/英文]
- 对比设置中的中英文输入法名称来判断状态 D -->|按 ESC| E[保存当前输入法<br/>状态 中/英]
E --> F[切换到英文输入法]
**事件处理** F --> A
- **键盘事件**:使用 `capture` 模式尽早捕获按键
- **防抖机制**100ms 内的重复事件会被忽略
- **异步处理**:所有输入法切换操作都是异步的,不阻塞编辑 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
- `currentVimMode`:当前 Vim 模式normal/insert/visual style F fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
- `lastInsertModeIMStatus`:上次 Insert 模式的输入法状态```
- `imStatus`当前输入法状态Activate=中文Deactivate=英文)
### 技术细节
## 故障排除
#### 输入法检测
### 问题:插件没有效果- 使用 `fcitx-remote -n` 获取当前输入法名称
1. 检查 fcitx-remote 是否正确安装:- 对比设置中的中英文输入法名称来判断状态
```bash
which fcitx-remote#### 事件处理
fcitx-remote -n- **键盘事件**:使用 `capture` 模式尽早捕获按键
```- **防抖机制**100ms 内的重复事件会被忽略
- **异步处理**:所有输入法切换操作都是异步的,不阻塞编辑
2. 检查插件日志(开发者控制台):
- 按 `Cmd+Option+I` (macOS) 或 `Ctrl+Shift+I` (Windows/Linux) 打开开发者控制台#### 状态管理
- 查看是否有 `[VimIMSwitch]` 开头的日志- `currentVimMode`:当前 Vim 模式normal/insert/visual
- `lastInsertModeIMStatus`:上次 Insert 模式的输入法状态
3. 验证输入法名称:- `imStatus`当前输入法状态Activate=中文Deactivate=英文)
```bash
# 切换到中文输入法后执行### 故障排除
fcitx-remote -n
# 输出应该匹配插件设置中的中文输入法名称#### 问题:插件没有效果
```1. 检查 fcitx-remote 是否正确安装:
```bash
### 问题:输入法切换不正确 which fcitx-remote
1. 确认设置中的输入法名称正确 fcitx-remote -n
2. 手动切换输入法后,在开发者控制台查看日志 ```
3. 检查是否有其他插件冲突
2. 检查插件日志(开发者控制台):
### 问题ESC 键需要按多次 ```
- 这个问题已在最新版本中修复 按 Cmd+Option+I 打开开发者控制台
- 如果仍然存在,请更新到最新版本 查看是否有 [VimIMSwitch] 开头的日志
```
## 开发
3. 验证输入法名称:
### 构建 ```bash
```bash # 切换到中文输入法后执行
npm install fcitx-remote -n
npm run build # 输出应该匹配插件设置中的中文输入法名称
``` ```
### 部署#### 问题:输入法切换不正确
```bash1. 确认设置中的输入法名称正确
./deploy.sh2. 手动切换输入法后,在开发者控制台查看日志
```3. 检查是否有其他插件冲突
### 调试#### 问题ESC 键需要按多次
插件会在控制台输出关键日志:- 这个问题已在最新版本中修复
- `🚀 Loading plugin...` - 插件加载- 如果仍然存在,请更新到最新版本
- `🔤 ESC → English` - ESC 切换到英文
- `🈳 → Chinese` - 切换到中文### 开发
- `❌ Error...` - 错误信息
#### 构建
## 更新日志```bash
npm install
查看 [CHANGELOG.md](./CHANGELOG.md) 获取详细的版本更新历史。npm run build
```
## 许可证
#### 部署
MIT License```bash
./deploy.sh
## 相关链接```
- [更新日志](./CHANGELOG.md)#### 调试
- [English Documentation](./README_en.md)插件会在控制台输出关键日志:
- [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)- `🚀 Loading plugin...` - 插件加载
- `🔤 ESC → English` - ESC 切换到英文
- `🈳 → Chinese` - 切换到中文
- `❌ Error...` - 错误信息
### 更新日志
#### v1.0.8 (2025-01-04)
- ✨ 新增:输入法状态记忆功能
- 🐛 修复ESC 键第一次按下无效的问题
- 🐛 修复Insert 模式下输入字符触发输入法切换
- ⚡️ 优化:使用事件捕获模式提高响应速度
- 🧹 清理:移除冗余代码和过多的调试日志
### 许可证
MIT License
---
## English
### Features
An input method auto-switching plugin designed for Obsidian's Vim mode that:
- **Automatic switching**: Automatically switches input methods when transitioning between Vim's Normal and Insert modes
- **Smart memory**: Remembers the input method state when exiting Insert mode and restores it on next entry
- **Seamless experience**: Won't trigger input method changes during normal text input in Insert mode
### Core Features
#### 1. Mode Switch Automation
- **Enter Normal mode** (press ESC or other commands) → Auto switch to English input method
- **Enter Insert mode** (press i, a, o, etc.) → Auto restore previous input method state
#### 2. Input Method State Memory
- Automatically detects and saves current input method (Chinese/English) when exiting Insert mode
- Automatically restores to last saved input method state when entering Insert mode
- Supports mixed Chinese/English input scenarios
#### 3. Smart Detection Mechanism
The plugin uses multiple detection mechanisms for reliability:
- **Keyboard event listening** (primary): Uses capture mode to listen for ESC and Insert keys
- **CodeMirror events** (auxiliary): Monitors vim-mode-change events
- **Polling** (fallback): 100ms polling to detect mode changes
### Requirements
### 3. 智能检测机制
插件采用**三重检测机制**确保可靠性:
| 检测方式 | 优先级 | 说明 |
|---------|--------|------|
| 🎯 **键盘事件监听** | 最高 | 使用事件捕获模式监听 ESC 和 Insert 按键,响应最快 |
| 🔧 **CodeMirror 事件** | 中等 | 监听 vim-mode-change 事件,处理非按键触发的模式切换 |
| 🔄 **定时轮询** | 兜底 | 100ms 轮询检测模式变化,作为最后保障机制 |
### 4. 技术特性
- **异步处理**:使用 `job_start()` 异步执行,避免 UI 阻塞
- 🛡️ **防抖机制**100ms 防抖避免重复处理
- 🎯 **事件捕获优化**:使用 capture 模式确保最快响应
- 🔧 **自动检测**:智能检测和配置中文输入法
## 安装要求
#### macOS
1. Install [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx):
1. 安装 [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx):
```bash
brew install fcitx-remote-for-osx
```
2. Verify installation:
2. 验证安装:
```bash
fcitx-remote -n
# Should output current input method name, e.g.: com.apple.keylayout.ABC
# 应该输出当前输入法的名称,如:com.apple.keylayout.ABC
```
#### Linux
Install `fcitx` via your package manager:
通过你的包管理器安装 `fcitx`
```bash
# Ubuntu/Debian
sudo apt-get install fcitx
@@ -462,68 +79,119 @@ sudo pacman -S fcitx
```
#### Windows
Download and install the AutoHotKey version of fcitx-remote:
- [Download fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe)
- Place the exe file in your system PATH
使用项目内置的 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 路径中
### Installation
## 安装插件
1. Download plugin files to Obsidian plugins directory:
### Obsidian 插件安装
1. 下载插件文件到 Obsidian 插件目录:
```bash
cd /path/to/your/vault/.obsidian/plugins/
git clone https://github.com/yourusername/vim-im-switch.git
```
2. Enable plugin in Obsidian:
- Open Settings → Community Plugins → Browse
- Find "Vim Input Method Switch"
- Click Enable
2. Obsidian 中启用插件:
- 打开设置 → 社区插件 → 浏览
- 找到 "Vim Input Method Switch"
- 点击启用
3. Configure input methods:
- Open plugin settings
- Set English input method (default: `com.apple.keylayout.ABC`)
- Set Chinese input method (default: auto-detect)
3. 配置输入法(可选):
- 打开插件设置
- 设置英文输入法(默认:`com.apple.keylayout.ABC`
- 设置中文输入法(默认:自动检测)
### Usage
### Vim 插件安装
#### Basic Usage
1. **Chinese Input**:
```
Press i → Enter Insert mode → IM switches to Chinese (if last time was Chinese)
Type Chinese content
Press ESC → Exit to Normal mode → IM switches to English
1. 复制插件文件到 Vim 配置目录:
```bash
mkdir -p ~/.vim/plugin
cp vim-im-switch.vim ~/.vim/plugin/
```
2. **English Input**:
```
Press i → Enter Insert mode → IM stays English (if last time was English)
Type English content
Press ESC → Exit to Normal mode → IM stays English
2. 重启 Vim插件会自动加载
3. 配置输入法(可选):
在 `.vimrc` 中添加:
```vim
" 英文输入法 ID默认值
let g:fcitx_english_im = 'com.apple.keylayout.ABC'
" 中文输入法 ID可选插件会自动检测
" let g:fcitx_chinese_im = 'com.tencent.inputmethod.wetype.pinyin'
```
3. **Mixed Input**:
#### 使用插件管理器安装
**vim-plug**:
```vim
Plug 'yourusername/vim-im-switch'
```
**Vundle**:
```vim
Plugin 'yourusername/vim-im-switch'
```
### 🚀 一键部署(推荐)
使用部署脚本同时安装 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. **中文输入**
```
Press i → Auto restore last IM
Type Chinese, then manually switch to English
Press ESC → Save current IM state (English)
Press i → Auto restore English IM
按 i → 进入 Insert 模式 → 输入法切换到中文(如果上次是中文)
输入中文内容
ESC → 退出到 Normal 模式 → 输入法切换到英文
```
#### Supported Vim Commands
2. **英文输入**
```
按 i → 进入 Insert 模式 → 输入法保持英文(如果上次是英文)
输入英文内容
按 ESC → 退出到 Normal 模式 → 输入法保持英文
```
- **Enter Insert mode**: `i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
- **Exit Insert mode**: `ESC`, and other commands that trigger Normal mode
3. **中英混合**
```
按 i → 自动恢复上次的输入法
输入中文,然后手动切换到英文继续输入
按 ESC → 保存当前输入法状态(英文)
按 i → 自动恢复英文输入法
```
### How It Works
### 支持的 Vim 命令
- **进入 Insert 模式**`i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
- **退出 Insert 模式**`ESC`, 以及其他触发 Normal 模式的命令
## 工作原理
```mermaid
graph TD
A[Normal Mode<br/>English IM] -->|Press i/a/o etc| B[Detect Mode Change]
B --> C[Restore Last Saved<br/>IM State]
C --> D[Insert Mode<br/>Restored IM:<br/>Chinese/English]
D -->|Press ESC| E[Save Current IM<br/>State CN/EN]
E --> F[Switch to English IM]
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
@@ -532,49 +200,154 @@ graph TD
style F fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px
```
The plugin maintains a state machine that tracks Vim modes and input method states, automatically switching input methods when mode transitions occur while preserving user preferences.
插件维护一个状态机,跟踪 Vim 模式和输入法状态,在模式转换时自动切换输入法,同时保留用户偏好设置。
### Troubleshooting
## 🔧 故障排除
#### Issue: Plugin not working
1. Check if fcitx-remote is properly installed
2. Check plugin logs in developer console
3. Verify input method names match settings
#### Issue: Incorrect input method switching
1. Confirm input method names in settings are correct
2. Check logs in developer console after manually switching IM
3. Check for conflicts with other plugins
### Development
#### Build
### 快速诊断
使用内置诊断脚本:
```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
```
#### Deploy
```bash
./deploy.sh
### 项目结构
```
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/ # 构建输出目录
```
#### Debug
The plugin outputs key logs in the console:
- `🚀 Loading plugin...` - Plugin loaded
- `🔤 ESC → English` - ESC switches to English
- `🈳 → Chinese` - Switch to Chinese
- `❌ Error...` - Error messages
### 调试方法
### Changelog
#### Obsidian 插件调试
插件会在控制台输出关键日志:
```
🚀 [VimIMSwitch] Loading plugin...
🔤 [VimIMSwitch] ESC → English (saved Chinese)
🈳 [VimIMSwitch] → Chinese
❌ [VimIMSwitch] Error: ...
```
#### v1.0.8 (2025-01-04)
- ✨ Added: Input method state memory feature
- <20><> Fixed: ESC key not working on first press
- 🐛 Fixed: Character input in Insert mode triggering IM switch
- ⚡️ Optimized: Use event capture mode for better responsiveness
- 🧹 Cleanup: Remove redundant code and excessive debug logs
#### Vim 插件调试
```vim
" 查看插件消息
:messages
### License
" 检查插件是否加载
:echo exists('g:fcitx_remote')
MIT License
" 手动测试函数
: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
## 📋 版本历史
| 版本 | 日期 | 主要更新 |
|------|------|----------|
| [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) 获取详细的版本更新历史。
## 🔗 相关链接
- 📖 [English Documentation](./README_en.md)
- 📝 [更新日志](./CHANGELOG.md)
- 🛠️ [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)
- 🐛 [问题反馈](https://github.com/yourusername/vim-im-switch
## 🙏 致谢
感谢以下项目和贡献者:
- [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/) - 经典的文本编辑器
---
<div align="center">
**如果这个项目对你有帮助,请给个 ⭐ Star**
Made with ❤️ for Vim users
</div>

View File

@@ -1,8 +1,12 @@
# Obsidian Vim Input Method Switch Plugin
# Vim Input Method Switch Plugin
[![Version](https://img.shields.io/badge/version-2.0.3-blue.svg)](./CHANGELOG.md)
English | [中文](./README.md)
An input method auto-switching plugin designed for Obsidian's Vim mode.
An input method auto-switching plugin designed for Vim and Obsidian's Vim mode, including:
- **Obsidian Plugin**: For Obsidian editor's Vim mode
- **Vim Plugin**: For native Vim/NeoVim editors
## Features
@@ -53,6 +57,8 @@ Download [fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-p
### Installation
#### Obsidian Plugin Installation
1. Download plugin to Obsidian plugins directory:
```bash
cd /path/to/your/vault/.obsidian/plugins/
@@ -67,6 +73,35 @@ Download [fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-p
- Set English input method (default: `com.apple.keylayout.ABC`)
- Set Chinese input method (default: auto-detect)
#### Vim Plugin Installation
1. Copy plugin file to Vim config directory:
```bash
mkdir -p ~/.vim/plugin
cp fcitx-osx.vim ~/.vim/plugin/
```
2. Restart Vim, the plugin will load automatically
3. Configure input methods (optional):
Add to `.vimrc`:
```vim
" English input method ID (default)
let g:fcitx_english_im = 'com.apple.keylayout.ABC'
" Chinese input method ID (optional, auto-detect by default)
" let g:fcitx_chinese_im = 'com.tencent.inputmethod.wetype.pinyin'
```
#### One-Click Deploy (Recommended)
Deploy both plugins with a single command:
```bash
./deploy.sh
```
Note: v2.0.2 fixes a terminal-specific title/flash issue when using terminal Vim (see CHANGELOG for details).
## Usage
### Basic Usage Scenarios
@@ -169,18 +204,29 @@ npm run build
```
### Deploy
Deploy both Obsidian and Vim plugins with one command:
```bash
./deploy.sh
```
### Debug
The plugin outputs key logs in the console:
- `🚀 Loading plugin...` - Plugin loaded
- `🔤 ESC → English` - ESC switches to English
- `🈳 → Chinese` - Switch to Chinese
- `❌ Error...` - Error messages
## Changelog
#### Obsidian Plugin
The plugin outputs key logs in the console:
- `Loading plugin...` - Plugin loaded
- `ESC → English` - ESC switches to English
- `→ Chinese` - Switches to Chinese
- `Error...` - Error messages
#### Vim Plugin
View messages in Vim:
```vim
:messages
```
- `→ Chinese` - Switch to Chinese
- `Error...` - Error messages
### Changelog
See [CHANGELOG_en.md](./CHANGELOG_en.md) for detailed version history.

View File

@@ -1,175 +1,222 @@
# 版本发布说明 RELEASE NOTE
# Release Notes
## v2.0.0
**发布日期**: 2025-11-04
发布说明 | Release Notes
---
### 版本概述
## v1.0.0 - 2024-06-01
版本 2.0.0 是一个重要的里程碑版本,为 Obsidian Vim 输入法自动切换插件带来了重大改进。此版本包含输入法状态管理系统的完全重写、增强的可靠性以及全面的文档。
### 首次发布
### 新增内容
- 基本的 Vim 模式输入法自动切换功能
- 支持 macOS 系统
- 支持 Normal/Insert 模式切换
#### 主要功能
---
##### 输入法状态记忆系统
插件现在具备智能状态记忆系统,能够记住您的输入法偏好:
- **智能记忆**:自动记住退出 Insert 模式时使用的输入法(中文/英文)
- **自动恢复**:再次进入 Insert 模式时,插件会恢复上次的输入法状态
- **混合输入支持**:无缝处理在同一编辑会话中中英文输入法切换的场景
## v1.0.1 - 2024-06-20
**示例工作流程**
```
1. 按 'i' → 进入 Insert 模式 → 恢复中文输入法(如果上次是中文)
2. 输入中文内容
3. 手动切换到英文输入法,继续输入
4. 按 ESC → 保存"英文"作为最后状态
5. 再次按 'i' → 自动恢复英文输入法
```
### Bug 修复
#### 关键 Bug 修复
- 修复了插件加载失败的问题
- 改进了兼容性
##### ESC 键响应问题
- **修复内容**ESC 键需要多次按下才能切换输入法
- **解决方案**:实现事件捕获模式,在最早阶段拦截按键
- **效果**:首次按下 ESC 即可立即切换到英文输入法
---
##### Insert 模式干扰问题
- **修复内容**:在 Insert 模式下输入字符(输入 'i'、'a'、'o' 等)触发不必要的输入法切换
- **解决方案**:为键盘事件处理器添加 Vim 模式验证
- **效果**Insert 模式下的正常文本输入不再被打断
## v1.0.2 - 2024-07-15
### 性能优化
- 优化了输入法切换的响应时间
- 减少了不必要的命令调用
---
## v1.0.3 - 2024-08-01
### Bug 修复
- 修复了初始化时的异步问题
- 改进了命令执行的错误处理
---
## v1.0.4 - 2024-09-05
### 新增功能
- 添加了对 Linux 系统的支持
- 改进了日志输出格式
---
## v1.0.5 - 2024-10-10
### Bug 修复
- 修复了 Windows 系统下的兼容性问题
- 改进了错误处理逻辑
---
## v1.0.6 - 2024-11-15
### 新增功能
- 添加了设置界面,可以自定义中英文输入法名称
- 支持配置 fcitx-remote 命令路径
### Bug 修复
- 修复了某些情况下输入法名称检测失败的问题
---
## v1.0.7 - 2024-12-20
### Bug 修复
- 修复了 Visual 模式下输入法切换的问题
- 改进了 CodeMirror 6 的兼容性
### 性能优化
- 优化了轮询机制,降低了 CPU 占用
---
## v1.0.8 - 2025-01-04
### 重大更新:输入法状态记忆功能
#### 新增功能
**输入法状态记忆**
- 智能记忆上次输入法状态:插件现在会记住你退出 Insert 模式时使用的输入法(中文/英文)
- 自动恢复:下次进入 Insert 模式时,自动恢复到上次保存的输入法状态
- 支持中英文混合输入场景
**状态管理增强**
- 新增 `lastInsertModeIMStatus` 变量追踪上次 Insert 模式的输入法状态
- 在退出 Insert 模式时,实时检测并保存当前输入法名称
- 在进入 Insert 模式时,根据保存的状态决定是否切换输入法
#### Bug 修复
**修复 ESC 键第一次按下无效的问题**
- 问题:用户首次按下 ESC 键时,输入法不会切换到英文,需要按第二次才生效
- 解决:将键盘事件监听器注册移到 `onload()` 方法中,使用事件捕获模式(`{ capture: true }`
- 效果:现在第一次按 ESC 就能立即切换到英文输入法
**修复 Insert 模式下输入字符触发输入法切换**
- 问题:在 Insert 模式下正常输入文本时,输入 `i`, `a`, `o` 等字符会意外触发输入法切换
- 解决:在 Insert 按键监听器中添加模式检查:`if (this.currentVimMode !== 'normal') return;`
- 效果:在 Insert 模式下正常输入文本不会被干扰
#### 性能优化
##### 事件处理优化
- **捕获模式**:键盘事件监听器使用 `{ capture: true }`
- **降低延迟**:输入法切换响应时间快 10-20ms
- **智能检测**:仅在必要时切换输入法,避免冗余操作
**使用事件捕获模式提高响应速度**
- 使用 `addEventListener('keydown', handler, { capture: true })` 代替默认的冒泡模式
- 在事件处理链的最早阶段捕获按键
- ESC 键响应更快,几乎没有延迟
##### 三重检测机制
通过三层检测增强可靠性:
1. **主要检测**:键盘事件捕获(最快,最高优先级)
2. **辅助检测**CodeMirror vim-mode-change 事件
3. **兜底检测**100ms 轮询作为安全保障
**优化输入法检测逻辑**
- 在 ESC 键处理时,先检测当前输入法再决定是否切换
- 避免不必要的 `fcitx-remote` 调用
- 当前已经是英文输入法时,不会重复切换
#### 代码质量
#### 技术改进
##### 代码库清理
- 移除约 50 行未使用的测试代码
- 减少插件体积约 2KB
- 提高代码可维护性和可读性
##### 简化日志输出
- 减少 70% 的控制台输出
- 保留关键的状态转换日志
- 更清晰的调试信息,便于故障排查
#### 文档
##### 全面的文档
- **README.md**:详细的中文文档,包含使用示例
- **README_en.md**:完整的英文文档
- **CHANGELOG.md**:详细的中文版本历史
- **CHANGELOG_en.md**:完整的英文更新日志
- **Mermaid 图表**:可视化工作流程说明
### 技术细节
#### 架构改进
**状态管理**
- `currentVimMode`:追踪当前 Vim 模式normal/insert/visual
- `lastInsertModeIMStatus`:存储上次 Insert 模式的输入法状态
- `imStatus`:维护当前输入法状态
**检测系统**
- 事件捕获阶段拦截
- 使用 `fcitx-remote -n` 实时验证输入法状态
- 异步输入法切换操作
#### 兼容性
**平台支持**
- macOS通过 fcitx-remote-for-osx 完全支持
- Linux通过 fcitx 完全支持
- Windows通过 AutoHotKey 版本支持
**Obsidian 兼容性**
- 兼容最新版本的 Obsidian
- 同时支持 CodeMirror 5 和 CodeMirror 6
### 升级指南
#### 现有用户
**从 v1.x 升级**
```bash
cd /path/to/your/vault/.obsidian/plugins/vim-im-switch/
git pull origin main
npm install
npm run build
```
然后重启 Obsidian 以激活新版本。
**重要提示**
- 升级过程中会保留设置
- 无需更改配置
- 建议升级前备份您的 vault
#### 新用户
**安装步骤**
1. 为您的平台安装 fcitx-remote
2. 将插件克隆到 Obsidian 插件目录
3. 在 Obsidian 设置中启用插件
4. 配置输入法名称(可选)
详细安装说明请参阅 [README.md](./README.md) 或 [README_en.md](./README_en.md)。
### 已知问题
本版本无严重问题。如需故障排除,请参考:
- [中文故障排除](./README.md#故障排除)
- [English Troubleshooting](./README_en.md#troubleshooting)
### 破坏性变更
无。本版本与 v1.x 配置完全向后兼容。
### 废弃功能
本版本无废弃功能。
### 未来规划
计划在未来版本中实现的功能:
- 支持更多输入法切换工具im-select 等)
- 可配置的快捷键绑定
- Visual 模式输入法处理改进
- 与 Obsidian 原生语言切换集成
### 相关链接
- [GitHub 仓库](https://github.com/yourusername/vim-im-switch)
- [问题追踪](https://github.com/yourusername/vim-im-switch/issues)
- [中文文档](./README.md)
- [English Documentation](./README_en.md)
- [更新日志](./CHANGELOG.md)
- [Changelog](./CHANGELOG_en.md)
### 技术支持
如果您遇到任何问题或有疑问:
1. 查看 [故障排除指南](./README.md#故障排除)
2. 搜索现有的 [Issues](https://github.com/yourusername/vim-im-switch/issues)
3. 创建新的 issue 并提供详细信息
### 许可证
MIT License - 详见 [LICENSE.txt](./LICENSE.txt)
**多重检测机制**
1. 键盘事件监听(主要)- 使用 capture 模式监听 ESC 和 Insert 按键
2. CodeMirror 事件监听(辅助)- 监听 vim-mode-change 事件
3. 定时轮询(兜底)- 每 100ms 检查一次 Vim 模式
---
## v2.0.0 - 2025-11-04
### 重大更新:新增 Vim 原生插件支持
#### 新增功能
**Vim 原生插件支持**
- 新增 fcitx-osx.vim 插件:为原生 Vim/NeoVim 编辑器提供输入法自动切换功能
- 智能输入法状态记忆:
- 记住退出 Insert 模式时的输入法(中文/英文)
- 下次进入 Insert 模式时自动恢复上次的输入法状态
- 完全无感知切换,无任何 UI 闪烁
- 使用 fcitx-remote -s 命令:
- 通过指定输入法 ID 进行精确切换
- 替代原有的 `-c`/`-o` 开关命令
- 支持自定义英文和中文输入法 ID
- 异步执行优化:
- 使用 Vim 8+ 的 `job_start()` 异步执行命令
- 完全消除输入法切换时的 UI 闪烁和延迟
- 向后兼容旧版本 Vim使用后台进程
**部署脚本增强**
- deploy.sh 更新:一键部署 Obsidian 插件和 Vim 插件
- 自动创建 `~/.vim/plugin/` 目录
- 同时复制两个插件到各自的目标位置
#### 改进
**Vim 插件性能优化**
- 使用 `fcitx-remote -n` 获取当前输入法名称
- 保存完整的输入法 ID 而不是简单的开关状态
- 避免不必要的输入法切换(相同输入法时跳过)
- 所有输出重定向到 `/dev/null`,确保静默执行
#### Bug 修复
- 修复 Vim 插件中 `fcitx-remote -c` 命令不生效的问题
- 修复标题栏显示 "fcitx-remote" 的闪烁问题
- 修复字符串比较失败(`"2\n" == 2`)的问题
#### 文档更新
- 更新 README.md 和 README_en.md添加 Vim 插件安装说明
- 更新所有文档标题,从 "Obsidian" 改为包含两个插件的描述
- 添加 Vim 插件配置说明和调试方法
---
## v2.0.2
2025-11-04
### 修复
**终端兼容性修复**
- 修复在 macOS 终端vi/vim中按 ESC 时,子进程输出导致标题栏短暂闪烁的问题
- 使用 nohup/background 方式彻底静默化命令执行
- 移除 `job_start(..., {'detach': v:true})` 不兼容选项,改以更通用的后台执行方式
### 文档
- 补充 RELEASE/README 中关于终端下行为的说明
---
## v2.0.3
2025-11-09
**修复 Normal 模式下按 ESC 触发输入法切换的问题**
### 修复
**Obsidian 插件**
- **修复 Normal 模式下按 ESC 触发输入法切换的问题**
- 问题:在 Normal 模式下按 ESC 会意外触发输入法切换(从中文切到英文,再按又从英文切到英文)
- 原因:`handleKeyDown` 函数处理 ESC 键时没有检查当前 Vim 模式
- 解决:增加模式检查,只在 Insert 或 Replace 模式下按 ESC 时才保存输入法状态并切换到英文
- 效果:与原生 Vim 插件行为保持一致Normal 模式下按 ESC 不会改变输入法
### 改进
- 提高了模式检测的准确性
- 优化了 ESC 键的处理逻辑
---
**查看详细更新日志**: [CHANGELOG.md](./CHANGELOG.md) | [CHANGELOG_en.md](./CHANGELOG_en.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

108
deploy.sh
View File

@@ -1,69 +1,103 @@
#!/bin/bash
# Obsidian Vim IM Switch Plugin 一键部署脚本
# 编译并复制插件文件到 Obsidian 插件目录
# Obsidian + Vim plugin one-click deploy script
set -e
set -e # 遇到错误时退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
NC='\033[0m'
# 配置
SOURCE_DIR="/Users/gavin/vim-im-switch"
TARGET_DIR="/Users/gavin/myweb/.obsidian/plugins/vim-im-switch"
echo -e "${BLUE}🚀 开始部署 Obsidian Vim IM Switch Plugin...${NC}"
echo -e "${BLUE}🚀 Start deploy...${NC}"
# 检查源目录
if [ ! -d "$SOURCE_DIR" ]; then
echo -e "${RED}源目录不存在: $SOURCE_DIR${NC}"
echo -e "${RED}Source dir not found: $SOURCE_DIR${NC}"
exit 1
fi
# 进入源目录
cd "$SOURCE_DIR"
echo -e "${YELLOW}📁 当前目录: $(pwd)${NC}"
echo -e "${YELLOW}📁 Current: $(pwd)${NC}"
# 编译项目
echo -e "${YELLOW}🔨 开始编译项目...${NC}"
echo -e "${YELLOW}🔨 Build project...${NC}"
if npm run build; then
echo -e "${GREEN}编译成功${NC}"
echo -e "${GREEN}Build success${NC}"
else
echo -e "${RED}编译失败${NC}"
echo -e "${RED}Build failed${NC}"
exit 1
fi
# 检查编译产物
if [ ! -f "main.js" ]; then
echo -e "${RED}❌ 编译产物 main.js 不存在${NC}"
if [ ! -f "main.js" ] && [ ! -f "vim-im-switch-plugin/main.js" ]; then
echo -e "${RED}❌ main.js not found in project or vim-im-switch-plugin/ (build output)${NC}"
exit 1
fi
# 创建目标目录
echo -e "${YELLOW}📂 创建目标目录...${NC}"
echo -e "${YELLOW}📂 Creating target dir...${NC}"
mkdir -p "$TARGET_DIR"
# 复制文件
echo -e "${YELLOW}📋 复制插件文件...${NC}"
echo -e "${YELLOW}📋 Copying plugin files...${NC}"
# 复制必需的文件
cp -f main.js "$TARGET_DIR/"
cp -f manifest.json "$TARGET_DIR/"
cp -f styles.css "$TARGET_DIR/"
# If build outputs are in vim-im-switch-plugin, prefer that directory
SRC_PLUGIN_DIR="$SOURCE_DIR"
if [ -d "$SOURCE_DIR/vim-im-switch-plugin" ]; then
SRC_PLUGIN_DIR="$SOURCE_DIR/vim-im-switch-plugin"
else
# If build outputs are at project root, copy them into vim-im-switch-plugin for release
mkdir -p "$SOURCE_DIR/vim-im-switch-plugin"
for f in main.js manifest.json styles.css; do
if [ -f "$SOURCE_DIR/$f" ]; then
cp -f "$SOURCE_DIR/$f" "$SOURCE_DIR/vim-im-switch-plugin/"
echo -e "${GREEN}✔ Move $f -> $SOURCE_DIR/vim-im-switch-plugin/${NC}"
fi
done
SRC_PLUGIN_DIR="$SOURCE_DIR/vim-im-switch-plugin"
fi
echo -e "${GREEN}✅ 文件复制完成:${NC}"
echo -e " • main.js"
echo -e " • manifest.json"
echo -e " • styles.css"
echo -e "${YELLOW}🔍 Using source dir: $SRC_PLUGIN_DIR${NC}"
# 验证文件
echo -e "${YELLOW}🔍 验证复制的文件...${NC}"
ls -la "$TARGET_DIR"
for f in main.js manifest.json styles.css; do
if [ -f "$SRC_PLUGIN_DIR/$f" ]; then
cp -f "$SRC_PLUGIN_DIR/$f" "$TARGET_DIR/"
echo -e "${GREEN}✔ Copied $f -> $TARGET_DIR/${NC}"
else
echo -e "${YELLOW}⚠️ Not found: $SRC_PLUGIN_DIR/$f (skipped)${NC}"
fi
done
echo -e "${GREEN}🎉 部署完成!${NC}"
echo -e "${BLUE}📍 插件已部署到: $TARGET_DIR${NC}"
echo -e "${YELLOW}💡 请重启 Obsidian 或重新加载插件以使更改生效${NC}"
echo -e "${GREEN}✅ Obsidian plugin files copied (if available)${NC}"
# Ensure repo-level release directory (vim-im-switch-plugin) contains the built files
RELEASE_DIR="$SOURCE_DIR/vim-im-switch-plugin"
mkdir -p "$RELEASE_DIR"
echo -e "${YELLOW}📦 Updating release dir: $RELEASE_DIR${NC}"
for f in main.js manifest.json styles.css; do
if [ -f "$SOURCE_DIR/$f" ]; then
cp -f "$SOURCE_DIR/$f" "$RELEASE_DIR/"
echo -e "${GREEN}✔ Copied $SOURCE_DIR/$f -> $RELEASE_DIR/${NC}"
else
if [ -f "$RELEASE_DIR/$f" ]; then
echo -e "${YELLOW} Using existing $RELEASE_DIR/$f${NC}"
else
echo -e "${RED}⚠️ Missing build output: $f (not found in project root or $RELEASE_DIR)${NC}"
fi
fi
done
echo -e "${YELLOW}📋 Copying plugin files to Obsidian plugin dir: $TARGET_DIR${NC}"
for f in main.js manifest.json styles.css; do
if [ -f "$RELEASE_DIR/$f" ]; then
cp -f "$RELEASE_DIR/$f" "$TARGET_DIR/"
echo -e "${GREEN}✔ Copied $RELEASE_DIR/$f -> $TARGET_DIR/${NC}"
else
echo -e "${YELLOW}⚠️ Not found in release dir: $RELEASE_DIR/$f (skipped)${NC}"
fi
done
echo -e "${GREEN}🎉 Deploy complete!${NC}"
echo -e " • Obsidian plugin -> $TARGET_DIR"
echo -e " • Release copy -> $RELEASE_DIR"
echo -e "${YELLOW}💡 Restart Obsidian or reload plugin to take effect.${NC}"

BIN
im-select Executable file

Binary file not shown.

119
main.js

File diff suppressed because one or more lines are too long

115
main.ts
View File

@@ -1,4 +1,4 @@
import { App, Modal, Notice, Plugin, PluginSettingTab, Setting, Workspace, MarkdownView, TFile, WorkspaceLeaf } from 'obsidian';
import { App, Plugin, PluginSettingTab, Setting, MarkdownView, TFile, WorkspaceLeaf } from 'obsidian';
import { exec } from "child_process";
import { promisify } from "util";
import * as CodeMirror from 'codemirror';
@@ -41,7 +41,7 @@ export default class VimIMSwitchPlugin extends Plugin {
private currentVimMode = 'normal'; // 跟踪当前vim模式
async onload() {
console.log('🚀 [VimIMSwitch] Loading plugin...');
console.log('🚀 Loading plugin...');
await this.loadSettings();
@@ -50,30 +50,6 @@ export default class VimIMSwitchPlugin extends Plugin {
this.addSettingTab(new IMSwitchSettingTab(this.app, this));
this.addCommand({
id: 'test-im-switch-to-english',
name: 'Test: Switch to English',
callback: () => {
this.deactivateIM();
}
});
this.addCommand({
id: 'test-im-switch-to-chinese',
name: 'Test: Switch to Chinese',
callback: () => {
this.activateIM();
}
});
this.addCommand({
id: 'test-check-im-status',
name: 'Test: Check IM Status',
callback: () => {
this.getFcitxRemoteStatus();
}
});
this.app.workspace.on('file-open', async (file: TFile) => {
if (!this.initialized) {
await this.initialize();
@@ -154,34 +130,6 @@ export default class VimIMSwitchPlugin extends Plugin {
}
}
setupVimModePolling() {
// 防止重复设置轮询
if ((this as any).vimModePollingInterval) {
clearInterval((this as any).vimModePollingInterval);
}
let lastMode = "";
const pollInterval = setInterval(() => {
if (!this.cmEditor) {
return;
}
try {
const realCM = (this.cmEditor as any).cm;
const currentMode = realCM?.state?.vim?.mode || "";
if (currentMode && currentMode !== lastMode) {
this.onVimModeChange({ mode: currentMode });
lastMode = currentMode;
}
} catch (error) {
// 忽略轮询错误
}
}, 100);
(this as any).vimModePollingInterval = pollInterval;
}
setupObsidianEditorEvents() {
if (this.keyboardListenerSetup) {
return;
@@ -196,24 +144,26 @@ export default class VimIMSwitchPlugin extends Plugin {
}
this.lastKeyTime = currentTime;
// 处理ESC键退出到normal模式
// 处理ESC键只在insert/replace模式下才切换输入法
if (event.key === 'Escape') {
// 退出insert模式前,先保存当前输入法状态
const beforeIM = await this.runCmd(this.fcitxRemotePath, ["-n"]);
const currentIMName = beforeIM.trim();
// 只有在insert或replace模式下按ESC才需要处理输入法
if (this.currentVimMode === 'insert' || this.currentVimMode === 'replace') {
// 退出insert模式前先保存当前输入法状态
const beforeIM = await this.runCmd(this.fcitxRemotePath, ["-n"]);
const currentIMName = beforeIM.trim();
// 检查当前输入法是中文还是英文
if (currentIMName === this.settings.chineseInputMethod) {
this.lastInsertModeIMStatus = IMStatus.Activate;
console.log('🔤 [VimIMSwitch] ESC → English (saved Chinese)');
console.log('ESC → English (saved Chinese)');
} else {
this.lastInsertModeIMStatus = IMStatus.Deactivate;
console.log('🔤 [VimIMSwitch] ESC → English (saved English)');
console.log('ESC → English (saved English)');
} // 切换到英文输入法
this.currentVimMode = 'normal';
await this.deactivateIM();
}
// 切换到英文输入法
this.currentVimMode = 'normal';
await this.deactivateIM();
// 如果已经在normal模式ESC键不做任何输入法切换
}
// 处理进入insert模式的按键只在normal模式下
else if (this.currentVimMode === 'normal' &&
@@ -224,10 +174,10 @@ export default class VimIMSwitchPlugin extends Plugin {
this.currentVimMode = 'insert';
// 恢复上次的输入法状态
if (this.lastInsertModeIMStatus == IMStatus.Activate) {
console.log("🈳 [VimIMSwitch] → Chinese");
console.log("→ Chinese");
await this.activateIM();
} else {
console.log("🔤 [VimIMSwitch] → English");
console.log("→ English");
await this.deactivateIM();
}
}, 10);
@@ -262,15 +212,15 @@ export default class VimIMSwitchPlugin extends Plugin {
if (this.imStatus == IMStatus.Activate) {
this.lastInsertModeIMStatus = IMStatus.Activate;
}
console.log("🔤 [VimIMSwitch] → English");
console.log("→ English");
await this.deactivateIM();
} else if (cm.mode == "insert" || cm.mode == "replace") {
// 进入insert模式时恢复上次的输入法状态
if (this.lastInsertModeIMStatus == IMStatus.Activate) {
console.log("🈳 [VimIMSwitch] → Chinese");
console.log("→ Chinese");
await this.activateIM();
} else {
console.log("🔤 [VimIMSwitch] → English");
console.log("→ English");
await this.deactivateIM();
}
}
@@ -283,7 +233,7 @@ export default class VimIMSwitchPlugin extends Plugin {
async getFcitxRemoteStatus() {
if (this.fcitxRemotePath == "") {
console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly.");
console.log("❌ Cannot get fcitx-remote path, please set it correctly.");
return;
}
@@ -299,31 +249,31 @@ export default class VimIMSwitchPlugin extends Plugin {
this.imStatus = IMStatus.None;
}
} catch (error) {
console.log(` [VimIMSwitch] Error getting IM status:`, error);
console.log(`❌ Error getting IM status:`, error);
}
}
async activateIM() {
if (this.fcitxRemotePath == "") {
console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly.");
console.log("❌ Cannot get fcitx-remote path, please set it correctly.");
return;
}
try {
await this.runCmd(this.fcitxRemotePath, ["-s", this.settings.chineseInputMethod]);
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.log("❌ [VimIMSwitch] Error activating IM:", error);
console.log("❌ Error activating IM:", error);
}
}
async deactivateIM() {
if (this.fcitxRemotePath == "") {
console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly.");
console.log("❌ Cannot get fcitx-remote path, please set it correctly.");
return;
}
try {
await this.runCmd(this.fcitxRemotePath, ["-s", this.settings.englishInputMethod]);
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.log("❌ [VimIMSwitch] Error deactivating IM:", error);
console.log("❌ Error deactivating IM:", error);
}
}
@@ -333,11 +283,6 @@ export default class VimIMSwitchPlugin extends Plugin {
this.cmEditor.off("vim-mode-change", this.onVimModeChange);
}
// 清理轮询定时器
if ((this as any).vimModePollingInterval) {
clearInterval((this as any).vimModePollingInterval);
}
// 清理键盘事件监听器
if ((this as any).obsidianKeyDownListener) {
document.removeEventListener('keydown', (this as any).obsidianKeyDownListener, { capture: true });
@@ -373,22 +318,22 @@ export default class VimIMSwitchPlugin extends Plugin {
}
async updateCurrentPath() {
console.log(`🖥️ [VimIMSwitch] Platform detected: ${process.platform}`);
console.log(`🖥️ Platform detected: ${process.platform}`);
switch (process.platform) {
case 'darwin':
this.fcitxRemotePath = this.settings.fcitxRemotePath_macOS;
console.log(`🍎 [VimIMSwitch] Using macOS path: ${this.fcitxRemotePath}`);
console.log(`🍎 Using macOS path: ${this.fcitxRemotePath}`);
break;
case 'linux':
this.fcitxRemotePath = this.settings.fcitxRemotePath_linux;
console.log(`🐧 [VimIMSwitch] Using Linux path: ${this.fcitxRemotePath}`);
console.log(`🐧 Using Linux path: ${this.fcitxRemotePath}`);
break;
case 'win32':
this.fcitxRemotePath = this.settings.fcitxRemotePath_windows;
console.log(`🪟 [VimIMSwitch] Using Windows path: ${this.fcitxRemotePath}`);
console.log(`🪟 Using Windows path: ${this.fcitxRemotePath}`);
break;
default:
console.log(` [VimIMSwitch] Platform ${process.platform} is not supported currently.`);
console.log(`❌ Platform ${process.platform} is not supported currently.`);
break;
}
}

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-vim-im-switch-plugin",
"name": "Vim Input Method Switch",
"version": "1.0.8",
"version": "2.0.3",
"minAppVersion": "0.9.12",
"description": "Switch input method with fcitx-remote when Vim keymap is enabled.",
"author": "Yuan Chen",

18
run-vim-test.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
# 在 Vim 中测试插件
echo "正在启动 Vim 测试 vim-im-switch-select.vim 插件..."
echo "说明:"
echo " 1. 按 i 进入 Insert 模式"
echo " 2. 切换到中文输入法并输入一些中文"
echo " 3. 按 ESC 退出到 Normal 模式(输入法应该切换到英文)"
echo " 4. 再按 i 进入 Insert 模式(输入法应该自动恢复到中文)"
echo " 5. 按 :q! 退出测试"
echo ""
echo "按 Enter 继续..."
read
# 使用绝对路径加载插件
vim -c "source /Users/gavin/vim-im-switch/vim-im-switch-select.vim" \
-c "echo '插件已加载,按 i 开始测试'" \
/Users/gavin/vim-im-switch/test-im-switch.txt

1
runit.sh Symbolic link
View File

@@ -0,0 +1 @@
/Users/gavin/tools/runit.sh

80
test-im-select.sh Executable file
View File

@@ -0,0 +1,80 @@
#!/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 ""

11
test-im-switch.txt Normal file
View File

@@ -0,0 +1,11 @@
测试输入法切换功能
Test IM Switch Functionality
使用说明:
1. 在 Vim 中加载此文件
2. 按 i 进入 Insert 模式
3. 输入中文内容
4. 按 ESC 退出到 Normal 模式(应该切换到英文输入法)
5. 再次按 i 进入 Insert 模式(应该恢复到中文输入法)
测试记录:

View File

@@ -1,4 +1,7 @@
{
"2.0.3": "0.9.12",
"2.0.2": "0.9.12",
"2.0.0": "0.9.12",
"1.0.2": "0.9.12",
"1.0.1": "0.9.12",
"1.0.0": "0.9.7"

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
{
"id": "obsidian-vim-im-switch-plugin",
"name": "Vim Input Method Switch",
"version": "2.0.3",
"minAppVersion": "0.9.12",
"description": "Switch input method with fcitx-remote when Vim keymap is enabled.",
"author": "Yuan Chen",
"authorUrl": "https://github.com/yuanotes",
"isDesktopOnly": true
}

View File

@@ -0,0 +1,2 @@
body {
}

145
vim-im-switch-select.vim Normal file
View File

@@ -0,0 +1,145 @@
" vim-im-switch-select.vim - 智能记忆输入法状态 (使用 im-select)
" Author: Gavin Chan
" Modified by: codefalling, enhanced with smart IM state memory
" Version: 2.0.0
" Description: 记住退出 Insert 模式时的输入法状态,下次进入时自动恢复
" 使用 im-select 而不是 fcitx-remote 切换输入法
" ---------------------------------------------------------------------
" Load Once:
if exists('g:imselect_loaded')
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("im-select")
finish
endif
let s:keepcpo = &cpo
let g:imselect_loaded = 1
set cpo&vim
" ---------------------------------------------------------------------
" 全局变量:记住上次 Insert 模式的输入法名称
let g:imselect_last_insert_im_name = ''
" 英文和中文输入法的 ID可以通过 im-select 获取)
if !exists('g:imselect_english_im')
let g:imselect_english_im = 'com.apple.keylayout.ABC'
endif
if !exists('g:imselect_chinese_im')
let g:imselect_chinese_im = 'auto-detect' " 将自动检测
endif
" ---------------------------------------------------------------------
" Functions:
" 离开 Insert 模式:保存当前输入法名称,然后切换到英文
function! IMSelect2en()
" 保存当前输入法名称
let current_im = substitute(system("im-select 2>/dev/null"), '\n', '', 'g')
let g:imselect_last_insert_im_name = current_im
" 切换到英文输入法(使用后台任务并重定向所有输出)
if has('job')
" Use nohup in a shell backgrounded process. Some Vim builds don't accept
" the 'detach' option; calling via sh -lc with nohup/& keeps process
" disassociated while avoiding unsupported job_start options.
call job_start(['sh', '-lc', 'nohup im-select ' . shellescape(g:imselect_english_im) . ' >/dev/null 2>&1 &'])
else
" Fallback: nohup in background
call system('nohup im-select ' . shellescape(g:imselect_english_im) . ' >/dev/null 2>&1 &')
endif
endfunction
" 进入 Insert 模式:根据保存的输入法名称恢复
function! IMSelect2zh()
" 如果上次保存的输入法名称为空,说明是第一次进入,保持英文
if g:imselect_last_insert_im_name == ''
return
endif
" 如果上次是英文输入法,保持英文(不需要做任何事)
if g:imselect_last_insert_im_name == g:imselect_english_im
return
endif
" 上次是中文输入法,恢复到那个输入法(使用后台任务并重定向所有输出)
if has('job')
call job_start(['sh', '-lc', 'nohup im-select ' . shellescape(g:imselect_last_insert_im_name) . ' >/dev/null 2>&1 &'])
else
call system('nohup im-select ' . shellescape(g:imselect_last_insert_im_name) . ' >/dev/null 2>&1 &')
endif
endfunction
" ---------------------------------------------------------------------
" Autocmds:
" 进入 Insert 模式一次后的处理
function! IMSelect2zhOnce()
call IMSelect2zh()
call UnBindIMSelectAu()
endfunction
function! BindIMSelectAu2zhOnce()
augroup IMSelect
au InsertEnter * call IMSelect2zhOnce()
augroup END
endfunction
" 绑定自动命令
function! BindIMSelectAu()
augroup IMSelect
" 离开 Insert 模式:保存输入法状态并切换到英文
au InsertLeave * call IMSelect2en()
" 进入 Insert 模式:恢复上次的输入法状态
au InsertEnter * call IMSelect2zh()
" Vim 启动时:切换到英文
au VimEnter * call IMSelect2en()
augroup END
endfunction
function! UnBindIMSelectAu()
au! IMSelect InsertLeave *
au! IMSelect InsertEnter *
endfunction
" 延迟初始化:首次进入 Insert 模式时才绑定自动命令
let g:imselect_called_bind = 0
function! IMSelectEchoBind()
if (g:imselect_called_bind==0)
call BindIMSelectAu()
endif
let g:imselect_called_bind = 1
endfunction
autocmd InsertEnter * call IMSelectEchoBind()
" 多光标支持:在选择多个光标前后的处理
function! IMSelect_multiple_cursors_before()
call UnBindIMSelectAu()
call BindIMSelectAu2zhOnce()
endfunction
function! IMSelect_multiple_cursors_after()
call IMSelect2en()
call BindIMSelectAu()
endfunction
" ---------------------------------------------------------------------
" Restoration And Modelines:
let &cpo=s:keepcpo
unlet s:keepcpo
let g:imselect_loaded = 1
" vim:fdm=expr:fde=getline(v\:lnum-1)=~'\\v"\\s*-{20,}'?'>1'\:1

144
vim-im-switch.vim Normal file
View File

@@ -0,0 +1,144 @@
" 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:
" 离开 Insert 模式:保存当前输入法名称,然后切换到英文
function! Fcitx2en()
" 保存当前输入法名称
let current_im = substitute(system("fcitx-remote -n 2>/dev/null"), '\n', '', 'g')
let g:fcitx_last_insert_im_name = current_im
" 切换到英文输入法(使用后台任务并重定向所有输出)
if has('job')
" Use nohup in a shell backgrounded process. Some Vim builds don't accept
" the 'detach' option; calling via sh -lc with nohup/& keeps process
" disassociated while avoiding unsupported job_start options.
call job_start(['sh', '-lc', 'nohup fcitx-remote -s ' . shellescape(g:fcitx_english_im) . ' >/dev/null 2>&1 &'])
else
" Fallback: nohup in background
call system('nohup fcitx-remote -s ' . shellescape(g:fcitx_english_im) . ' >/dev/null 2>&1 &')
endif
endfunction
" 进入 Insert 模式:根据保存的输入法名称恢复
function! Fcitx2zh()
" 如果上次保存的输入法名称为空,说明是第一次进入,保持英文
if g:fcitx_last_insert_im_name == ''
return
endif
" 如果上次是英文输入法,保持英文(不需要做任何事)
if g:fcitx_last_insert_im_name == g:fcitx_english_im
return
endif
" 上次是中文输入法,恢复到那个输入法(使用后台任务并重定向所有输出)
if has('job')
call job_start(['sh', '-lc', 'nohup fcitx-remote -s ' . shellescape(g:fcitx_last_insert_im_name) . ' >/dev/null 2>&1 &'])
else
call system('nohup fcitx-remote -s ' . shellescape(g:fcitx_last_insert_im_name) . ' >/dev/null 2>&1 &')
endif
endfunction
" ---------------------------------------------------------------------
" Autocmds:
" 进入 Insert 模式一次后的处理
function! Fcitx2zhOnce()
call Fcitx2zh()
call UnBindAu()
endfunction
function! BindAu2zhOnce()
augroup Fcitx
au InsertEnter * call Fcitx2zhOnce()
augroup END
endfunction
" 绑定自动命令
function! BindAu()
augroup Fcitx
" 离开 Insert 模式:保存输入法状态并切换到英文
au InsertLeave * call Fcitx2en()
" 进入 Insert 模式:恢复上次的输入法状态
au InsertEnter * call Fcitx2zh()
" Vim 启动时:切换到英文
au VimEnter * call Fcitx2en()
augroup END
endfunction
function! UnBindAu()
au! Fcitx InsertLeave *
au! Fcitx InsertEnter *
endfunction
" 延迟初始化:首次进入 Insert 模式时才绑定自动命令
let g:called_bind = 0
function! EchoBind()
if (g:called_bind==0)
call BindAu()
endif
let g:called_bind = 1
endfunction
autocmd InsertEnter * call EchoBind()
" 多光标支持:在选择多个光标前后的处理
function! Multiple_cursors_before()
call UnBindAu()
call BindAu2zhOnce()
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