看到这个问题 两行代码格式化为一行,快捷键 的时候,突然想到一个困扰了我很久的问题,就是合并上下两行的时候,如果是中文怎样避免空格?
我想应该从这个函数入手: delete-indentation
,它调用了fixup-whitespace
这个函数。解决办法应该是调整 fixup-whitespace
,使它在前文是中文的时候不添加空格。但是这里是用advice
还是用cl-letf
比较合适呢?欢迎大家来献策。
Edit: 答案在 17 楼。根据试用过的朋友反馈,除了这个版本以外,这个帖子内的其它版本可能跟 Evil 配合不好。
方案1: advise fixup-whitespace
,缺点是不知道这个函数在别的地方有没有用到,会不会造成什么问题。
方案2: 使用 cl-letf
,仅针对 delete-indentation
这个函数改变 fixup-whitespace
的定义。
还有什么方案欢迎大家赐教!
恐怕只动 delete-indentation 就可以了。
也可以试试直接定义新的命令,这样也不用担心有副作用了
(defun my-fixup-whitespace ()
"同 `fixup-whitespace' 但如前面是中文字符则不留空格."
(interactive "*")
(fixup-whitespace)
(when (save-excursion (forward-char -1)
(looking-at "\\cc"))
(delete-char 1)))
(defun my-delete-indentation ()
"同 `delete-indentation' 但如前面是中文字符则不留空格."
(interactive "*")
(delete-indentation)
(my-fixup-whitespace))
应该都可以,advice 也可以当作用来临时重定义一个函数,如果及时去掉 advice 的话,比如下面 fixup-whitespace
的 advice 只会对 delete-indentaion
有效。
(define-advice delete-indentation (:around (old-fun &rest r) 中文无须空格)
(unwind-protect
(progn
(define-advice fixup-whitespace (:around (old-fun &rest r) 是的,中文无须空格)
;; 仅仅是为了
(apply old-fun r))
;; 举例子
(apply old-fun r))
(advice-remove 'fixup-whitespace #'fixup-whitespace@是的,中文无须空格)))
1 个赞
确实,这样简单直接
但是下面的 advice 没看太明白,能不能把注释以外的中文换成英文字符,谢谢!
PS:这是 25 的新 advice 语法吗?我都是用 defadvice
,所以没看太明白。。。
嗯,上面的代码是可以用 Emacs 25 运行的,但并没有修改 delete-indentation 的行为,用了举个例子而已。我不会老的 advice 的方法(defadvice
),我开始频繁地用 Emacs 的时候(两三年前)它就已经被新的方法取代了。
好吧,我肯定是被哪篇博文误导了,我接触 advice 就是从 defadvice 开始的
这个 Advice 的方法(nadvice.el
)不是 Emacs 25 才有的,只是 define-advice
是 Emacs 25 新加入的一个辅助宏,效果与 defun
+ advice-add
一样
;; Emacs 24.4+
(define-advice emacs-version (:around (&rest _) vim)
(message "Vim 7.4"))
等价于
;; Emacs 25.1+
(defun emacs-version@vim (&rest _)
(message "Vim 7.4"))
(advice-add 'emacs-version :around (function emacs-version@vim)))
2 个赞
不是。不是。
@
是 define-advice
用来构造函数名的连接号。如果你用 defun
+ advice-add
的话,随便用什么名字都可以。
1 个赞
et2010
2017 年3 月 15 日 14:33
14
还有一个问题,用这种方式 Advise 的话,interactive 怎样处理?我之所以这么问是看了这个: EmacsWiki: Advising Functions
遇到实际的情况再考虑吧,因为很少见。
在函数里面需要判断是否一个命令是从按键还是从 Lisp 调用的情况比较少见,就算用也只是用来显示一条提示,文档(interactive-p
/ called-interactively-p
的 Doc string)也说要尽量避免。
比如,用户只用 M-x foo
时才打印提示,从 Lisp 调用 (foo buffer)
不打印,如果你 Advice 了 foo
还需要这个打印功能,可以用 funcall-interactively
。
(defun foo (buffer)
(interactive "bBuffer: ")
(let ((filename (buffer-file-name (get-buffer buffer))))
(when (called-interactively-p 'interactive)
(message "The buffer file name is %s" filename))
filename))
(define-advice foo (:around (old-fun buffer) bar)
(funcall-interactively old-fun (current-buffer)))
1 个赞
et2010
2017 年3 月 15 日 15:27
16
特别感谢您的耐心回复,我学到了很多东西 @xuchunyang
我修改了您的代码,简单测试了一下,放到gist上了。有需要的同学可以试用,意见反馈留在 gist 上或这里我好修改: https://gist.github.com/et2010/8dadd64a7e4193b7c93f6a4ba6226ea6#file-fixup-join-lines-in-chinese-el
Edit: 根据 @lxeg0429 的反馈,这个版本跟 evil 配合不好,所以我把链接编辑掉了,推荐用下面一个使用 cl-letf
的版本。
et2010
2017 年3 月 15 日 16:07
17
这里是另外一个版本,这个版本用到了 cl-letf
和 around advice,个人觉得这个版本可能更不容易出错,因为上一个版本并未考虑如果原始函数并未添加空格的情况(当然也许这些情形并不重叠)。 Remove needless whitespace when joining two lines in Chinese · GitHub
(defun et/fixup-whitespace ()
"Fixup white space between objects around point.
Leave one space or none, according to the context."
(interactive "*")
(save-excursion
(delete-horizontal-space)
(if (or (looking-at "^\\|\\s)")
(save-excursion (forward-char -1)
;; we adapted the regexp here:
(looking-at "\\cc\\|$\\|\\s(\\|\\s'")))
nil
(insert ?\s))))
(defun et/delete-indentation (old-func &rest args)
(cl-letf (((symbol-function 'fixup-whitespace) #'et/fixup-whitespace))
(apply old-func args)))
(advice-add #'delete-indentation :around #'et/delete-indentation)
PS: 未考虑 interactive 的问题, @xuchunyang 大神帮我看看
PPS:这个版本中的 et/fixup-whitespace
函数是复制粘贴的 emacs 原生函数,只是把其中的正则表达式改了。
PPPS:这种Advice方式真的是比旧的 defadvice 好用太太太太多了,谢谢 @xuchunyang 大神的推荐!
1 个赞
不用考虑,(interactive ...)
是照常工作的。上面(也就是 EmacsWiki: Advising Functions 的末尾)说的是当你要 Advice 的函数体中用到了 interactive-p
时的情况,在 delete-indentation
中并没有用到。
如何把这个功能直接绑定在S-j上啊,判断如果末尾是中文就删除一个空格,如果是英文就用原生的功能?
能不能给段代码啊?