我用过 lispy 这些, paredit可以针对大多数模式, 而不仅仅是 lisp, 而且 paredit 的做法更加直觉化一点.
大致试了一下,在lisp Ruby Python之外的C风格语言中,好像只有paredit-kill能比较好的工作(kill到当前expression的末尾),语法太复杂,怪不得需要vim/evil来按字符划分text object,按语法划分太多了,按不过来。
不过光一个paredit-kill也有帮助的。有个小问题,好像没有和paredit-kill反向,删除到expression开头的函数?这个需求也会有吧?奇怪
其实用的最多的就是 paredit-kill 了, 在 lisp 中,我经常用 paredit-close-round-and-newline+
lazycat-toolkit
里用了不认识的东西:
(file-missing "Cannot open load file" "No such file or directory" "mwe-log-commands")
require(mwe-log-commands)
eval-buffer(#<buffer *load*-822461> nil "/Users/***/.spacemacs.d/extensions/lazycat-toolkit.el" nil t) ; Reading at buffer position 2367
是有这个需求,似乎不怎么重视?How to do paredit-kill backwards? 的解决方案有点暴力,我用 syntax-ppss
也实现了一个,有些坑可能没有踩到。去除了对 paredit-mode
的依赖,比较晦涩,但愿一个月后还能看得懂。
-
save-excursion
应该可以去掉,但是不确定会产生什么副作用,所以还是保留了。 -
有些支持 b style comment 的 mode,工作得不太好(也不支持 nestable comment),可能是我不会设置吧。
代码:
(defun paredit-backward-kill (&optional argument)
"Backward version of `paredit-kill'.
With a `\\[universal-argument]' prefix argument, kill the text before point on
the current line.
With a positive integer prefix argument N, kill lines backward
many times.
With a `\\[universal-argument] \\[universal-argument]' prefix argument, kill all expressions before
the point in the current block, group, string or comment."
(interactive "P")
(unless (bobp)
(let ((pos (point))
(hungry-p (equal argument '(16))))
(cond ((and (bolp) (not argument))
(kill-region pos (1- pos)))
((and (integerp argument) (> argument 1))
(kill-line (- (1- argument))))
((and argument (not hungry-p))
(kill-line 0))
(t (let* ((bol (point-at-bol))
(cur-ppss (syntax-ppss))
(cur-up-pos (cadr cur-ppss))
(cur-comment-stat (nth 4 cur-ppss))
(cur-comment-style (nth 7 cur-ppss)))
(if (nth 5 cur-ppss)
(cl-incf pos)
(when (and (not (eobp))
(nth 10 cur-ppss)
(not (eq cur-comment-stat
(nth 4 (save-excursion
(syntax-ppss (1+ pos)))))))
(cl-decf pos)
(backward-char 1)))
(cond ((or (nth 3 cur-ppss) (and cur-comment-stat cur-comment-style))
(let ((str/cmt-pos (1+ (nth 8 cur-ppss))))
(when cur-comment-style (cl-incf str/cmt-pos))
(kill-region pos (if hungry-p str/cmt-pos (max bol str/cmt-pos)))))
((and cur-up-pos (or hungry-p (<= bol cur-up-pos)))
(kill-region pos (1+ cur-up-pos)))
(t (let* ((bol-ppss (save-excursion (syntax-ppss bol)))
(bol-up-pos (cadr bol-ppss)))
(cond ((or (and cur-up-pos (> bol-up-pos cur-up-pos))
(and (not cur-up-pos) bol-up-pos))
(kill-region pos (nth (car cur-ppss) (nth 9 bol-ppss))))
((or (nth 3 bol-ppss) (nth 4 bol-ppss))
(kill-region pos (nth 8 bol-ppss)))
(t (kill-region pos bol))))))))))))
一些示例:
;; in expression
(foo bar
baz |quux)
;; =>
(foo bar
|quux)
;; =>
(foo bar|quux)
;; =>
(|quux)
;; in string
"foo bar
baz |quux"
;; =>
"foo bar
|quux"
;; =>
"foo bar|quux"
;; =>
"|quux"
;; expr at bol
(foo ("bar
baz") zot |quux)
;; =>
(foo |quux)
;; C-u / M-<num> / C-u <num>
;; `kill-line' backward
(foo (bar |quux
;; =>
|quux
;; C-u C-u
;; hungry kill
(foo (bar
baz)
zot |quux)
;; =>
(|quux)
"foo bar
baz
zot |quux"
;; =>
"|quux"
更新了一下,现在支持 block comment 了,但仍不支持 nestable comment。还有现在可以用 yank
插入连续被 kill 的文本了。
如果不常使用 kill-line
backward 的功能,可以将 '(16)
改为 '(4)
,把宝贵的 C-u
让出来。
- 光标在
/*
,*/
中间时先退一个字符
/* foo bar
baz quux *|/
=>
/* foo bar
|*/
=>
/* foo bar|*/
=>
/*|*/
{foo /|* bar */}
=>
{|/* bar */}
- 对于支持 nestable comment 的语言,需注意第二种情况会机械地删到头,应该只删到
baz
前的一个字符
foo /* bar /* baz */ zot |*/ quux
=>
foo /*|*/ quux
foo /* bar /* baz |*/ zot */ quux
=>
foo /*|*/ zot */ quux
感谢分享,才知道 paredit 也能够用于 C/C++ ,之前以为只能用于 Lisp 。
简单在 c++-mode
上试了一下,下面这种情况会删除到 }
,( |
是光标)
switch |(foo) {
}
这种情况就能正确地删除到 )
前:
switch (|foo) {
}
paredit 在绝大多数模式都工作良好, paredit 作者的功力相当深厚。
求知道paredit和smartparens到底有什么区别。跟风从paredit切换到了smartparens的人表示原本paredit用的好好的,只是觉得paredit不像smartparens代码提交的依旧很频繁,paredit连一个git源都找不到。
另表示,论坛的C-M-f
快捷键和mac系统的文本编辑框光标移动快捷键有冲突。
paredit的作者功力更深厚,很多语法级处理都比smartparents好
smartparents commit多并不代表东西更好
两个我都是用过了,smartparents到现在都没有达到十年前paredit的水平
很多强的elisp插件取决于作者的功力,而不是commit数量和更新频繁
您在其他major mode里面也会默认开启paredit吗?
试用过 smartparens 和 paredit,我觉得 paredit 好用太多了。然而当我在c++里面开启了paredit-mode,发现有很多特性还是专门为s-exp设计的:比如字母后面敲括号会自动加一个空格。
然而我又特别喜欢paredit的“括号必须匹配才能删除”的功能emmm
我大部分模式都会用paredit,自动加空格是你其他模式影响的,paredit没有这个问题
请用emacs -Q单独测试paredit来排除其他插件的问题。
确实是 paredit 引起的
我这里包的版本是 25beta 20171127.205 来自 melpa
edit:发现了一个叫 paredit-everwhere 的包用于非lisp buffer
假的paredit 吧,我从来不用melpa
直接从作者官网下载吧,emacs大多数插件都是单文件,非要搞一个melpa,真麻烦
我的 paredit 的版本也是 20171127.205 来自 melpa 也没有自动加空格,估计真的是其他插件或者配置的影响
打算试试 paredit-extension,所以把包的依赖关系整理了一下,尽量找到原始下载地址不知道对不对:
paredit-extension "https://www.emacswiki.org/emacs/download/paredit-extension.el"
\-> lazycat-toolkit "https://www.emacswiki.org/emacs/download/lazycat-toolkit.el"
|-> color-moccur "https://www.emacswiki.org/emacs/download/color-moccur.el"
|-> shell-command-extension "https://www.emacswiki.org/emacs/download/shell-command-extension.el"
|-> mwe-log-commands "http://www.foldr.org/~michaelw/emacs/mwe-log-commands.el"
\-> basic-toolkit "https://www.emacswiki.org/emacs/download/basic-toolkit.el"
|-> cycle-buffer "https://www.emacswiki.org/emacs/download/cycle-buffer.el"
|-> css-sort-buffer "https://www.emacswiki.org/emacs/download/css-sort-buffer.el"
\-> windows "http://www.gentei.org/~yuuji/software/windows.el"
\-> revive "http://www.gentei.org/~yuuji/software/revive.el"
(我的配置是这样的: (foo :requires (bar (qux :source (git "https://~/qux.git"))))
,显式地声明依赖关系,避免因为初始化语句书写顺序产生问题,我还可以单独启用某个 “layer”,它本身包含了完整的依赖关系,不必关心它依赖的 package 在其他 layer 里没有加载)
已经解决了
`paredit-web-mode-kill' support rails template now. · manateelazycat/lazycat-emacs@463eed9 · GitHub 这个补丁支持 rails 模板.
比如在 <% … %> 的代码中, 会删除到 %> 之前
大部分都从我 lazycat-emacs git 仓库中去找吧,emacswiki虽然我也会同步更新,但是怕有时候会忘记更新