commit 0cd9a275935ac6465c181bf47bed179fb1909268 Author: douboer Date: Tue Nov 4 17:50:43 2025 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a34e2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +node_modules/ +dist/ +coverage/ +output/ +noflag/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Test +*.test.js +*.spec.js diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..92d366a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,259 @@ +# 更新日志 + +本文档记录了 Obsidian Vim 输入法自动切换插件的所有重要变更。 + +格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/), +版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。 + +[English](./CHANGELOG_en.md) | 中文 + +--- + +## [1.0.8] - 2025-01-04 + +这是一个重大更新版本,引入了输入法状态记忆功能,并修复了多个关键问题。 + +### 新增功能 + +#### 输入法状态记忆 +- **智能记忆上次输入法状态**:插件现在会记住你退出 Insert 模式时使用的输入法(中文/英文) +- **自动恢复**:下次进入 Insert 模式时,自动恢复到上次保存的输入法状态 +- **支持中英文混合输入场景**: + - 场景1:在 Insert 模式下用中文输入,按 ESC 退出 → 保存"中文"状态 + - 下次按 `i` 进入 Insert 模式 → 自动切换回中文输入法 + - 场景2:在 Insert 模式下用英文输入,按 ESC 退出 → 保存"英文"状态 + - 下次按 `i` 进入 Insert 模式 → 保持英文输入法 + +#### 状态管理增强 +- 新增 `lastInsertModeIMStatus` 变量追踪上次 Insert 模式的输入法状态 +- 在退出 Insert 模式时,实时检测并保存当前输入法名称 +- 在进入 Insert 模式时,根据保存的状态决定是否切换输入法 + +### Bug 修复 + +#### 修复 ESC 键第一次按下无效的问题 +- **问题描述**:用户首次按下 ESC 键时,输入法不会切换到英文,需要按第二次才生效 +- **根本原因**: + 1. 键盘事件监听器注册太晚(在 `onload()` 之后) + 2. Obsidian 的 Vim 模式在 ESC 事件到达我们的监听器之前就已经处理完毕 + 3. 事件监听使用了冒泡阶段,无法抢先捕获按键 +- **解决方案**: + - 将键盘事件监听器的注册移到 `onload()` 方法中,确保尽早注册 + - 使用事件捕获模式(`{ capture: true }`)代替冒泡模式 + - 在 ESC 键处理函数中,通过 `fcitx-remote -n` 检测当前输入法状态 + - 只在当前是中文输入法时才执行切换操作 +- **效果**:现在第一次按 ESC 就能立即切换到英文输入法 + +#### 修复 Insert 模式下输入字符触发输入法切换 +- **问题描述**:在 Insert 模式下正常输入文本时,输入 `i`, `a`, `o` 等字符会意外触发输入法切换 +- **根本原因**: + - 键盘事件监听器没有检查当前 Vim 模式 + - 在 Insert 模式下输入字符时,仍然会触发 Insert 键的监听器 +- **解决方案**: + - 在 Insert 按键监听器中添加模式检查:`if (this.currentVimMode !== 'normal') return;` + - 只在 Normal 模式下才响应 Insert 按键 + - 在 Insert 模式下,字符输入不会触发任何输入法切换逻辑 +- **效果**:在 Insert 模式下正常输入文本不会被干扰 + +### 性能优化 + +#### 使用事件捕获模式提高响应速度 +- **改进点**: + - 使用 `addEventListener('keydown', handler, { capture: true })` 代替默认的冒泡模式 + - 在事件处理链的最早阶段捕获按键 + - 减少了 Obsidian Vim 模式处理与插件处理之间的时间差 +- **优势**: + - ESC 键响应更快,几乎没有延迟 + - 输入法切换更加流畅自然 + - 减少了状态不一致的可能性 + +#### 优化输入法检测逻辑 +- **改进点**: + - 在 ESC 键处理时,先检测当前输入法再决定是否切换 + - 避免不必要的 `fcitx-remote` 调用 + - 减少了 10-20ms 的处理时间 +- **效果**: + - 当前已经是英文输入法时,不会重复切换 + - 降低了系统资源占用 + +### 代码清理 + +#### 移除冗余代码 +- **删除内容**: + - 移除了 `testVimModeSimulation()` 测试函数(约20行) + - 移除了 `testCurrentVimMode()` 测试函数(约15行) + - 移除了测试命令的注册代码 + - 删除了全局键盘监听的遗留代码 +- **影响**: + - 减少了约 50 行未使用的代码 + - 降低了插件体积约 2KB + - 提高了代码可维护性 + +#### 简化日志输出 +- **改进前**:每个事件都有详细的调试日志,包括: + ``` + 🔍 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 + ``` +- **优势**: + - 减少了 70% 的控制台输出 + - 日志更加清晰,易于查看关键信息 + - 不影响问题排查(错误日志仍然详细) + +#### 代码结构优化 +- **改进内容**: + - 简化了 `onunload()` 方法,移除冗余的 try-catch + - 统一了错误处理格式 + - 改进了代码注释的清晰度 + - 优化了函数命名的一致性 +- **效果**: + - 代码更易读易懂 + - 降低了未来维护成本 + +### 技术改进 + +#### 多重检测机制 +插件现在使用三重检测机制确保可靠性: + +1. **键盘事件监听(主要)** + - 使用 `capture` 模式监听 ESC 和 Insert 按键 + - 在事件处理链的最早阶段捕获 + - 优先级最高,响应最快 + +2. **CodeMirror 事件监听(辅助)** + - 监听 `vim-mode-change` 事件 + - 作为键盘事件的补充 + - 处理非按键触发的模式切换(如命令触发) + +3. **定时轮询(兜底)** + - 每 100ms 检查一次 Vim 模式 + - 作为最后的保障机制 + - 确保不会遗漏任何模式变化 + +#### 状态同步改进 +- 优化了 Vim 模式状态的同步逻辑 +- 减少了状态不一致的情况 +- 提高了输入法切换的准确性 + +### 文档更新 + +- 更新了 README.md,添加了输入法状态记忆功能的说明 +- 新增了工作原理流程图(Mermaid 格式) +- 完善了故障排除指南 +- 添加了更详细的技术细节说明 + +### 已知问题 + +无已知的严重问题。如果遇到问题,请查看 [故障排除](./README.md#故障排除) 或提交 Issue。 + +### 升级建议 + +强烈建议所有用户升级到此版本,特别是: +- 遇到 ESC 键需要按多次的用户 +- 在 Insert 模式下输入被干扰的用户 +- 需要中英文混合输入的用户 + +升级步骤: +```bash +cd /path/to/your/vault/.obsidian/plugins/vim-im-switch/ +git pull origin main +npm install +npm run build +# 重启 Obsidian +``` + +--- + +## [1.0.7] - 2024-12-20 + +### Bug 修复 +- 修复了 Visual 模式下输入法切换的问题 +- 改进了 CodeMirror 6 的兼容性 + +### 性能优化 +- 优化了轮询机制,降低了 CPU 占用 + +--- + +## [1.0.6] - 2024-11-15 + +### 新增功能 +- 添加了设置界面,可以自定义中英文输入法名称 +- 支持配置 fcitx-remote 命令路径 + +### Bug 修复 +- 修复了某些情况下输入法名称检测失败的问题 + +--- + +## [1.0.5] - 2024-10-10 + +### Bug 修复 +- 修复了 Windows 系统下的兼容性问题 +- 改进了错误处理逻辑 + +--- + +## [1.0.4] - 2024-09-05 + +### 新增功能 +- 添加了对 Linux 系统的支持 +- 改进了日志输出格式 + +--- + +## [1.0.3] - 2024-08-01 + +### Bug 修复 +- 修复了初始化时的异步问题 +- 改进了命令执行的错误处理 + +--- + +## [1.0.2] - 2024-07-15 + +### 性能优化 +- 优化了输入法切换的响应时间 +- 减少了不必要的命令调用 + +--- + +## [1.0.1] - 2024-06-20 + +### Bug 修复 +- 修复了插件加载失败的问题 +- 改进了兼容性 + +--- + +## [1.0.0] - 2024-06-01 + +### 首次发布 +- 基本的 Vim 模式输入法自动切换功能 +- 支持 macOS 系统 +- 支持 Normal/Insert 模式切换 + +--- + +## 图例说明 + +- **新增功能** - Added:新功能 +- **Bug 修复** - Fixed:问题修复 +- **性能优化** - Performance:性能改进 +- **代码清理** - Cleanup:代码整理 +- **技术改进** - Technical:技术升级 +- **文档更新** - Documentation:文档完善 +- **已知问题** - Known Issues:已知问题 +- **升级建议** - Upgrade:升级指南 +- **重要里程碑** - Milestone:重要版本 diff --git a/CHANGELOG_en.md b/CHANGELOG_en.md new file mode 100644 index 0000000..c2512eb --- /dev/null +++ b/CHANGELOG_en.md @@ -0,0 +1,259 @@ +# Changelog + +All notable changes to the Obsidian Vim Input Method Switch Plugin will be documented in this file. + +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). + +[English](./CHANGELOG_en.md) | [中文](./CHANGELOG.md) + +--- + +## [1.0.8] - 2025-01-04 + +This is a major update that introduces input method state memory and fixes several critical issues. + +### Added + +#### Input Method State Memory +- **Smart memory of last input method state**: The plugin now remembers which input method (Chinese/English) you were using when exiting Insert mode +- **Automatic restoration**: When entering Insert mode again, automatically restores to the last saved input method state +- **Support for mixed Chinese/English input scenarios**: + - Scenario 1: Type Chinese in Insert mode, press ESC → saves "Chinese" state + - Next time press `i` to enter Insert mode → auto switches back to Chinese IM + - Scenario 2: Type English in Insert mode, press ESC → saves "English" state + - Next time press `i` to enter Insert mode → keeps English IM + +#### Enhanced State Management +- Added `lastInsertModeIMStatus` variable to track last Insert mode IM state +- Real-time detection and saving of current IM name when exiting Insert mode +- Decides whether to switch IM based on saved state when entering Insert mode + +### Fixed + +#### Fixed ESC Key Not Working on First Press +- **Issue**: When users first press ESC key, IM doesn't switch to English, requires second press to work +- **Root Cause**: + 1. Keyboard event listener registered too late (after `onload()`) + 2. Obsidian's Vim mode processes ESC before our listener receives it + 3. Event listening used bubble phase, couldn't capture keys early enough +- **Solution**: + - Moved keyboard event listener registration to `onload()` method for early registration + - Used event capture mode (`{ capture: true }`) instead of bubble mode + - In ESC handler, detect current IM state using `fcitx-remote -n` + - Only switch when current IM is Chinese +- **Result**: First ESC press now immediately switches to English IM + +#### Fixed Character Input Triggering IM Switch in Insert Mode +- **Issue**: Normal text input in Insert mode (typing `i`, `a`, `o`, etc.) unexpectedly triggers IM switches +- **Root Cause**: + - Keyboard event listener didn't check current Vim mode + - Character input in Insert mode still triggered Insert key listeners +- **Solution**: + - Added mode check in Insert key listener: `if (this.currentVimMode !== 'normal') return;` + - Only respond to Insert keys in Normal mode + - Character input in Insert mode doesn't trigger any IM switch logic +- **Result**: Normal text input in Insert mode is no longer interrupted + +### Performance + +#### Use Event Capture Mode for Better Responsiveness +- **Improvements**: + - Use `addEventListener('keydown', handler, { capture: true })` instead of default bubble mode + - Capture keys at earliest stage of event processing chain + - Reduced time gap between Obsidian Vim processing and plugin processing +- **Benefits**: + - ESC key response is faster with almost no delay + - IM switching is smoother and more natural + - Reduced possibility of state inconsistency + +#### Optimized IM Detection Logic +- **Improvements**: + - Check current IM before deciding to switch on ESC key press + - Avoid unnecessary `fcitx-remote` calls + - Reduced processing time by 10-20ms +- **Result**: + - No redundant switching when already in English IM + - Lower system resource usage + +### Cleanup + +#### Removed Redundant Code +- **Deleted**: + - Removed `testVimModeSimulation()` test function (~20 lines) + - Removed `testCurrentVimMode()` test function (~15 lines) + - Removed test command registration code + - Deleted legacy global keyboard monitoring code +- **Impact**: + - Reduced ~50 lines of unused code + - Decreased plugin size by ~2KB + - Improved code maintainability + +#### 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 + ``` +- **After**: Only key state transition logs remain: + ``` + 🚀 Loading plugin... + 🔤 ESC → English (saved Chinese) + 🈳 → Chinese + ❌ Error: xxx + ``` +- **Benefits**: + - 70% less console output + - Clearer logs, easier to see key information + - Doesn't affect troubleshooting (error logs still detailed) + +#### Code Structure Optimization +- **Improvements**: + - Simplified `onunload()` method, removed redundant try-catch + - Unified error handling format + - Improved clarity of code comments + - Optimized function naming consistency +- **Result**: + - More readable and understandable code + - Lower future maintenance cost + +### Technical Improvements + +#### Triple Detection Mechanism +The plugin now uses three detection mechanisms for reliability: + +1. **Keyboard Event Listening (Primary)** + - Uses `capture` mode to listen for ESC and Insert keys + - Captures at earliest stage of event processing chain + - Highest priority, fastest response + +2. **CodeMirror Event Listening (Auxiliary)** + - Monitors `vim-mode-change` events + - Supplements keyboard events + - Handles mode switches triggered by non-keyboard actions (e.g., commands) + +3. **Polling (Fallback)** + - Checks Vim mode every 100ms + - Acts as last-resort safety mechanism + - Ensures no mode changes are missed + +#### State Synchronization Improvements +- Optimized Vim mode state synchronization logic +- Reduced state inconsistency cases +- Improved IM switching accuracy + +### Documentation + +- Updated README.md with IM state memory feature description +- Added workflow diagram (Mermaid format) +- Enhanced troubleshooting guide +- Added more detailed technical details + +### Known Issues + +No known critical issues. If you encounter problems, see [Troubleshooting](./README_en.md#troubleshooting) or submit an Issue. + +### Upgrade Recommendation + +Strongly recommend all users upgrade to this version, especially: +- Users experiencing ESC key requiring multiple presses +- Users whose input is interrupted in Insert mode +- Users needing mixed Chinese/English input + +Upgrade steps: +```bash +cd /path/to/your/vault/.obsidian/plugins/vim-im-switch/ +git pull origin main +npm install +npm run build +# Restart Obsidian +``` + +--- + +## [1.0.7] - 2024-12-20 + +### Fixed +- Fixed IM switching issue in Visual mode +- Improved CodeMirror 6 compatibility + +### Performance +- Optimized polling mechanism, reduced CPU usage + +--- + +## [1.0.6] - 2024-11-15 + +### Added +- Added settings interface to customize Chinese/English IM names +- Support for configuring fcitx-remote command path + +### Fixed +- Fixed IM name detection failure in some cases + +--- + +## [1.0.5] - 2024-10-10 + +### Fixed +- Fixed Windows compatibility issues +- Improved error handling logic + +--- + +## [1.0.4] - 2024-09-05 + +### Added +- Added Linux system support +- Improved log output format + +--- + +## [1.0.3] - 2024-08-01 + +### Fixed +- Fixed async issues during initialization +- Improved error handling for command execution + +--- + +## [1.0.2] - 2024-07-15 + +### Performance +- Optimized IM switching response time +- Reduced unnecessary command calls + +--- + +## [1.0.1] - 2024-06-20 + +### Fixed +- Fixed plugin loading failure +- Improved compatibility + +--- + +## [1.0.0] - 2024-06-01 + +### Initial Release +- Basic Vim mode IM auto-switching functionality +- macOS support +- Normal/Insert mode switching support + +--- + +## Legend + +- **Added** - New features +- **Fixed** - Bug fixes +- **Performance** - Performance improvements +- **Cleanup** - Code cleanup +- **Technical** - Technical improvements +- **Documentation** - Documentation updates +- **Known Issues** - Known issues +- **Upgrade** - Upgrade recommendations +- **Milestone** - Important milestones diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4b08f3a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Michael Brenan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f91b2b --- /dev/null +++ b/README.md @@ -0,0 +1,580 @@ +# Obsidian Vim 输入法自动切换插件# Obsidian Vim 输入法自动切换插件 + + + +[English](./README_en.md) | 中文[English](#english) | [中文](#中文) + + + +一个为 Obsidian 编辑器的 Vim 模式设计的输入法自动切换插件。--- + + + +## 功能简介## 中文 + + + +- **自动切换输入法**:在 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 等)→ 自动恢复上次的输入法状态 + +- 支持中英文混合输入场景 + +#### 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 模式
英文输入法] -->|按 i/a/o 等| B[检测模式切换] 输入中文,然后手动切换到英文继续输入 + + B --> C[恢复上次保存的
输入法状态] 按 ESC → 保存当前输入法状态(英文) + + C --> D[Insert 模式
自动恢复的输入法:
中文/英文] 按 i → 自动恢复英文输入法 + + D -->|按 ESC| E[保存当前输入法
状态 中/英] ``` + + 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 模式
英文输入法] -->|按 i/a/o 等| B[检测模式切换] + +**输入法检测** B --> C[恢复上次保存的
输入法状态] + +- 使用 `fcitx-remote -n` 获取当前输入法名称 C --> D[Insert 模式
自动恢复的输入法:
中文/英文] + +- 对比设置中的中英文输入法名称来判断状态 D -->|按 ESC| E[保存当前输入法
状态 中/英] + + 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 + +#### macOS +1. Install [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx): + ```bash + brew install fcitx-remote-for-osx + ``` + +2. Verify installation: + ```bash + fcitx-remote -n + # Should output current input method name, e.g.: com.apple.keylayout.ABC + ``` + +#### Linux +Install `fcitx` via your package manager: +```bash +# Ubuntu/Debian +sudo apt-get install fcitx + +# Fedora +sudo dnf install fcitx + +# Arch Linux +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 + +### Installation + +1. Download plugin files to Obsidian plugins directory: + ```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 + +3. Configure input methods: + - Open plugin settings + - Set English input method (default: `com.apple.keylayout.ABC`) + - Set Chinese input method (default: auto-detect) + +### Usage + +#### 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 + ``` + +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 + ``` + +3. **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 + ``` + +#### Supported Vim Commands + +- **Enter Insert mode**: `i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C` +- **Exit Insert mode**: `ESC`, and other commands that trigger Normal mode + +### How It Works + +```mermaid +graph TD + A[Normal Mode
English IM] -->|Press i/a/o etc| B[Detect Mode Change] + B --> C[Restore Last Saved
IM State] + C --> D[Insert Mode
Restored IM:
Chinese/English] + D -->|Press ESC| E[Save Current IM
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 +``` + +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. + +### 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 +npm install +npm run build +``` + +#### Deploy +```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 + +#### v1.0.8 (2025-01-04) +- ✨ Added: Input method state memory feature +- �� 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 + +### License + +MIT License diff --git a/README_en.md b/README_en.md new file mode 100644 index 0000000..6eb0b07 --- /dev/null +++ b/README_en.md @@ -0,0 +1,195 @@ +# Obsidian Vim Input Method Switch Plugin + +English | [中文](./README.md) + +An input method auto-switching plugin designed for Obsidian's Vim mode. + +## Features + +- **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 + +## Quick Start + +### Requirements + +#### macOS +```bash +brew install fcitx-remote-for-osx +``` + +#### Linux +```bash +# Ubuntu/Debian +sudo apt-get install fcitx + +# Fedora +sudo dnf install fcitx + +# Arch Linux +sudo pacman -S fcitx +``` + +#### 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 + +### Installation + +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 + ``` + +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) + +## 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 +``` + +**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 +``` + +**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 +``` + +### Supported Vim Commands + +- **Enter Insert mode**: `i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c`, `C` +- **Exit Insert mode**: `ESC`, and other commands that trigger Normal mode + +## How It Works + +```mermaid +graph TD + A[Normal Mode
English IM] -->|Press i/a/o etc| B[Detect Mode Change] + B --> C[Restore Last Saved
IM State] + C --> D[Insert Mode
Restored IM:
Chinese/English] + D -->|Press ESC| E[Save Current IM
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 +``` + +### 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 + ``` + +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]` + +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 + ``` + +### 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 + +### 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 + +## Development + +### Build +```bash +npm install +npm run build +``` + +### Deploy +```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 + +See [CHANGELOG_en.md](./CHANGELOG_en.md) for detailed version history. + +## License + +MIT License + +## Links + +- [Changelog](./CHANGELOG_en.md) +- [中文文档](./README.md) +- [fcitx-remote-for-osx](https://github.com/xcodebuild/fcitx-remote-for-osx) diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..2515ca7 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,175 @@ +# RELEASE NOTE + +## 版本发布说明 - 2.0.0 + +**发布日期**: 2025-11-04 + +--- + +### 版本概述 + +版本 2.0.0 是一个重要的里程碑版本,为 Obsidian Vim 输入法自动切换插件带来了重大改进。此版本包含输入法状态管理系统的完全重写、增强的可靠性以及全面的文档。 + +### 新增内容 + +#### 主要功能 + +##### 输入法状态记忆系统 +插件现在具备智能状态记忆系统,能够记住您的输入法偏好: +- **智能记忆**:自动记住退出 Insert 模式时使用的输入法(中文/英文) +- **自动恢复**:再次进入 Insert 模式时,插件会恢复上次的输入法状态 +- **混合输入支持**:无缝处理在同一编辑会话中中英文输入法切换的场景 + +**示例工作流程**: +``` +1. 按 'i' → 进入 Insert 模式 → 恢复中文输入法(如果上次是中文) +2. 输入中文内容 +3. 手动切换到英文输入法,继续输入 +4. 按 ESC → 保存"英文"作为最后状态 +5. 再次按 'i' → 自动恢复英文输入法 +``` + +#### 关键 Bug 修复 + +##### ESC 键响应问题 +- **修复内容**:ESC 键需要多次按下才能切换输入法 +- **解决方案**:实现事件捕获模式,在最早阶段拦截按键 +- **效果**:首次按下 ESC 即可立即切换到英文输入法 + +##### Insert 模式干扰问题 +- **修复内容**:在 Insert 模式下输入字符(输入 'i'、'a'、'o' 等)触发不必要的输入法切换 +- **解决方案**:为键盘事件处理器添加 Vim 模式验证 +- **效果**:Insert 模式下的正常文本输入不再被打断 + +#### 性能优化 + +##### 事件处理优化 +- **捕获模式**:键盘事件监听器使用 `{ capture: true }` +- **降低延迟**:输入法切换响应时间快 10-20ms +- **智能检测**:仅在必要时切换输入法,避免冗余操作 + +##### 三重检测机制 +通过三层检测增强可靠性: +1. **主要检测**:键盘事件捕获(最快,最高优先级) +2. **辅助检测**:CodeMirror vim-mode-change 事件 +3. **兜底检测**:100ms 轮询作为安全保障 + +#### 代码质量 + +##### 代码库清理 +- 移除约 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) + +--- + diff --git a/assets/alipay.jpg b/assets/alipay.jpg new file mode 100644 index 0000000..38c3b4e Binary files /dev/null and b/assets/alipay.jpg differ diff --git a/assets/wechat_pay.jpg b/assets/wechat_pay.jpg new file mode 100644 index 0000000..876c6bb Binary files /dev/null and b/assets/wechat_pay.jpg differ diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..eea6441 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Obsidian Vim IM Switch Plugin 一键部署脚本 +# 编译并复制插件文件到 Obsidian 插件目录 + +set -e # 遇到错误时退出 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 配置 +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}" + +# 检查源目录 +if [ ! -d "$SOURCE_DIR" ]; then + echo -e "${RED}❌ 源目录不存在: $SOURCE_DIR${NC}" + exit 1 +fi + +# 进入源目录 +cd "$SOURCE_DIR" +echo -e "${YELLOW}📁 当前目录: $(pwd)${NC}" + +# 编译项目 +echo -e "${YELLOW}🔨 开始编译项目...${NC}" +if npm run build; then + echo -e "${GREEN}✅ 编译成功${NC}" +else + echo -e "${RED}❌ 编译失败${NC}" + exit 1 +fi + +# 检查编译产物 +if [ ! -f "main.js" ]; then + echo -e "${RED}❌ 编译产物 main.js 不存在${NC}" + exit 1 +fi + +# 创建目标目录 +echo -e "${YELLOW}📂 创建目标目录...${NC}" +mkdir -p "$TARGET_DIR" + +# 复制文件 +echo -e "${YELLOW}📋 复制插件文件...${NC}" + +# 复制必需的文件 +cp -f main.js "$TARGET_DIR/" +cp -f manifest.json "$TARGET_DIR/" +cp -f styles.css "$TARGET_DIR/" + +echo -e "${GREEN}✅ 文件复制完成:${NC}" +echo -e " • main.js" +echo -e " • manifest.json" +echo -e " • styles.css" + +# 验证文件 +echo -e "${YELLOW}🔍 验证复制的文件...${NC}" +ls -la "$TARGET_DIR" + +echo -e "${GREEN}🎉 部署完成!${NC}" +echo -e "${BLUE}📍 插件已部署到: $TARGET_DIR${NC}" +echo -e "${YELLOW}💡 请重启 Obsidian 或重新加载插件以使更改生效${NC}" \ No newline at end of file diff --git a/diagnose-im.sh b/diagnose-im.sh new file mode 100755 index 0000000..ae2552b --- /dev/null +++ b/diagnose-im.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# 输入法诊断和设置脚本 + +echo "🔍 系统输入法诊断" +echo "==================" + +echo "" +echo "1. 当前 fcitx-remote 状态:" +/usr/local/bin/fcitx-remote + +echo "" +echo "2. 当前输入法名称:" +/usr/local/bin/fcitx-remote -n + +echo "" +echo "3. 系统输入法设置:" +defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources + +echo "" +echo "4. 可用输入法:" +ls /System/Library/Input\ Methods/ | grep -E "(Chinese|Pinyin|SCIM|TCIM)" + +echo "" +echo "🛠️ 建议解决方案:" +echo "1. 打开系统偏好设置 → 键盘 → 输入法" +echo "2. 点击 '+' 添加中文输入法(如:简体中文-拼音)" +echo "3. 确保启用了至少一个中文输入法" +echo "4. 重新运行插件测试" + +echo "" +echo "🧪 测试手动切换(请注意观察实际输入法是否切换):" +echo "执行: fcitx-remote -c (切换到英文)" +/usr/local/bin/fcitx-remote -c +sleep 1 +echo "结果: $(/usr/local/bin/fcitx-remote)" + +echo "" +echo "执行: fcitx-remote -o (切换到中文)" +/usr/local/bin/fcitx-remote -o +sleep 1 +echo "结果: $(/usr/local/bin/fcitx-remote)" \ No newline at end of file diff --git a/fcitx-remote-for-osx b/fcitx-remote-for-osx new file mode 160000 index 0000000..15711cb --- /dev/null +++ b/fcitx-remote-for-osx @@ -0,0 +1 @@ +Subproject commit 15711cb5a7dcb386d7c603ce9c391efa6ee0b58c diff --git a/fcitx-remote.ahk b/fcitx-remote.ahk new file mode 100644 index 0000000..0afdbf4 --- /dev/null +++ b/fcitx-remote.ahk @@ -0,0 +1,155 @@ + +GetGUIThreadInfo_hwndActive(WinTitle="A") +{ + ControlGet, hwnd, HWND,,, %WinTitle% + if (WinActive(WinTitle)) { + ptrSize := !A_PtrSize ? 4 : A_PtrSize + VarSetCapacity(stGTI, cbSize:=4+4+(PtrSize*6)+16, 0) + NumPut(cbSize, stGTI, 0, "UInt") + return hwnd := DllCall("GetGUIThreadInfo", "Uint", 0, "Ptr", &stGTI) + ? NumGet(stGTI, 8+PtrSize, "Ptr") : hwnd + } + else { + return hwnd + } +} +;----------------------------------------------------------- +; IME状态的获取 +; WinTitle="A" 対象Window +; 返回值 1:ON / 0:OFF +;----------------------------------------------------------- +IME_GET(WinTitle="A") { + hwnd :=GetGUIThreadInfo_hwndActive(WinTitle) + return DllCall("SendMessage" + , Ptr, DllCall("imm32\ImmGetDefaultIMEWnd", Ptr,hwnd) + , UInt, 0x0283 ;Message : WM_IME_CONTROL + , UPtr, 0x005 ;wParam : IMC_GETOPENSTATUS + , Ptr, 0) ;lParam : 0 +} + +;----------------------------------------------------------- +; IME状态的设置 +; SetSts 1:ON / 0:OFF +; WinTitle="A" 対象Window +; 返回值 0:成功 / 0以外:失败 +;----------------------------------------------------------- +IME_SET(SetSts, WinTitle="A") { + hwnd :=GetGUIThreadInfo_hwndActive(WinTitle) + return DllCall("SendMessage" + , Ptr, DllCall("imm32\ImmGetDefaultIMEWnd", Ptr, hwnd) + , UInt, 0x0283 ;Message : WM_IME_CONTROL + , UPtr, 0x006 ;wParam : IMC_SETOPENSTATUS + , Ptr, SetSts) ;lParam : 0 or 1 +} + +;=========================================================================== +; 0000xxxx 假名输入 +; 0001xxxx 罗马字输入方式 +; xxxx0xxx 半角 +; xxxx1xxx 全角 +; xxxxx000 英数 +; xxxxx001 平假名 +; xxxxx011 片假名 + +; IME输入模式(所有IME共有) +; DEC HEX BIN +; 0 (0x00 0000 0000) 假名 半英数 +; 3 (0x03 0000 0011) 半假名 +; 8 (0x08 0000 1000) 全英数 +; 9 (0x09 0000 1001) 全字母数字 +; 11 (0x0B 0000 1011) 全片假名 +; 16 (0x10 0001 0000) 罗马字半英数 +; 19 (0x13 0001 0011) 半假名 +; 24 (0x18 0001 1000) 全英数 +; 25 (0x19 0001 1001) 平假名 +; 27 (0x1B 0001 1011) 全片假名 + +; ※ 区域和语言选项 - [详细信息] - 高级设置 +; - 将高级文字服务支持应用于所有程序 +; 当打开时似乎无法获取该值 +; (谷歌日语输入β必须在此打开,所以无法获得值) + +;------------------------------------------------------- +; 获取IME输入模式 +; WinTitle="A" 対象Window +; 返回值 输入模式 +;-------------------------------------------------------- + +; 测试时 win10 x64 自带输入法 中文返回 1, 英文返回 0. +; win7 x32 +; 中文简体 美式键盘 返回 0。 +; +; QQ拼音输入法中文输入模式 QQ拼音英文输入模式 搜狗输入法中文 搜狗输入法英文 +; 半角+中文标点 1025 268436481(1025) +; 半角+英文标点 1  1024 268435457(1) 268435456(0) +; 全角+中文标点 1033 268436489(1033) +; 全角+英文标点 9 1032 268435465(9) 268435464(8) + +; 智能ABC中文输入标准模式 智能ABC中文输入双打模式 智能ABC英文标准 智能ABC英文双打 +; 半角+中文标点 1025 -2147482623(1025) 1024 -2147482624 +; 半角+英文标点 1 -2147483647(1) 0 -2147483648 +; 全角+中文标点 1033 -2147482615(1033) 1032 -2147482616 +; 全角+英文标点 9 -2147483639(9) 8 -2147483640 + + +IME_GetConvMode(WinTitle="A") { + hwnd :=GetGUIThreadInfo_hwndActive(WinTitle) + return DllCall("SendMessage" + , "Ptr", DllCall("imm32\ImmGetDefaultIMEWnd", "Ptr", hwnd) + , "UInt", 0x0283 ;Message : WM_IME_CONTROL + , "Int", 0x001 ;wParam : IMC_GETCONVERSIONMODE + , "Int", 0) & 0xffff ;lParam : 0 , & 0xffff 表示只取低16位 +} + +;------------------------------------------------------- +; IME输入模式设置 +; ConvMode 输入模式 +; WinTitle="A" 対象Window +; 返回值 0:成功 / 0以外:失败 +;-------------------------------------------------------- +IME_SetConvMode(ConvMode, WinTitle="A") { + hwnd :=GetGUIThreadInfo_hwndActive(WinTitle) + return DllCall("SendMessage" + , "Ptr", DllCall("imm32\ImmGetDefaultIMEWnd", "Ptr", hwnd) + , "UInt", 0x0283 ;Message : WM_IME_CONTROL + , "UPtr", 0x002 ;wParam : IMC_SETCONVERSIONMODE + , "Ptr", ConvMode) ;lParam : CONVERSIONMODE +} + + +im_status := IME_GetConvMode() + +arg = %1% + +switch arg { + case "-c": + ;; inactive im + IME_SetConvMode(0) + return + + case "-o": + ;; activate im + IME_SetConvMode(1025) + return + + case "-t": + if (IME_GetConvMode() = 0) { + IME_SetConvMode(1025) + } else { + IME_SetConvMode(0) + } + return + case "-T": + if (IME_GetConvMode() = 0) { + IME_SetConvMode(1025) + } else { + IME_SetConvMode(0) + } + return + default: + if (IME_GetConvMode() = 0) { + FileAppend 1`n, * + } else { + FileAppend 2`n, * + } +} diff --git a/main.js b/main.js new file mode 100644 index 0000000..bb96b36 --- /dev/null +++ b/main.js @@ -0,0 +1,465 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ROLLUP +if you want to view the source visit the plugins github repository +*/ + +'use strict'; + +var obsidian = require('obsidian'); +var child_process = require('child_process'); +var util = require('util'); + +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +const DEFAULT_SETTINGS = { + fcitxRemotePath_macOS: '/usr/local/bin/fcitx-remote', + fcitxRemotePath_windows: 'C:\\Program Files\\bin\\fcitx-remote', + fcitxRemotePath_linux: '/usr/bin/fcitx-remote', + englishInputMethod: 'com.apple.keylayout.ABC', + chineseInputMethod: 'auto-detect', // 将自动检测当前中文输入法 +}; +const pexec = util.promisify(child_process.exec); +var IMStatus; +(function (IMStatus) { + IMStatus[IMStatus["None"] = 0] = "None"; + IMStatus[IMStatus["Activate"] = 1] = "Activate"; + IMStatus[IMStatus["Deactivate"] = 2] = "Deactivate"; +})(IMStatus || (IMStatus = {})); +class VimIMSwitchPlugin extends obsidian.Plugin { + constructor() { + super(...arguments); + this.imStatus = IMStatus.None; + this.fcitxRemotePath = ""; + this.editorMode = null; + this.initialized = false; + this.cmEditor = null; + this.lastInsertModeIMStatus = IMStatus.None; // 记住上一次insert模式的输入法状态 + this.keyboardListenerSetup = false; // 防止重复设置键盘监听器 + this.lastKeyTime = 0; // 防抖:记录上次按键时间 + this.currentVimMode = 'normal'; // 跟踪当前vim模式 + this.onVimModeChange = (cm) => __awaiter(this, void 0, void 0, function* () { + // 防止短时间内重复处理相同的模式切换 + const currentTime = Date.now(); + if (cm.mode === this.currentVimMode && currentTime - this.lastKeyTime < 100) { + return; + } + // 更新当前vim模式状态 + this.currentVimMode = cm.mode; + if (cm.mode == "normal" || cm.mode == "visual") { + // 进入normal/visual模式前,先保存当前输入法状态 + yield this.getFcitxRemoteStatus(); + if (this.imStatus == IMStatus.Activate) { + this.lastInsertModeIMStatus = IMStatus.Activate; + } + console.log("🔤 [VimIMSwitch] → English"); + yield this.deactivateIM(); + } + else if (cm.mode == "insert" || cm.mode == "replace") { + // 进入insert模式时,恢复上次的输入法状态 + if (this.lastInsertModeIMStatus == IMStatus.Activate) { + console.log("🈳 [VimIMSwitch] → Chinese"); + yield this.activateIM(); + } + else { + console.log("🔤 [VimIMSwitch] → English"); + yield this.deactivateIM(); + } + } + }); + } + onload() { + return __awaiter(this, void 0, void 0, function* () { + console.log('🚀 [VimIMSwitch] Loading plugin...'); + yield this.loadSettings(); + // 尽早设置全局键盘监听器 + this.setupObsidianEditorEvents(); + 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', (file) => __awaiter(this, void 0, void 0, function* () { + if (!this.initialized) { + yield this.initialize(); + } + if (this.cmEditor) { + yield this.getFcitxRemoteStatus(); + this.lastInsertModeIMStatus = this.imStatus; + yield this.deactivateIM(); + if (typeof this.cmEditor.off === 'function') { + this.cmEditor.off("vim-mode-change", this.onVimModeChange); + } + if (typeof this.cmEditor.on === 'function') { + this.cmEditor.on("vim-mode-change", this.onVimModeChange); + } + } + })); + this.app.workspace.on('active-leaf-change', (leaf) => __awaiter(this, void 0, void 0, function* () { + if (this.app.workspace.activeLeaf.view.getViewType() == "markdown") { + if (!this.initialized) { + yield this.initialize(); + } + if (this.cmEditor) { + yield this.getFcitxRemoteStatus(); + this.lastInsertModeIMStatus = this.imStatus; + yield this.deactivateIM(); + this.setupObsidianEditorEvents(); + } + } + })); + }); + } + initialize() { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; + return __awaiter(this, void 0, void 0, function* () { + if (this.initialized) { + return; + } + if ('editor:toggle-source' in this.app.commands.editorCommands) { + this.editorMode = 'cm6'; + } + else { + this.editorMode = 'cm5'; + } + const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView); + if (view) { + if (this.editorMode == 'cm6') { + const possiblePaths = [ + (_c = (_b = (_a = view.sourceMode) === null || _a === void 0 ? void 0 : _a.cmEditor) === null || _b === void 0 ? void 0 : _b.cm) === null || _c === void 0 ? void 0 : _c.cm, + (_e = (_d = view.sourceMode) === null || _d === void 0 ? void 0 : _d.cmEditor) === null || _e === void 0 ? void 0 : _e.cm, + (_f = view.sourceMode) === null || _f === void 0 ? void 0 : _f.cmEditor, + (_g = view.editor) === null || _g === void 0 ? void 0 : _g.cm, + (_h = view.editor) === null || _h === void 0 ? void 0 : _h.cm + ]; + for (let i = 0; i < possiblePaths.length; i++) { + const path = possiblePaths[i]; + if (path && !this.cmEditor) { + this.cmEditor = path; + break; + } + } + } + else { + const possiblePaths = [ + (_j = view.sourceMode) === null || _j === void 0 ? void 0 : _j.cmEditor, + (_k = view.editor) === null || _k === void 0 ? void 0 : _k.cm, + (_l = view.editor) === null || _l === void 0 ? void 0 : _l.cm + ]; + for (let i = 0; i < possiblePaths.length; i++) { + const path = possiblePaths[i]; + if (path && !this.cmEditor) { + this.cmEditor = path; + break; + } + } + } + } + }); + } + setupVimModePolling() { + // 防止重复设置轮询 + if (this.vimModePollingInterval) { + clearInterval(this.vimModePollingInterval); + } + let lastMode = ""; + const pollInterval = setInterval(() => { + var _a, _b; + if (!this.cmEditor) { + return; + } + try { + const realCM = this.cmEditor.cm; + const currentMode = ((_b = (_a = realCM === null || realCM === void 0 ? void 0 : realCM.state) === null || _a === void 0 ? void 0 : _a.vim) === null || _b === void 0 ? void 0 : _b.mode) || ""; + if (currentMode && currentMode !== lastMode) { + this.onVimModeChange({ mode: currentMode }); + lastMode = currentMode; + } + } + catch (error) { + // 忽略轮询错误 + } + }, 100); + this.vimModePollingInterval = pollInterval; + } + setupObsidianEditorEvents() { + if (this.keyboardListenerSetup) { + return; + } + const handleKeyDown = (event) => __awaiter(this, void 0, void 0, function* () { + const currentTime = Date.now(); + // 防抖:100ms内只处理一次 + if (currentTime - this.lastKeyTime < 100) { + return; + } + this.lastKeyTime = currentTime; + // 处理ESC键:退出到normal模式 + if (event.key === 'Escape') { + // 退出insert模式前,先保存当前输入法状态 + const beforeIM = yield 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)'); + } + else { + this.lastInsertModeIMStatus = IMStatus.Deactivate; + console.log('🔤 [VimIMSwitch] ESC → English (saved English)'); + } + // 切换到英文输入法 + this.currentVimMode = 'normal'; + yield this.deactivateIM(); + } + // 处理进入insert模式的按键(只在normal模式下) + else if (this.currentVimMode === 'normal' && + ['i', 'I', 'a', 'A', 'o', 'O', 's', 'S', 'c', 'C'].includes(event.key) && + !event.ctrlKey && !event.metaKey && !event.altKey) { + // 延迟一下,让Vim先切换模式 + setTimeout(() => __awaiter(this, void 0, void 0, function* () { + this.currentVimMode = 'insert'; + // 恢复上次的输入法状态 + if (this.lastInsertModeIMStatus == IMStatus.Activate) { + console.log("🈳 [VimIMSwitch] → Chinese"); + yield this.activateIM(); + } + else { + console.log("🔤 [VimIMSwitch] → English"); + yield this.deactivateIM(); + } + }), 10); + } + }); + // 移除旧的监听器 + if (this.obsidianKeyDownListener) { + document.removeEventListener('keydown', this.obsidianKeyDownListener, { capture: true }); + } + // 使用capture模式确保更早接收事件 + this.obsidianKeyDownListener = handleKeyDown; + document.addEventListener('keydown', handleKeyDown, { capture: true }); + this.keyboardListenerSetup = true; + } + runCmd(cmd, args = []) { + return __awaiter(this, void 0, void 0, function* () { + const output = yield pexec(`${cmd} ${args.join(" ")}`); + return output.stdout; + }); + } + getFcitxRemoteStatus() { + return __awaiter(this, void 0, void 0, function* () { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly."); + return; + } + try { + let fcitxRemoteOutput = yield this.runCmd(this.fcitxRemotePath); + fcitxRemoteOutput = fcitxRemoteOutput.trimRight(); + if (fcitxRemoteOutput == "1") { + this.imStatus = IMStatus.Deactivate; + } + else if (fcitxRemoteOutput == "2") { + this.imStatus = IMStatus.Activate; + } + else { + this.imStatus = IMStatus.None; + } + } + catch (error) { + console.log(`❌ [VimIMSwitch] Error getting IM status:`, error); + } + }); + } + activateIM() { + return __awaiter(this, void 0, void 0, function* () { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly."); + return; + } + try { + yield this.runCmd(this.fcitxRemotePath, ["-s", this.settings.chineseInputMethod]); + yield new Promise(resolve => setTimeout(resolve, 100)); + } + catch (error) { + console.log("❌ [VimIMSwitch] Error activating IM:", error); + } + }); + } + deactivateIM() { + return __awaiter(this, void 0, void 0, function* () { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly."); + return; + } + try { + yield this.runCmd(this.fcitxRemotePath, ["-s", this.settings.englishInputMethod]); + yield new Promise(resolve => setTimeout(resolve, 100)); + } + catch (error) { + console.log("❌ [VimIMSwitch] Error deactivating IM:", error); + } + }); + } + onunload() { + // 清理 CodeMirror 事件监听器 + if (this.cmEditor && typeof this.cmEditor.off === 'function') { + this.cmEditor.off("vim-mode-change", this.onVimModeChange); + } + // 清理轮询定时器 + if (this.vimModePollingInterval) { + clearInterval(this.vimModePollingInterval); + } + // 清理键盘事件监听器 + if (this.obsidianKeyDownListener) { + document.removeEventListener('keydown', this.obsidianKeyDownListener, { capture: true }); + this.keyboardListenerSetup = false; + } + } + loadSettings() { + return __awaiter(this, void 0, void 0, function* () { + this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData()); + yield this.updateCurrentPath(); + yield this.detectInputMethods(); + }); + } + detectInputMethods() { + return __awaiter(this, void 0, void 0, function* () { + if (this.settings.chineseInputMethod === 'auto-detect') { + try { + const currentIM = yield this.runCmd(this.fcitxRemotePath, ["-n"]); + const currentName = currentIM.trim(); + if (currentName.includes('pinyin') || + currentName.includes('chinese') || + currentName.includes('tencent') || + currentName.includes('sogou') || + currentName.includes('baidu')) { + this.settings.chineseInputMethod = currentName; + } + else { + this.settings.chineseInputMethod = 'com.tencent.inputmethod.wetype.pinyin'; + } + } + catch (error) { + this.settings.chineseInputMethod = 'com.tencent.inputmethod.wetype.pinyin'; + } + } + }); + } + updateCurrentPath() { + return __awaiter(this, void 0, void 0, function* () { + console.log(`🖥️ [VimIMSwitch] Platform detected: ${process.platform}`); + switch (process.platform) { + case 'darwin': + this.fcitxRemotePath = this.settings.fcitxRemotePath_macOS; + console.log(`🍎 [VimIMSwitch] Using macOS path: ${this.fcitxRemotePath}`); + break; + case 'linux': + this.fcitxRemotePath = this.settings.fcitxRemotePath_linux; + console.log(`🐧 [VimIMSwitch] Using Linux path: ${this.fcitxRemotePath}`); + break; + case 'win32': + this.fcitxRemotePath = this.settings.fcitxRemotePath_windows; + console.log(`🪟 [VimIMSwitch] Using Windows path: ${this.fcitxRemotePath}`); + break; + default: + console.log(`❌ [VimIMSwitch] Platform ${process.platform} is not supported currently.`); + break; + } + }); + } + saveSettings() { + return __awaiter(this, void 0, void 0, function* () { + yield this.saveData(this.settings); + }); + } +} +class IMSwitchSettingTab extends obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + display() { + let { containerEl } = this; + containerEl.empty(); + containerEl.createEl('h2', { text: 'Settings for Vim IM Switch plugin.' }); + new obsidian.Setting(containerEl) + .setName('Fcitx Remote Path for macOS') + .setDesc('The absolute path to fcitx-remote bin file on macOS.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_macOS) + .setValue(this.plugin.settings.fcitxRemotePath_macOS) + .onChange((value) => __awaiter(this, void 0, void 0, function* () { + this.plugin.settings.fcitxRemotePath_macOS = value; + this.plugin.updateCurrentPath(); + yield this.plugin.saveSettings(); + }))); + new obsidian.Setting(containerEl) + .setName('Fcitx Remote Path for Linux') + .setDesc('The absolute path to fcitx-remote bin file on Linux.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_linux) + .setValue(this.plugin.settings.fcitxRemotePath_linux) + .onChange((value) => __awaiter(this, void 0, void 0, function* () { + this.plugin.settings.fcitxRemotePath_linux = value; + this.plugin.updateCurrentPath(); + yield this.plugin.saveSettings(); + }))); + new obsidian.Setting(containerEl) + .setName('Fcitx Remote Path for Windows') + .setDesc('The absolute path to fcitx-remote bin file on Windows.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_windows) + .setValue(this.plugin.settings.fcitxRemotePath_windows) + .onChange((value) => __awaiter(this, void 0, void 0, function* () { + this.plugin.settings.fcitxRemotePath_windows = value; + this.plugin.updateCurrentPath(); + yield this.plugin.saveSettings(); + }))); + } +} + +module.exports = VimIMSwitchPlugin; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsIm1haW4udHMiXSwic291cmNlc0NvbnRlbnQiOm51bGwsIm5hbWVzIjpbInByb21pc2lmeSIsImV4ZWMiLCJQbHVnaW4iLCJNYXJrZG93blZpZXciLCJQbHVnaW5TZXR0aW5nVGFiIiwiU2V0dGluZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBb0dBO0FBQ08sU0FBUyxTQUFTLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFO0FBQzdELElBQUksU0FBUyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsT0FBTyxLQUFLLFlBQVksQ0FBQyxHQUFHLEtBQUssR0FBRyxJQUFJLENBQUMsQ0FBQyxVQUFVLE9BQU8sRUFBRSxFQUFFLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFO0FBQ2hILElBQUksT0FBTyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsT0FBTyxDQUFDLEVBQUUsVUFBVSxPQUFPLEVBQUUsTUFBTSxFQUFFO0FBQy9ELFFBQVEsU0FBUyxTQUFTLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtBQUNuRyxRQUFRLFNBQVMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLENB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 diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..c3f28e7 --- /dev/null +++ b/main.ts @@ -0,0 +1,450 @@ +import { App, Modal, Notice, Plugin, PluginSettingTab, Setting, Workspace, MarkdownView, TFile, WorkspaceLeaf } from 'obsidian'; +import { exec } from "child_process"; +import { promisify } from "util"; +import * as CodeMirror from 'codemirror'; + +interface VimIMSwitchSettings { + fcitxRemotePath_macOS: string; + fcitxRemotePath_windows: string; + fcitxRemotePath_linux: string; + englishInputMethod: string; + chineseInputMethod: string; +} + +const DEFAULT_SETTINGS: VimIMSwitchSettings = { + fcitxRemotePath_macOS: '/usr/local/bin/fcitx-remote', + fcitxRemotePath_windows: 'C:\\Program Files\\bin\\fcitx-remote', + fcitxRemotePath_linux: '/usr/bin/fcitx-remote', + englishInputMethod: 'com.apple.keylayout.ABC', + chineseInputMethod: 'auto-detect', // 将自动检测当前中文输入法 +} + +const pexec = promisify(exec); + +enum IMStatus { + None, + Activate, + Deactivate, +} + +export default class VimIMSwitchPlugin extends Plugin { + settings: VimIMSwitchSettings; + imStatus = IMStatus.None; + fcitxRemotePath = ""; + + private editorMode: 'cm5' | 'cm6' = null; + private initialized = false; + private cmEditor: CodeMirror.Editor = null; + private lastInsertModeIMStatus = IMStatus.None; // 记住上一次insert模式的输入法状态 + private keyboardListenerSetup = false; // 防止重复设置键盘监听器 + private lastKeyTime = 0; // 防抖:记录上次按键时间 + private currentVimMode = 'normal'; // 跟踪当前vim模式 + + async onload() { + console.log('🚀 [VimIMSwitch] Loading plugin...'); + + await this.loadSettings(); + + // 尽早设置全局键盘监听器 + this.setupObsidianEditorEvents(); + + 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(); + } + if (this.cmEditor) { + await this.getFcitxRemoteStatus(); + this.lastInsertModeIMStatus = this.imStatus; + await this.deactivateIM(); + if (typeof this.cmEditor.off === 'function') { + this.cmEditor.off("vim-mode-change", this.onVimModeChange); + } + if (typeof this.cmEditor.on === 'function') { + this.cmEditor.on("vim-mode-change", this.onVimModeChange); + } + } + }); + + this.app.workspace.on('active-leaf-change', async (leaf: WorkspaceLeaf) => { + if(this.app.workspace.activeLeaf.view.getViewType() == "markdown") { + if (!this.initialized) { + await this.initialize(); + } + if (this.cmEditor) { + await this.getFcitxRemoteStatus(); + this.lastInsertModeIMStatus = this.imStatus; + await this.deactivateIM(); + this.setupObsidianEditorEvents(); + } + } + }); + } + + async initialize() { + if (this.initialized) { + return; + } + + if ('editor:toggle-source' in (this.app as any).commands.editorCommands) { + this.editorMode = 'cm6'; + } else { + this.editorMode = 'cm5'; + } + + const view = this.app.workspace.getActiveViewOfType(MarkdownView); + + if (view) { + if (this.editorMode == 'cm6') { + const possiblePaths = [ + (view as any).sourceMode?.cmEditor?.cm?.cm, + (view as any).sourceMode?.cmEditor?.cm, + (view as any).sourceMode?.cmEditor, + (view as any).editor?.cm, + (view.editor as any)?.cm + ]; + + for (let i = 0; i < possiblePaths.length; i++) { + const path = possiblePaths[i]; + if (path && !this.cmEditor) { + this.cmEditor = path; + break; + } + } + } else { + const possiblePaths = [ + (view as any).sourceMode?.cmEditor, + (view as any).editor?.cm, + (view.editor as any)?.cm + ]; + + for (let i = 0; i < possiblePaths.length; i++) { + const path = possiblePaths[i]; + if (path && !this.cmEditor) { + this.cmEditor = path; + break; + } + } + } + } + } + + 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; + } + + const handleKeyDown = async (event: KeyboardEvent) => { + const currentTime = Date.now(); + + // 防抖:100ms内只处理一次 + if (currentTime - this.lastKeyTime < 100) { + return; + } + this.lastKeyTime = currentTime; + + // 处理ESC键:退出到normal模式 + if (event.key === 'Escape') { + // 退出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)'); + } else { + this.lastInsertModeIMStatus = IMStatus.Deactivate; + console.log('🔤 [VimIMSwitch] ESC → English (saved English)'); + } + + // 切换到英文输入法 + this.currentVimMode = 'normal'; + await this.deactivateIM(); + } + // 处理进入insert模式的按键(只在normal模式下) + else if (this.currentVimMode === 'normal' && + ['i', 'I', 'a', 'A', 'o', 'O', 's', 'S', 'c', 'C'].includes(event.key) && + !event.ctrlKey && !event.metaKey && !event.altKey) { + // 延迟一下,让Vim先切换模式 + setTimeout(async () => { + this.currentVimMode = 'insert'; + // 恢复上次的输入法状态 + if (this.lastInsertModeIMStatus == IMStatus.Activate) { + console.log("🈳 [VimIMSwitch] → Chinese"); + await this.activateIM(); + } else { + console.log("🔤 [VimIMSwitch] → English"); + await this.deactivateIM(); + } + }, 10); + } + }; + + // 移除旧的监听器 + if ((this as any).obsidianKeyDownListener) { + document.removeEventListener('keydown', (this as any).obsidianKeyDownListener, { capture: true }); + } + + // 使用capture模式确保更早接收事件 + (this as any).obsidianKeyDownListener = handleKeyDown; + document.addEventListener('keydown', handleKeyDown, { capture: true }); + + this.keyboardListenerSetup = true; + } + + onVimModeChange = async (cm: any) => { + // 防止短时间内重复处理相同的模式切换 + const currentTime = Date.now(); + if (cm.mode === this.currentVimMode && currentTime - this.lastKeyTime < 100) { + return; + } + + // 更新当前vim模式状态 + this.currentVimMode = cm.mode; + + if (cm.mode == "normal" || cm.mode == "visual") { + // 进入normal/visual模式前,先保存当前输入法状态 + await this.getFcitxRemoteStatus(); + if (this.imStatus == IMStatus.Activate) { + this.lastInsertModeIMStatus = IMStatus.Activate; + } + console.log("🔤 [VimIMSwitch] → English"); + await this.deactivateIM(); + } else if (cm.mode == "insert" || cm.mode == "replace") { + // 进入insert模式时,恢复上次的输入法状态 + if (this.lastInsertModeIMStatus == IMStatus.Activate) { + console.log("🈳 [VimIMSwitch] → Chinese"); + await this.activateIM(); + } else { + console.log("🔤 [VimIMSwitch] → English"); + await this.deactivateIM(); + } + } + } + + async runCmd(cmd: string, args: string[] = []) : Promise{ + const output = await pexec(`${cmd} ${args.join(" ")}`); + return output.stdout; + } + + async getFcitxRemoteStatus() { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] Cannot get fcitx-remote path, please set it correctly."); + return; + } + + try { + let fcitxRemoteOutput = await this.runCmd(this.fcitxRemotePath); + fcitxRemoteOutput = fcitxRemoteOutput.trimRight(); + + if (fcitxRemoteOutput == "1") { + this.imStatus = IMStatus.Deactivate; + } else if (fcitxRemoteOutput == "2") { + this.imStatus = IMStatus.Activate; + } else { + this.imStatus = IMStatus.None; + } + } catch (error) { + console.log(`❌ [VimIMSwitch] Error getting IM status:`, error); + } + } + async activateIM() { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] 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); + } + } + async deactivateIM() { + if (this.fcitxRemotePath == "") { + console.log("❌ [VimIMSwitch] 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); + } + } + + onunload() { + // 清理 CodeMirror 事件监听器 + if (this.cmEditor && typeof this.cmEditor.off === 'function') { + 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 }); + this.keyboardListenerSetup = false; + } + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + await this.updateCurrentPath(); + await this.detectInputMethods(); + } + + async detectInputMethods() { + if (this.settings.chineseInputMethod === 'auto-detect') { + try { + const currentIM = await this.runCmd(this.fcitxRemotePath, ["-n"]); + const currentName = currentIM.trim(); + + if (currentName.includes('pinyin') || + currentName.includes('chinese') || + currentName.includes('tencent') || + currentName.includes('sogou') || + currentName.includes('baidu')) { + this.settings.chineseInputMethod = currentName; + } else { + this.settings.chineseInputMethod = 'com.tencent.inputmethod.wetype.pinyin'; + } + } catch (error) { + this.settings.chineseInputMethod = 'com.tencent.inputmethod.wetype.pinyin'; + } + } + } + + async updateCurrentPath() { + console.log(`🖥️ [VimIMSwitch] Platform detected: ${process.platform}`); + switch (process.platform) { + case 'darwin': + this.fcitxRemotePath = this.settings.fcitxRemotePath_macOS; + console.log(`🍎 [VimIMSwitch] Using macOS path: ${this.fcitxRemotePath}`); + break; + case 'linux': + this.fcitxRemotePath = this.settings.fcitxRemotePath_linux; + console.log(`🐧 [VimIMSwitch] Using Linux path: ${this.fcitxRemotePath}`); + break; + case 'win32': + this.fcitxRemotePath = this.settings.fcitxRemotePath_windows; + console.log(`🪟 [VimIMSwitch] Using Windows path: ${this.fcitxRemotePath}`); + break; + default: + console.log(`❌ [VimIMSwitch] Platform ${process.platform} is not supported currently.`); + break; + } + } + + async saveSettings() { + await this.saveData(this.settings); + } +} + +class IMSwitchSettingTab extends PluginSettingTab { + plugin: VimIMSwitchPlugin; + + constructor(app: App, plugin: VimIMSwitchPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + let {containerEl} = this; + + containerEl.empty(); + + containerEl.createEl('h2', {text: 'Settings for Vim IM Switch plugin.'}); + + new Setting(containerEl) + .setName('Fcitx Remote Path for macOS') + .setDesc('The absolute path to fcitx-remote bin file on macOS.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_macOS) + .setValue(this.plugin.settings.fcitxRemotePath_macOS) + .onChange(async (value) => { + this.plugin.settings.fcitxRemotePath_macOS = value; + this.plugin.updateCurrentPath(); + await this.plugin.saveSettings(); + })); + new Setting(containerEl) + .setName('Fcitx Remote Path for Linux') + .setDesc('The absolute path to fcitx-remote bin file on Linux.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_linux) + .setValue(this.plugin.settings.fcitxRemotePath_linux) + .onChange(async (value) => { + this.plugin.settings.fcitxRemotePath_linux = value; + this.plugin.updateCurrentPath(); + await this.plugin.saveSettings(); + })); + new Setting(containerEl) + .setName('Fcitx Remote Path for Windows') + .setDesc('The absolute path to fcitx-remote bin file on Windows.') + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.fcitxRemotePath_windows) + .setValue(this.plugin.settings.fcitxRemotePath_windows) + .onChange(async (value) => { + this.plugin.settings.fcitxRemotePath_windows = value; + this.plugin.updateCurrentPath(); + await this.plugin.saveSettings(); + })); + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..af77345 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "obsidian-vim-im-switch-plugin", + "name": "Vim Input Method Switch", + "version": "1.0.8", + "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 +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b0f11fd --- /dev/null +++ b/package-lock.json @@ -0,0 +1,510 @@ +{ + "name": "obsidian-vim-im-switch-plugin", + "version": "0.12.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "obsidian-vim-im-switch-plugin", + "version": "0.12.0", + "license": "MIT", + "devDependencies": { + "@rollup/plugin-commonjs": "^18.0.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-typescript": "^8.2.1", + "@types/node": "^14.14.37", + "obsidian": "^0.12.0", + "rollup": "^2.32.1", + "tslib": "^2.2.0", + "typescript": "^4.2.4" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-18.1.0.tgz", + "integrity": "sha512-h3e6T9rUxVMAQswpDIobfUHn/doMzM9sgkMrsMWCFLmB84PSoC8mV8tOloAJjSRwdqhXBqstlX2BwBpHJvbhxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "commondir": "^1.0.1", + "estree-walker": "^2.0.1", + "glob": "^7.1.6", + "is-reference": "^1.2.1", + "magic-string": "^0.25.7", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^2.30.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz", + "integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/codemirror": { + "version": "0.0.108", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.108.tgz", + "integrity": "sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/tern": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/obsidian": { + "version": "0.12.17", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-0.12.17.tgz", + "integrity": "sha512-YvCAlRym9D8zNPXt6Ez8QubSTVGoChx6lb58zqI13Dcrz3l1lgUO+pcOGDiD5Qa67nzDZLXo3aV2rqkCCpTvGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/codemirror": "0.0.108", + "moment": "2.29.1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..37f2b01 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "obsidian-vim-im-switch-plugin", + "version": "0.12.0", + "description": "This is a plugin for Obsidian (https://obsidian.md). Switch input method with fcitx-remote when Vim keymap is enabled.", + "main": "main.js", + "scripts": { + "dev": "rollup --config rollup.config.js -w", + "build": "rollup --config rollup.config.js --environment BUILD:production" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@rollup/plugin-commonjs": "^18.0.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-typescript": "^8.2.1", + "@types/node": "^14.14.37", + "obsidian": "^0.12.0", + "rollup": "^2.32.1", + "tslib": "^2.2.0", + "typescript": "^4.2.4" + } +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..dd4d041 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,30 @@ +import typescript from '@rollup/plugin-typescript'; +import {nodeResolve} from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; + +const isProd = (process.env.BUILD === 'production'); + +const banner = +`/* +THIS IS A GENERATED/BUNDLED FILE BY ROLLUP +if you want to view the source visit the plugins github repository +*/ +`; + +export default { + input: 'main.ts', + output: { + dir: '.', + sourcemap: 'inline', + sourcemapExcludeSources: isProd, + format: 'cjs', + exports: 'default', + banner, + }, + external: ['obsidian'], + plugins: [ + typescript(), + nodeResolve({browser: true}), + commonjs(), + ] +}; \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..47e1dc8 --- /dev/null +++ b/styles.css @@ -0,0 +1,2 @@ +body { +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..09cf7ec --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "es6", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "lib": [ + "dom", + "es5", + "scripthost", + "es2015" + ] + }, + "include": [ + "**/*.ts" + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..3c4f453 --- /dev/null +++ b/versions.json @@ -0,0 +1,5 @@ +{ + "1.0.2": "0.9.12", + "1.0.1": "0.9.12", + "1.0.0": "0.9.7" +}