可以用 awesome-pair.el, awesome-pair.el 很容易针对这种情况做增强。
我研究了下,似乎没看到 single-quote 版本的命令?
我的意思是可以针对awesome-pair.el进行开发。
electric-pair 提供了修改方法,可自行扩展。
在《 自带 HTML+ 模式和 electric-pair-mode 在 JS 区域的一个问题 - #4,来自 twlz0ne 》里讨论过,用我回帖中的方法,添加一条规则即可:
(add-to-list 'electric-pair-inhibit-predicate-mode-chars-alist
'(rust-mode . ((?' . "&'"))))
smartparens里已经有了这些配置
(require 'smartparens-rust)
你的这个方案似乎不工作诶。
下面是我的完整代码:
(defvar electric-pair-inhibit-predicate-mode-chars-alist
'((t . nil))
"A list of major-mode and inhibit chars.
Each element is in the form of (MODE . (CHAR/CHAR-STRING/CHAR-FUNCTION ...)).
MODE
A mode, or t for all modes.
CHAR
A character to match the input. for example:
?\{
CHAR-STRING
A pair of character and string, the character to match the input,
the string for ‘looking-back’. for example:
(?\{ . \":{\")
CHAR-FUNCTION
A pair of character and function, the character to match the input,
the function accept the input character as parameter. for example:
(?\{ . (lambda (_c)
(eq ?: (char-before (1- (point))))))")
(defun electric-pair-inhibit-predicate-function (c)
(let ((alist
(append
(assoc-default major-mode electric-pair-inhibit-predicate-mode-chars-alist)
(assoc-default t electric-pair-inhibit-predicate-mode-chars-alist))))
(or (cl-member c
alist
:test
(lambda (c it)
(cond
((characterp it) (equal c it))
((and (consp it) (equal c (car it)))
(cond ((stringp (cdr it)) (looking-back (cdr it) 1))
((functionp (cdr it)) (funcall (cdr it) c)))))))
(electric-pair-default-inhibit c))))
(with-eval-after-load 'elec-pair
(setq electric-pair-inhibit-predicate
#'electric-pair-inhibit-predicate-function))
(add-hook 'rust-mode-hook
#'(lambda ()
(add-to-list (make-local-variable 'electric-pair-pairs) '(?' . ?'))
(add-to-list 'electric-pair-inhibit-predicate-mode-chars-alist
'(rust-mode . ((?' . "&'"))))
))
smartparens
这个包我一直没用过,很早的时候尝试过,记得当时因为某个小 bug, 然后放弃了。
如果没有其他解决方案,回头我再试试。
smartparens我觉得现在稳定多了, 以前我都只敢自己fork一份改着用, 现在已经可以直接melpa了.
初步判断存在以下问题:
- rust-mode.el 有设置自己的 inhibit 函数,抢走了执行权:
(setq-local electric-pair-inhibit-predicate 'rust-electric-pair-inhibit-predicate-wrap)
- 不应该设置
electric-pair-pairs
,它的优先级高于 inhibit 函数,等于是强制插入配对字符。应该采用modify-syntax-entry
来定义成对符号。
以 html-mode
为例:
(with-temp-buffer
(html-mode)
(electric-pair-syntax-info ?<))
;; => (40 62 nil nil)
;; | | |
;; | | '-- 为 nil 表示将执行 inhibit 函数。
;; | | 如果用 electric-pair-pairs 设置配对符号,
;; | | 则必返回 t,表示无需后续判断,强制插入配对符号。
;; | '------ 配对的右侧符号 ?>。
;; '-------- 40 说明当前插入的是成对符号的左侧。
试试以下配置:
(defun rust/electric-pair-inhibit-predicate (c)
(let ((al (assoc major-mode electric-pair-inhibit-predicate-mode-chars-alist)))
(if (assoc c (cdr al))
(electric-pair-inhibit-predicate-function c)
(rust-electric-pair-inhibit-predicate-wrap c))))
(with-eval-after-load 'rust-mode
(modify-syntax-entry ?' "\"" rust-mode-syntax-table)
(add-to-list 'electric-pair-inhibit-predicate-mode-chars-alist
'(rust-mode . ((?' . "&'"))))
(add-hook 'rust-mode-hook
(lambda ()
(setq-local electric-pair-inhibit-predicate
#'rust/electric-pair-inhibit-predicate))))
多谢,似乎将 (add-to-list (make-local-variable 'electric-pair-pairs) '(?' . ?'))
替换为 (modify-syntax-entry ?' "\"" rust-mode-syntax-table)
就工作了。
下面是完整的代码:
(defvar electric-pair-inhibit-predicate-mode-chars-alist
'((t . nil))
"A list of major-mode and inhibit chars.
Each element is in the form of (MODE . (CHAR/CHAR-STRING/CHAR-FUNCTION ...)).
MODE
A mode, or t for all modes.
CHAR
A character to match the input. for example:
?\{
CHAR-STRING
A pair of character and string, the character to match the input,
the string for ‘looking-back’. for example:
(?\{ . \":{\")
CHAR-FUNCTION
A pair of character and function, the character to match the input,
the function accept the input character as parameter. for example:
(?\{ . (lambda (_c)
(eq ?: (char-before (1- (point))))))")
(defun electric-pair-inhibit-predicate-function (c)
(let ((alist
(append
(assoc-default major-mode electric-pair-inhibit-predicate-mode-chars-alist)
(assoc-default t electric-pair-inhibit-predicate-mode-chars-alist))))
(or (cl-member c
alist
:test
(lambda (c it)
(cond
((characterp it) (equal c it))
((and (consp it) (equal c (car it)))
(cond ((stringp (cdr it)) (looking-back (cdr it) 1))
((functionp (cdr it)) (funcall (cdr it) c)))))))
(electric-pair-default-inhibit c))))
(with-eval-after-load 'elec-pair
(setq electric-pair-inhibit-predicate
#'electric-pair-inhibit-predicate-function))
(add-to-list 'electric-pair-inhibit-predicate-mode-chars-alist
'(rust-mode . ((?' . "&'"))))
(modify-syntax-entry ?' "\"" rust-mode-syntax-table)
下面的代码必须用 setq, 用 setq-local 无效。
(setq electric-pair-inhibit-predicate
#'electric-pair-inhibit-predicate-function)
1
(modify-syntax-entry ?' "\"" rust-mode-syntax-table)
在 rust-mode.el 文件加载的时候执行一次就好,没必要放在 rust-mode-hook 里打开每个文件都执行。
2
仅 electric-pair-inhibit-predicate-function
不够,rust-mode 自己的 inhibit 函数不能丢,否则 <
符号的处理不正常。
3
setq-local
要在 rust-mode-hook
才有效,因为 rust-mode
每次启用都重置了 electric-pair-inhibit-predicate
变量。
#12 楼的配置流程大致上应该没问题,至少我这边验证过了。
不懂这个不够是什么意思,<
处理不正常,有办法重现吗?
可以贴一个完整的方案吗? 如果可以的话,请在 [已解决] Emacs 27, rust-mode, 如何让单引号自动的 autopair, 但是,单引号前面如果是 & 则例外。 - #13,来自 zw963 上面修改。
例如,需要区分 i < j
和 <T>
。
它大致算一个完整方案了,直接拿去用没问题。判定规则上可能会有所遗漏,如果 electric-pair-inhibit-predicate-mode-chars-alist
有添加全局规则的话,需改为:
(defun rust/electric-pair-inhibit-predicate-fn (c)
- (let ((al (assoc major-mode electric-pair-inhibit-predicate-mode-chars-alist))
+ (let ((al (append
+ (assoc-default major-mode electric-pair-inhibit-predicate-mode-chars-alist)
+ (assoc-default t electric-pair-inhibit-predicate-mode-chars-alist)))
如果没有全局规则就不用改。
在 rust-mode 下面似乎并没有遇到这个问题。
它大致算一个完整方案了,直接拿去用没问题。判定规则上可能会有所遗漏,如果
electric-pair-inhibit-predicate-mode-chars-alist
有添加全局规则的话,需改为:
您错会了我的意思,我指的 完整方案
,是希望您把所有需要的代码全部贴出来(不用参考我贴的代码),我好采纳为答案,目前这样,每次回复时,写一部分代码我有点糊涂了。
好吧,我这个需求 smartparens 支持得很好了,不需要做额外配置。
确实,以前用的最老的配置,没加config那个。。。也是总感觉不太舒服
好吧,我这个需求 smartparens 支持得很好了,不需要做额外配置。
smartparens 解决了自己制造的问题:
1. electric-pair
$ emacsq.sh -P rust-mode -M electric-pair-mode --eval \
"(progn
(rust-mode)
(insert \"let str: &\")
(execute-kbd-macro (string-to-vector \"'\")) ;; 触发补全
(message (buffer-string)))" -nw --batch
let str: &'
2. electric-pair & smartparens
$ emacsq.sh -P rust-mode,smartparens -M electric-pair-mode,smartparens-global-strict-mode --eval \
"(progn
(rust-mode)
(insert \"let str: &\")
(execute-kbd-macro (string-to-vector \"'\")) ;; 触发补全
(message (buffer-string)))" -nw --batch
let str: &''
3. electric-pair & smartparens [+ rust]
$ emacsq.sh -P rust-mode,smartparens -M electric-pair-mode,smartparens-global-strict-mode --eval \
"(progn
(rust-mode)
(require 'smartparens-rust) ;; ++
(insert \"let str: &\")
(execute-kbd-macro (string-to-vector \"'\")) ;; 触发补全
(message (buffer-string)))" -nw --batch
let str: &'
我刚开始用的是 rustic, 因为 rustic 和 lsp-rust 是一个维护者,后来 … 遇到一些问题,我提了 issue, 讨论挺久的,一直没解决,就用了 rust-mode 了,其实有 lsp, 我感觉上用那个都一样的,rust-mode 更少 bug.
也许是我用的少,还没发现吧。
现在最新版的 rustic
依赖 rust-mode
,以前 rustic
是 fork 的 rust-mode
, 现在可以将 rustic 理解为 rust-mode 的扩展,和 lsp 集成更方便一些。我用的 eglot + flycheck