Electric Pair 中文后引号补全问题

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

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

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

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

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

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

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

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

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

不补全参考这里:.emacs.d/lang-org.el at master · tshu-w/.emacs.d · GitHub

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 不太理解。

看了下 Quoting (GNU Emacs Lisp Reference Manual) ,里面说 “quote returns its single argument, as written, without evaluating it”,quote a list 应该就是把 list 原封不动的返回吧。

补充一个小知识:

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

在 wikipedia External links 找到了

这个问题的根源是因为中文输入法会把第二次引号自动翻译成后引号吗? :face_with_raised_eyebrow: