在web-mode中,<div>¦</div>
经过newline-and-indent
会变成
<div>
¦
</div>
而不是
<div>
¦</div>
我现在用rjsx-mode编辑react的jsx,希望能复刻这个行为。
不明白web-mode是怎么做的,同样是newline-and-indent
,别的mode不会这样,我看这个函数有个ad-Advice-newline-and-indent
的advice(spacemacs加的?),似乎跟我的问题无关。
一个简单的实现:
(defun web/newline-and-indent (&optional arg interactive)
(interactive "*P\np")
(when (and
(looking-back ">[\s\t]*" (point-at-bol))
(not (looking-back "/[^>]*>" (point-at-bol)))
(looking-at "[\s\t]*</"))
(newline arg interactive)
(forward-line -1)
(end-of-line))
(newline arg interactive))
光标在 tag 之间:
<!-- before -->
<tag>|</tag>
<!-- after -->
<tag>
|
</tag>
光标在 tag 之外:
<!-- before -->
<tag></tag>|<tag></tag>
<!-- after -->
<tag></tag>
|<tag></tag>
1 个赞
但是web-mode是用了什么黑魔法只用newline-and-indent
就做出了这个效果呢,好奇
也许就是那个 advice,你看一下。
或者绑定的不是 newline-and-indent
,这是 simple.el 的一个函数:
(defun newline-and-indent ()
(interactive "*")
(delete-horizontal-space t)
(newline nil t)
(indent-according-to-mode))
只插入了一个换行,除非 web-mode 对 newline / indent-according-to-mode 进行了扩展。
可以单步调试看看到底最后去了哪里,也可以添加一个 after advice,然后 (error “trap”) 把调用栈打出来。
还可能和smartparens有关。如果开了smartparens-mode不妨disable一下再试试
(defvar sp--html-modes '(
sgml-mode
html-mode
rhtml-mode
nxhtml-mode
nxml-mode
web-mode
jinja2-mode
html-erb-mode
js2-jsx-mode
rjsx-mode
)
"List of HTML modes.")
喔不过web-mode和rjsx-mode都在支持列表里 如果是sp干的应该都有影响才对
但是sp的:post-handler
是可以实现这个效果的
我用的doom-emacs 开了sp和yasnippet 没遇到你说的问题(spacemacs issue和sp被禁用)
doom里和sp有关的hack应该就这些
23 candidates:
./core/core-editor.el:180: ;; disable smartparens in evil-mode's replace state (they conflict)
./core/core-editor.el:181: (add-hook 'evil-replace-state-entry-hook #'turn-off-smartparens-mode)
./core/core-editor.el:182: (add-hook 'evil-replace-state-exit-hook #'turn-on-smartparens-mode)
./modules/lang/python/config.el:70: (define-key python-mode-map (kbd "DEL") nil) ; interferes with smartparens
./modules/lang/web/+html.el:15: (add-hook 'web-mode-hook #'turn-off-smartparens-mode)
./modules/feature/snippets/config.el:40: ;; fix an error caused by smartparens interfering with yasnippet bindings
./modules/lang/cc/config.el:102: ;; Completely disable electric keys because it interferes with smartparens and
./modules/lang/cc/config.el:108: ;; Smartparens and cc-mode both try to autoclose angle-brackets intelligently.
./modules/lang/cc/config.el:113: ;; ...and leave it to smartparens
和yasnippt相关的应该只有
;; fix an error caused by smartparens interfering with yasnippet bindings
(advice-add #'yas-expand :before #'sp-remove-active-pair-overlay)
但并不像你说的问题
这个效果跟 newline-and-indent
这个名字正好相符「换行并且缩进」。
C-h f newline-and-indent
:
Insert a newline, then indent according to major mode.
Indentation is done using the value of indent-line-function
或许是这个,每个 Buffer 都能自定义独立的 indent-line-function
。
设置了 post-command-hook
和开关 web-mode-enable-auto-opening
。
参见函数 web-mode-on-post-command
:
2 个赞
抄过来了:
但是不能用
;; like web-mode-on-post-command
(defun my/on-post-newline ()
"Insert an extra line if inside a tag."
(let (n)
(when (and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
(and (not (eobp))
(eq (char-after) ?\<)
(eq (get-text-property (point) 'tag-type) 'end)
(looking-back ">\n[ \t]*" (point-min))
(setq n (length (match-string-no-properties 0)))
(eq (get-text-property (- (point) n) 'tag-type) 'start)
(string= (get-text-property (- (point) n) 'tag-name)
(get-text-property (point) 'tag-name))
))
(newline-and-indent)
(forward-line -1)
(indent-according-to-mode)
)
))
不对只有web-mode才有tag-type
tag-name
这些text-property
结合 @twlz0ne 的答案和web-mode里的写法:
;; like web-mode-on-post-command
(defun jjpandari/on-post-newline ()
"Insert an extra line if inside a tag."
(let (n)
(when (and (member this-command '(newline electric-newline-and-maybe-indent newline-and-indent))
(and (looking-back ">\n[\s\t]*" (point-min))
(not (looking-back "/[^>]*>\n[\s\t]*" (point-min)))
(looking-at "[\s\t]*</")
))
(newline-and-indent)
(forward-line -1)
(indent-according-to-mode)
)
))
所以还是用我前面那个实现吧,刚刚更新了:
before after
|----------------------------------|---------------------------------
| <tag> | </tag> | <tag>
| | |
| | </tag>
|----------------------------------|---------------------------------
| <tag>|<tag></tag></tag> | <tag>
| | |<tag></tag></tag>
|----------------------------------|---------------------------------
| <tag><tag></tag>|</tag> | <tag><tag></tag>
| | |</tag>
|----------------------------------|---------------------------------
| <tag> | <tag>
| <tag>|</tag></tag> | <tag>
| | |
| | </tag></tag>
|----------------------------------|---------------------------------
| <tag | <tag
| class="foo"><tag>|</tag></tag> | class="foo"><tag>
| | |
| | </tag></tag>
|----------------------------------|---------------------------------
有点不一样,用这个post-command-hook
的话是在
<tag>
|</tag>
时执行的。
是把when
的条件部分抄过来就行了是吧(要不你把这个做法也更新上去)?我上面的更新了
另外(add-hook 'post-command-hook 'my/func nil t)
加在use-package
的:config
里面对么?(我刚想重启试试,启动报错了)不行,要把它放在rjsx-mode-hook
里
之前也在找相应的实现,后来发现emacs自带的 electric-pair-mode
就是最好实现方式。
打开这个mode,需要的功能基本就有了。
但是 electric-pair-mode
进行了一些按键绑定,用得不合适就自己修改下。
我就是吧 electric-pair-mode
绑定的 DEL
键删除了。