update at 2026-07-15 11:10:25
This commit is contained in:
378
README_en.md
378
README_en.md
@@ -1,241 +1,257 @@
|
||||
# Vim Input Method Switch Plugin
|
||||
|
||||
[](./CHANGELOG.md)
|
||||
|
||||
English | [中文](./README.md)
|
||||
|
||||
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
|
||||
This repository contains two related but currently separate implementations:
|
||||
|
||||
## Features
|
||||
- **Native Vim plugin**: `vim-im-switch-select.vim`, currently the stable macOS path.
|
||||
- **Obsidian plugin**: `main.ts`, unchanged by the recent Hammerspoon work.
|
||||
|
||||
- **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
|
||||
## Native Vim plugin
|
||||
|
||||
## Core Features
|
||||
The native Vim plugin is designed for macOS Vim and uses this stable strategy:
|
||||
|
||||
### 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
|
||||
- Normal mode always switches to English `ABC`.
|
||||
- Insert mode restores the last Chinese/English state used in the same Vim process.
|
||||
- Hammerspoon is preferred via `hs.keycodes.setLayout()` / `hs.keycodes.setMethod()`.
|
||||
- `im-select` is kept only as fallback.
|
||||
|
||||
### 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
|
||||
> Note: The Hammerspoon behavior described here applies only to the native Vim plugin `vim-im-switch-select.vim`. It does not change the Obsidian plugin.
|
||||
|
||||
### 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
|
||||
### Mode behavior
|
||||
|
||||
## Quick Start
|
||||
| Vim state | Behavior |
|
||||
|---|---|
|
||||
| After Vim starts | Delayed switch to English `ABC` |
|
||||
| Enter Insert | Restore the last Insert-mode Chinese/English state in this Vim process; first entry defaults to Chinese |
|
||||
| Leave Insert / `Esc` | Save the current Insert-mode language state, then switch to English `ABC` |
|
||||
|
||||
### Requirements
|
||||
Example:
|
||||
|
||||
```text
|
||||
First Insert -> Chinese
|
||||
Manually switch to English in Insert -> Esc -> next Insert -> English
|
||||
Manually switch back to Chinese in Insert -> Esc -> next Insert -> Chinese
|
||||
Quit Vim and open again -> memory resets; first Insert defaults to Chinese
|
||||
```
|
||||
|
||||
### Why Hammerspoon
|
||||
|
||||
Using only `im-select` can leave Apple Pinyin in an inconsistent macOS state:
|
||||
|
||||
```text
|
||||
sourceID = com.apple.inputmethod.SCIM.ITABC
|
||||
layout = ABC
|
||||
method = Pinyin – Simplified
|
||||
```
|
||||
|
||||
The menu bar may show Chinese input, but actual typing remains English.
|
||||
|
||||
Hammerspoon can directly set layout and method:
|
||||
|
||||
```lua
|
||||
hs.keycodes.setLayout("ABC")
|
||||
hs.keycodes.setMethod("Pinyin – Simplified")
|
||||
```
|
||||
|
||||
This avoids relying only on the input source ID.
|
||||
|
||||
### Hammerspoon setup
|
||||
|
||||
Install and run Hammerspoon. Enable IPC in `~/.hammerspoon/init.lua`:
|
||||
|
||||
```lua
|
||||
require("hs.ipc")
|
||||
hs.ipc.cliInstall()
|
||||
```
|
||||
|
||||
Reload Hammerspoon config, then verify:
|
||||
|
||||
#### macOS
|
||||
```bash
|
||||
brew install fcitx-remote-for-osx
|
||||
hs -c 'hs.keycodes.setLayout("ABC")'
|
||||
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
|
||||
```
|
||||
|
||||
#### Linux
|
||||
Both commands should return:
|
||||
|
||||
```text
|
||||
true
|
||||
```
|
||||
|
||||
### im-select fallback
|
||||
|
||||
If `hs` is unavailable, the Vim plugin falls back to `im-select`:
|
||||
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install fcitx
|
||||
|
||||
# Fedora
|
||||
sudo dnf install fcitx
|
||||
|
||||
# Arch Linux
|
||||
sudo pacman -S fcitx
|
||||
im-select
|
||||
im-select com.apple.keylayout.ABC
|
||||
im-select com.apple.inputmethod.SCIM.ITABC
|
||||
```
|
||||
|
||||
#### Windows
|
||||
Download [fcitx-remote.exe](https://github.com/yuanotes/obsidian-vim-im-switch-plugin/releases/download/1.0.3/fcitx-remote.exe) and place it in your system PATH
|
||||
Common input source IDs:
|
||||
|
||||
### Installation
|
||||
| Input method | ID |
|
||||
|---|---|
|
||||
| ABC | `com.apple.keylayout.ABC` |
|
||||
| Apple Simplified Pinyin | `com.apple.inputmethod.SCIM.ITABC` |
|
||||
|
||||
#### Obsidian Plugin Installation
|
||||
### Install native Vim plugin
|
||||
|
||||
1. Download plugin to Obsidian plugins directory:
|
||||
```bash
|
||||
cd /path/to/your/vault/.obsidian/plugins/
|
||||
git clone https://github.com/yourusername/vim-im-switch.git
|
||||
```
|
||||
Copy the plugin to Vim's plugin directory:
|
||||
|
||||
2. Enable plugin in Obsidian:
|
||||
- Open Settings → Community Plugins
|
||||
- Find "Vim Input Method Switch" and enable it
|
||||
|
||||
3. Configure input methods (optional):
|
||||
- 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
|
||||
mkdir -p ~/.vim/plugin
|
||||
cp vim-im-switch-select.vim ~/.vim/plugin/
|
||||
```
|
||||
|
||||
Note: v2.0.2 fixes a terminal-specific title/flash issue when using terminal Vim (see CHANGELOG for details).
|
||||
Or source it from `.vimrc`:
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage Scenarios
|
||||
|
||||
**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
|
||||
```vim
|
||||
source /path/to/vim-im-switch-select.vim
|
||||
```
|
||||
|
||||
**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
|
||||
### Native Vim configuration
|
||||
|
||||
Defaults are for macOS ABC + Apple Simplified Pinyin:
|
||||
|
||||
```vim
|
||||
" Hammerspoon path: English keyboard layout name
|
||||
let g:imselect_hs_english_layout = 'ABC'
|
||||
|
||||
" Hammerspoon path: Chinese input method name
|
||||
let g:imselect_hs_chinese_method = 'Pinyin – Simplified'
|
||||
|
||||
" im-select fallback: English input source ID
|
||||
let g:imselect_english_im = 'com.apple.keylayout.ABC'
|
||||
|
||||
" im-select fallback: Chinese input source ID
|
||||
let g:imselect_chinese_im = 'com.apple.inputmethod.SCIM.ITABC'
|
||||
|
||||
" Delay before restoring Insert state, default 80ms
|
||||
let g:imselect_restore_delay = 80
|
||||
|
||||
" Confirm target state after restore, default 200ms
|
||||
let g:imselect_confirm_delay = 200
|
||||
```
|
||||
|
||||
**Mixed Input**:
|
||||
```
|
||||
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
|
||||
### Native Vim implementation notes
|
||||
|
||||
```vim
|
||||
InsertLeavePre -> Save the last Insert-mode Chinese/English state
|
||||
InsertLeave -> Switch to English ABC
|
||||
InsertEnter -> Delayed restore of the last Insert-mode state
|
||||
VimEnter -> Delayed switch to English ABC on startup
|
||||
```
|
||||
|
||||
### Supported Vim Commands
|
||||
Important details:
|
||||
|
||||
- **Enter Insert mode**: `i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C`
|
||||
- **Exit Insert mode**: `ESC`, and other commands that trigger Normal mode
|
||||
- `InsertLeavePre` must save state before `InsertLeave` switches to English.
|
||||
- Timer callbacks check the target state so fast `i<Esc>` does not switch Normal mode back to Chinese.
|
||||
- Hammerspoon is the primary path; `im-select` is fallback only.
|
||||
- State memory is script-local and only valid within the current Vim process.
|
||||
|
||||
## How It Works
|
||||
### Native Vim manual test
|
||||
|
||||
```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]
|
||||
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
|
||||
```
|
||||
1. Open Vim:
|
||||
|
||||
### Technical Details
|
||||
|
||||
**Input Method Detection**
|
||||
- Uses `fcitx-remote -n` to get current input method name
|
||||
- Compares with configured Chinese/English input method names
|
||||
|
||||
**Event Handling**
|
||||
- **Keyboard events**: Uses `capture` mode to intercept keys early
|
||||
- **Debouncing**: Ignores repeated events within 100ms
|
||||
- **Async processing**: All input method switches are asynchronous and non-blocking
|
||||
|
||||
**State Management**
|
||||
- `currentVimMode`: Current Vim mode (normal/insert/visual)
|
||||
- `lastInsertModeIMStatus`: Last input method state in Insert mode
|
||||
- `imStatus`: Current input method state (Activate=Chinese, Deactivate=English)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Plugin not working
|
||||
1. Check if fcitx-remote is properly installed:
|
||||
```bash
|
||||
which fcitx-remote
|
||||
fcitx-remote -n
|
||||
vim test-im-switch.txt
|
||||
```
|
||||
|
||||
2. Check plugin logs (developer console):
|
||||
- Press `Cmd+Option+I` (macOS) or `Ctrl+Shift+I` (Windows/Linux) to open developer console
|
||||
- Look for logs starting with `[VimIMSwitch]`
|
||||
2. First `i`: should switch to Chinese.
|
||||
3. Type Chinese, press `Esc`: should switch to English `ABC`.
|
||||
4. Press `i` again: should restore Chinese.
|
||||
5. In Insert, manually switch to English, type English, press `Esc`.
|
||||
6. Press `i` again: should restore English.
|
||||
7. In Insert, manually switch back to Chinese, press `Esc`, then `i`: should restore Chinese.
|
||||
8. Quit and reopen Vim: first Insert defaults to Chinese; this is a known limitation.
|
||||
|
||||
3. Verify input method names:
|
||||
```bash
|
||||
# After switching to Chinese input method
|
||||
fcitx-remote -n
|
||||
# Output should match the Chinese IM name in plugin settings
|
||||
```
|
||||
### Native Vim verification
|
||||
|
||||
### 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
|
||||
```bash
|
||||
vim -Nu NONE -n -es -S "/path/to/vim-im-switch-select.vim" -c 'qa'
|
||||
```
|
||||
|
||||
### Issue: ESC key requires multiple presses
|
||||
- This issue has been fixed in the latest version
|
||||
- If it still occurs, please update to the latest version
|
||||
```bash
|
||||
hs -c 'hs.keycodes.setLayout("ABC")'
|
||||
hs -c 'hs.keycodes.setMethod("Pinyin – Simplified")'
|
||||
```
|
||||
|
||||
## Development
|
||||
## Obsidian plugin
|
||||
|
||||
The Obsidian plugin remains in this repository and is implemented by `main.ts`.
|
||||
|
||||
Current Obsidian plugin behavior is unchanged:
|
||||
|
||||
- Uses `fcitx-remote` to query and switch input methods.
|
||||
- Listens to Obsidian / CodeMirror Vim mode changes.
|
||||
- Normal / Visual mode switches to English.
|
||||
- Insert / Replace mode restores the last Insert-mode state.
|
||||
- Settings still use the plugin settings page and the configured `fcitx-remote` paths / input method IDs.
|
||||
|
||||
### Obsidian requirements
|
||||
|
||||
The plugin expects a working `fcitx-remote` command for the current platform.
|
||||
|
||||
Default macOS path:
|
||||
|
||||
```text
|
||||
/usr/local/bin/fcitx-remote
|
||||
```
|
||||
|
||||
Default input methods:
|
||||
|
||||
```text
|
||||
English: com.apple.keylayout.ABC
|
||||
Chinese: auto-detect, fallback com.apple.inputmethod.SCIM.ITABC
|
||||
```
|
||||
|
||||
### Obsidian development
|
||||
|
||||
### Build
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Deploy
|
||||
Deploy both Obsidian and Vim plugins with one command:
|
||||
```bash
|
||||
./deploy.sh
|
||||
## Known limitations
|
||||
|
||||
### Native Vim Insert memory is not persisted across Vim processes
|
||||
|
||||
The native Vim plugin only remembers the last Insert-mode state within the current Vim process.
|
||||
|
||||
```text
|
||||
Switch to English in Insert -> Esc -> next Insert -> English
|
||||
Quit Vim -> reopen Vim -> first Insert defaults to Chinese
|
||||
```
|
||||
|
||||
### Debug
|
||||
This is intentional for now; no file-based persistence is implemented.
|
||||
|
||||
#### 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
|
||||
### Native Vim depends on Hammerspoon for the stable macOS path
|
||||
|
||||
#### Vim Plugin
|
||||
View messages in Vim:
|
||||
```vim
|
||||
:messages
|
||||
```
|
||||
- `→ Chinese` - Switch to Chinese
|
||||
- `Error...` - Error messages
|
||||
The stable path requires:
|
||||
|
||||
### Changelog
|
||||
- Hammerspoon running
|
||||
- `hs` CLI available
|
||||
- `hs.ipc` enabled
|
||||
- Input method name matching `Pinyin – Simplified`
|
||||
|
||||
See [CHANGELOG_en.md](./CHANGELOG_en.md) for detailed version history.
|
||||
If Hammerspoon is unavailable, the plugin falls back to `im-select`, but fallback cannot fully fix Apple Pinyin layout/method inconsistency.
|
||||
|
||||
### No simulated CapsLock / Ctrl-Space
|
||||
|
||||
The native Vim plugin does not simulate `Caps Lock`, `Ctrl-Space`, `Shift`, or other system shortcuts. Those keys may be received by Vim and cause side effects.
|
||||
|
||||
## Main files
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| `vim-im-switch-select.vim` | Current stable native Vim plugin |
|
||||
| `main.ts` | Obsidian plugin entry |
|
||||
| `README.md` | Chinese documentation |
|
||||
| `README_en.md` | English documentation |
|
||||
| `CHANGELOG.md` / `CHANGELOG_en.md` | Change history |
|
||||
| `RELEASE.md` | Release notes |
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
## Links
|
||||
|
||||
- [Changelog](./CHANGELOG_en.md)
|
||||
- [中文文档](./README.md)
|
||||
- [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx)
|
||||
|
||||
Reference in New Issue
Block a user