自带的 HTML+ 模式很酷,不知道用了什么 hack 支持 CSS、JS,不只是语法高亮,keymap 、甚至代码补全也支持。目前我遇到了一个问题,我开启了 electric-pair-mode 这个全局模式来输入括号,在 HTML+ 模式下输入 <
,会得到 <>
,这很对,因为这是 HTML 标签,但是光标移动到 JS 中还是这样就不对了,我已经有 N 次因为它把 for 循环写错,后面多出来的 >
就是 electric-pair-mode 插入的:
for (let i = 0; i < 10; i++>)
不知道如何避免。
awesome-pair会自动识别vue文件的html,css,js不同部分,智能决定什么时候补全括号。
1 个赞
之前不知道在哪看到的避免方式:
;; disable <> auto pairing in electric-pair-mode for org-mode
(add-hook 'org-mode-hook
'(lambda ()
(setq-local electric-pair-inhibit-predicate
`(lambda (c)
(if (char-equal c ?<) t
(,electric-pair-inhibit-predicate c))))))
我没找到 HTML+
,它在哪个文件?
找到了,正式名称是 mhtml-mode
。
用了一下发现,它有子模式的概念:
(defconst mhtml--js-submode
(mhtml--construct-submode 'js-mode
:name "JS"
:end-tag "</script>"
:syntax-table js-mode-syntax-table
:propertize #'js-syntax-propertize
:keymap js-mode-map))
进入 JS 区域自动切换成 js-mode
(可运行 M-: major-mode
观察)。这就好办了,把 <
加入 electric-pair 禁止列表即可:
(add-to-list 'electric-pair-inhibit-predicate-mode-chars-alist
'(js-mode . (?<)))
有这个变量吗?我这没有,搜索了下 Emacs 源代码也没发现。是不是你自己定制了 electric-pair-inhibit-predicate
?
哎呀,不好意思。是我自己定义的,很久没改这部分配置,都忘了,完整代码:
;;; pair.el --- Electric Pair -*- lexical-binding: t; -*-
(defvar electric-pair-inhibit-predicate-mode-chars-alist
'((t . nil))
"A list of major-mode and inhibit chars. For example,
(setq electric-pair-inhibit-predicate-mode-chars-alist
'((example-mode . (?<))
(t . nil)))
t means for all modes.")
(defun electric-pair-inhibit-predicate-function (c)
(let ((chars
(-concat
(assoc-default major-mode electric-pair-inhibit-predicate-mode-chars-alist)
(assoc-default t electric-pair-inhibit-predicate-mode-chars-alist))))
(or (member c chars)
(electric-pair-default-inhibit c))))
(with-eval-after-load 'elec-pair
(setq electric-pair-inhibit-predicate
#'electric-pair-inhibit-predicate-function))
;;; pair.el ends here
1 个赞
我也试着改了下 electric-pair-inhibit-predicate,只修复 MHTML 下 JS 的问题,简单试了下符合预期
(defun chunyang-mhtml-mode-electric-pair-inhibit-predicate (char)
(or (and (eq major-mode 'js-mode)
(= char ?<))
(electric-pair-default-inhibit char)))
(defun chunyang-mhtml-mode-setup ()
(setq-local electric-pair-inhibit-predicate
#'chunyang-mhtml-mode-electric-pair-inhibit-predicate))
(add-hook 'mhtml-mode-hook #'chunyang-mhtml-mode-setup)
electric-pair会不会自动补全是syntax table决定的吧,应该改syntax table。另外输入html一定要用emmet-mode的emmet-expand-line
/emmet-expand-yas
。
2 个赞
不懂 mhtml 的 submode 的实现,在单独的 js-mode 下是正常的,<
不会匹配。
被主模式“传染”的吧。
在 mhtml 模式下,文件任何地方执行 (electric-pair-syntax-info ?<)
都会得到:
(40 62 nil nil)
这条 syntax 在 sgml 模式中有定义(mhtml << html << sgml):
(defun sgml-make-syntax-table (specials)
(let ((table (make-syntax-table text-mode-syntax-table)))
(modify-syntax-entry ?< "(>" table)
;; ^^
...
))
在单独的 js 模式下 (electric-pair-syntax-info ?<)
返回 nil。
1 个赞
升级了一下,支持 3 种规则定义:
- 字符
?\{ ;; 禁止输入 { 时候补全
- 字符-字符串
(?\{ . ":{") ;; 禁止输入 :{ 时候补全,但不禁止其他情况下的 { 补全
- 字符-函数
(?\{ . (lambda (_c) ;; 函数可以做更多的事,以下实现的是 2. 的效果
(eq ?: (char-before (1- (point))))))
完整代码:
;;; pair.el --- Electric Pair -*- lexical-binding: t; -*-
(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))
;;; pair.el ends here
1 个赞
@twlz0ne 我用你的方法实现了 typescript-ts-mode
中的 <> 配对,多谢多谢。
写了一个简单的 wrap,自定义 rules 来同时实现 某个major-mode 的 pair 和 inhibit。
(require 'elec-pair-extra)
(add-hook 'after-init-hook #'elec-pair-extra-setup)
;; set rules for major-mode
(setq elec-pair-extra-rules
'(;; enable <> auto pair for generics usage in typescript, disable pair
;; when ?< following a space
(typescript-ts-mode :pair ((?\< . ?\>)) :inhibit ((?\< . " <")))
;; disable pair <> in HTML+JS submode in mhtml-mode
(mhtml-mode :pair nil :inhibit ((?\< . (lambda (c)
(and (eq major-mode 'js-mode)
(= c ?<))))))))
1 个赞