(重新设计)中英文混打:OS输入法管理包 smart-input-source

@chinhant

'org-capture我加到默认值里了,
所以你自己的配置中可以删除了。

以后还有别的命令需要加入的话,
可以报给我。
如果足够通用,我会加到默认值里。

@goumao 如果只是想运行 prefix 命令(如 C-x、M-x 等)的时候,临时切换到英文,其它时候还是系统当前输入法, 可以支持么?

@opsnull

你开respect mode,别的不开。
不过 cusor color mode,我还是建议开的。

这样,C-x, M-x等的时候,自动切到英文。
返回的时候,
原来的buffer是什么输入法,就恢复到什么输入法。

这个包整的太复杂了,我试了第三次还是没搞懂怎么用。

我的用法: 一个快捷键切换local buffer的输入法状态,Emacs内置快捷键切换Buffer后,每个Buffer保持各自的输入法状态

完成这个需求要怎么设置?

自己绑定 smart-input-source-switch 这个command就可以了。

  1. smart-input-source-global-respect-mode
  2. smart-input-source-save-triggers 内置了一些命令。用这些命令切换,每个buffer各自的输入法都是可以记住的。
  3. 如果你有些操作下buffer的输入法没有保持,那么你可以开smart-input-source-hint-mode,重新操作一下,这个mode会提示你,哪些命令可能需要自己通过配置加到smart-input-source-save-triggers 里去。

@manateelazycat 猫哥,你可以参考下我的配置,因为我Emacs就是基本上用的你的emacs配置,我测试过Mac 正常使用,Linux应该没问题。

(when (eq system-type 'darwin)
  (setq smart-input-source-english "com.apple.keylayout.ABC")
  (setq-default smart-input-source-other "im.rime.inputmethod.Squirrel.Rime"))

;; enable the /respect/ mode
(add-to-list 'smart-input-source-prefix-override-keys "C-z")
(add-to-list 'smart-input-source-prefix-override-keys "s-x")
(add-to-list 'smart-input-source-preserve-save-triggers 'awesome-tab-backward-tab)
(add-to-list 'smart-input-source-preserve-save-triggers 'awesome-tab-forward-tab)
(add-to-list 'smart-input-source-preserve-save-triggers 'awesome-tab-backward-group)
(add-to-list 'smart-input-source-preserve-save-triggers 'awesome-tab-forward-group)

(smart-input-source-global-respect-mode t)

(add-to-list 'smart-input-source-preserve-save-triggers 'smex+)

;; enable the /follow context/ and /inline english/ mode for all buffers
;; (smart-input-source-global-follow-context-mode t)
;; (smart-input-source-global-inline-english-mode t)

;; Input source specific cursor color
(add-hook 'smart-input-source-set-english-hook
          (lambda ()
            (setq current-input-method nil)
            ))

(add-hook 'smart-input-source-set-other-hook
          (lambda ()
            (setq current-input-method "rime-smart")
            ))

我刚刚把 bury-buffer 和 unbury-buffer 加到 smart-input-source-save-triggers 里面并没有记住buffer的输入法状态。

而且我认为 smart-input-source-save-triggers 的这种实现方式太复杂了,提供一下我的思路:

  1. 每个Buffer默认都是英文输入状态
  2. smart-input-source-switch 命令的时候,给Buffer做一个local variable记住输入法的状态
  3. 只用在Buffer Switch的hook做监控(具体可以参考EAF Hook实现),如果Buffer切换的时候,根据 local variable 的状态调用输入法命令

按照第三步的设计,这样不论什么命令,只要切换了Buffer都会自动切换输入法状态,完全可以去掉 smart-input-source-save-triggers 这种设计了。

2 个赞

多谢回复。

开了 respect mode 后,系统的输入法自动被切换到 English,手动切换到 Other 或者 smart-input-source-switch 都会立即自动切换到 English。

我的场景是这样的:系统输入法是 sougou,emacs 编辑文件不会自动改变系统输入法,只是执行前缀命令时切换到 English,命令执行完后,恢复系统的输入法到切换前状态。

我当前的配置如下:

    (use-package smart-input-source
      :load-path "site-lisp"
      :init
      (setq smart-input-source-external-ism "/usr/local/bin/im-select")
      (setq smart-input-source-english "com.apple.keylayout.ABC")
      (setq-default smart-input-source-other "com.sogou.inputmethod.sogou.pinyin")
      (setq-default smart-input-source-inline-with-other t)
      (setq smart-input-source-fixed-context 'other)
      :config
      ;; enable the /cursor color/ mode
      (smart-input-source-global-cursor-color-mode t)
      ;; enable the /respect/ mode
      (smart-input-source-global-respect-mode t)
      ;; enable the /follow context/ mode for all buffers
      ;;(smart-input-source-global-follow-context-mode t)
      ;; enable the /inline english/ mode for all buffers
      ;;(smart-input-source-global-inline-mode t)
      )

这一行没有必要,当然加了也没有影响,只是不起作用
这一行是在启用inline-mode的情况下,
在英文上下文中激活 inline chinese region。

      (setq smart-input-source-fixed-context 'other)

这一行也没有必要,是follow-context-mode用的,
强制上下文输入法是other。
我一会把这个变量改个名,改成follow-context-fixed
这样更容易看出来是follow-context-mode用的

你现在的配置,期望中的行为就是:

emacs 编辑文件不会自动改变系统输入法,只是执行前缀命令时切换到 English,命令执行完后,恢复系统的输入法到切换前状态。

你这现在有什么问题么?

现象就是前面提到的,进入 emacs 后,系统输入法被自动切换到 English,如果手动选择 sougou、或者执行 smart-input-source-switch,还是会立即自动切换到 English。

我期望的行为是:进入 emacs 后,不自动修改系统输入法,在执行前缀命令前,保存当前系统输入法(不是当前 buffer 的输入法),执行完前缀命令后,恢复以前保存的系统输入法。

你更新一下最新版(一定要是git最新版)。

(setq smart-input-source-respect-start nil)

不会吧。。。
从english 状态 switch之后,就是中文了
并不会自动切到别的输入法。

可以把你的操作步骤一步步描述一下么?

我觉得你的场景很简单,下面的配置就行了。

    (use-package smart-input-source
      :load-path "site-lisp"
      :init
      (setq smart-input-source-external-ism "/usr/local/bin/im-select")
      (setq smart-input-source-english "com.apple.keylayout.ABC")
      (setq-default smart-input-source-other "com.sogou.inputmethod.sogou.pinyin")
      (setq smart-input-source-respect-start nil)
      :config
      (smart-input-source-global-cursor-color-mode t)
      (smart-input-source-global-respect-mode t)
      )

我更新过一次prefix相关的代码,应该和这块无关。
但是,因为那个冲突的原因我一直没找到
说不定这个更新也顺带解决了那个冲突的问题

你试一下?看看什么结果。

试了,依然是一样的问题。

那还是等大神 @manateelazycat 解决吧,
而且我手里没有linux GUI 环境,
没有办法调试。

懒猫, 你能不能指明加哪个hook,所有的buffer 切换都得调用 switch-to-buffer 吧,是不是加个advice更简单,

(advice-add 'switch-to-buffer :around 'smart-input-source-save)
1 个赞

估计还得加上 focus out 和 focus in hook.

@manateelazycat

哦哦哦,才注意到你的回复。

其实当前的实现和你的思路是一样的(hint-mode能够给出提示,当然是有章可循的):

  • 默认英文
  • local variable记录输入法状态
  • 在buffer switch的时候restore输入法。

区别就是何时保存输入法状态:没有自动保存输入法,而是用save-triggers主要是减小开销。因为外置输入法管理工具开销比较大,尽量少调用,而通过操作系统切换输入法时,输入法的变化就只能通过poll的方式才能感知。

后来的cursor-color-mode启用了idle timer更新输入法状态,然后设计了比较tricky的机制(开了两个不同机制的timer互相合作)来减少外置输入法的调用,个人感觉还行。但是,不确定是不是有些用户能感觉到系统开销,所以这个mode默认没有开启。

你这么一说,倒是提醒了我,可以启用自动保存输入法,完了看看大家的使用反馈。

另外,其实还有不少细微的地方要处理。比如Ctrl-x, b时,Ctrl-x之后,本package就要主动切换到英文,这样之后的b才能不被输入法拦截。但是恢复输入法的时候,恢复的是Ctrl-x之前的输入法。所以自动更新输入法的结果,有时候得不能直接用。

这两个都有了,
而且,不仅仅支持GUI,连TUI都支持。
cursor color啥的,也都支持TUI,
因为我自己主要是用TUI嘛。

winner-undo 得加到 trigger 里 :grin: