Electric Pair 中文后引号补全问题

使用 Electric Pair 的话,输入中文双引号会自动补全另一个双引号,此时光标在两个双引号之间(“|”)。如果在这个引号对中间再输入一个中文双引号时,光标会从中间移动到第二个双引号的后面(“”|)。

但是如果在输入第二个中文双引号之前,用 C-f, C-b, C-e 等操作将光标移动到这对引号外面或直接 backspace 删除这对双引号的话,再次输入的中文双引号是后引号。

由于已经有了一个双引号自动补全的机制,输入后引号就显得没有必要。而我常常也会移动光标,再次输入引号是个后引号也不符合预期。

这个问题在中文单引号下也存在。

有啥方法能让在 Emacs 下输入的中文双引号没有后引号么?或者是配置输入法让它在 Emacs 这个程序下不输出中文后引号。或者是直接配置 Electric Pair 让它不补全中文引号。

Rime 下倒是有一种思路是人为配置中文引号的输入不再是交替输入,而是自己选择,不过是全局改动(以下内容没经过测试):

half_shape:
  '''' : [ '‘', '’' ]
  '"' : [ '“', '”' ]

想了下,貌似可以用 AutoHotkey 来解决在 Emacs 下输入的中文引号没有反引号。但是 AHK 没有 *nix 版本。

emacs-rime 是否能满足这个需求呢?

不补全参考这里:https://github.com/tshu-w/.emacs.d/blob/master/lisp/lang-org.el#L59

1 个赞

如果 “所有的事情都是靠 Rime 来完成的”,那输入是前引号还是后引号应该也是交给 Rime 来完成。

是的,按照你的那个配置,是可以切换前后引号的。

读了几遍才读顺楼主的帖子。

如果让我来描述,我会这样写:

步骤

  1. 切换到中文输入状态

  2. 按键:

    "
    <C-f>
    "
    

期望

“”“|”

实际

 “””|

这的确是个问题,对于系统内置输入法恐怕不太好解决,我想到一个剑走偏锋的方法:

;; 把弯引号左右对调重新添加到补全列表
(setq electric-pair-pairs
      `(,@electric-pair-pairs
        (?’ . ?‘)
        (?” . ?“)))

;; 修正左右对调的补全
(define-advice electric-pair--insert (:around (orig-fn c) fix-curved-quotes)
  (let* ((qpair (rassoc c electric-pair-pairs))
         (reverse-p (and qpair (> (car qpair) (cdr qpair)))))
    (if reverse-p
        (run-with-timer 0 nil
                        `(lambda ()
                          (backward-char 1)
                          (insert (char-to-string ,c))))
      (funcall orig-fn c))))
1 个赞

谢谢,试了这段代码没发现有区别,还报了个错。

我把上面这段放进 .custom.el 里测试了一下,启用 electric pair mode 后,切换到中文输入状态,然后按如下序列按键

  1. "“|”
  2. C-e“”|
  3. "“”|”) <- 这里也报了下面这个错
Error running timer: (void-variable c)

Backtrace 是

Debugger entered--Lisp error: (void-variable c)
  (char-to-string c)
  (insert (char-to-string c))
  (lambda nil (backward-char 1) (insert (char-to-string c)))()
  apply((lambda nil (backward-char 1) (insert (char-to-string c))) nil)
  timer-event-handler([t 24632 58154 919927 nil (lambda nil (backward-char 1) (insert (char-to-string c))) nil nil 0])

Emacs version: GNU Emacs 27.1 (build 1, x86_64-w64-mingw32) of 2020-08-22

OS: Win10

前面的代码改了一下,应该不会有 void-variable 的问题了。

把 backtick 加进去,还是有 void-variable 问题

Debugger entered--Lisp error: (void-variable c)
  (char-to-string c)
  (insert (char-to-string c))
  (lambda nil (backward-char 1) (insert (char-to-string c)))()
  apply((lambda nil (backward-char 1) (insert (char-to-string c))) nil)
  timer-event-handler([t 24632 59684 587219 nil (lambda nil (backward-char 1) (insert (char-to-string c))) nil nil 0])

你没保存文件吧?backquote 之后怎么提示还是一样的。把代码放到单独的文件试试:emacs -Q -l test-pair.el

;; 把弯引号左右对调重新添加到补全列表
(setq electric-pair-pairs
      `(,@electric-pair-pairs
        (?’ . ?‘)
        (?” . ?“)))

;; 修正左右对调的补全
(define-advice electric-pair--insert (:around (orig-fn c) fix-curved-quotes)
  (let* ((qpair (rassoc c electric-pair-pairs))
         (reverse-p (and qpair (> (car qpair) (cdr qpair)))))
    (if reverse-p
        (run-with-timer 0 nil
                        `(lambda ()
                           (backward-char 1)
                           (insert (char-to-string c))))
      (funcall orig-fn c))))

上面这个不行,下面这个可以

;; 把弯引号左右对调重新添加到补全列表
(setq electric-pair-pairs
      `(,@electric-pair-pairs
        (?’ . ?‘)
        (?” . ?“)))

;; 修正左右对调的补全
(define-advice electric-pair--insert (:around (orig-fn c) fix-curved-quotes)
  (let* ((qpair (rassoc c electric-pair-pairs))
         (reverse-p (and qpair (> (car qpair) (cdr qpair)))))
    (if reverse-p
        (run-with-timer 0 nil
                        `(lambda ()
                          (backward-char 1)
                          (insert (char-to-string ,c))))
      (funcall orig-fn c))))

这俩我看着一样啊

倒数第二行⚠️

跑去你修改的楼层看了下,看掉 , 了,加不加逗号有啥区别呢

加逗号提前求值,避免到运行时出现未定变量。

谢谢,看了下 https://www.gnu.org/software/emacs/manual/html_node/elisp/Backquote.html。

我理解的是逗号是引用变量,Backquote 和 quote 都是 quote a list, but selectively evaluate elements of that list,后面这个选择性 evaluate 我结合逗号能理解,但是 quote a list 不太理解。

看了下 https://www.gnu.org/software/emacs/manual/html_node/elisp/Quoting.html#Quoting ,里面说 “quote returns its single argument, as written, without evaluating it”,quote a list 应该就是把 list 原封不动的返回吧。

补充一个小知识:

中文输入法好输入 “”‘’,好奇英文是怎么输入的 :face_with_monocle:

在 wikipedia External links 找到了