我想在Emacs中构建一个regexp来清理我的R代码。
我遇到的一个问题是有不同类型的评论: 你有那些具有一定数量的空格(1),例如:
# This is a comment:
# This is also a comment
或者你有这样的情况(2):
require(lattice) # executable while the comment is informative
我的想法是,我想在第二种评论时(在可执行文件之后)对齐评论,同时排除第一类评论。
理想情况下,它会将所有评论与第一类评论对齐,而不是第一类评论。
示例:
funfun <- function(a, b) {
# This is a function
if (a == b) { # if a equals b
c <- 1 # c is 1
}
}
#
要:
funfun <- function(a, b) {
# This is a function
if (a == b) { # if a equals b
c <- 1 # c is 1
}
}
#
我找到了一个正则表达式来替换第一类的那些,所以我能够按照段落对齐它们(mark-paragraph)。这样做很好。
然后问题就是后退:
(replace-regexp "^\\s-+#+" "bla" nil (point-min) (point-max))
这取代了行的开头,包含任意数量的空格和任意数量的注释字符,如:
#########
到
bla
问题在于我想将它们替换回原来的状态,因此“bla”必须回到相同数量的空白和相同数量的#。
希望有人理解我想要做的事情,并且对方法有更好的想法,或者知道如何解决这个正则表达式部分。
答案 0 :(得分:1)
嗯,这是一些疯狂的尝试做我认为你追求的事情。它似乎有效,但它需要大量的测试和抛光:
(defun has-face-at-point (face &optional position)
(unless position (setq position (point)))
(unless (consp face) (setq face (list face)))
(let ((props (text-properties-at position)))
(loop for (key value) on props by #'cddr
do (when (and (eql key 'face) (member value face))
(return t)))))
(defun face-start (face)
(save-excursion
(while (and (has-face-at-point face) (not (bolp)))
(backward-char))
(- (point) (save-excursion (move-beginning-of-line 1)) (if (bolp) 0 -1))))
(defun beautify-side-comments ()
(interactive)
;; Because this function does a lot of insertion, it would
;; be better to execute it in the temporary buffer, while
;; copying the original text of the file into it, such as
;; to prevent junk in the formatted buffer's history
(let ((pos (cons (save-excursion
(beginning-of-line)
(count-lines (point-min) (point)))
(- (save-excursion (end-of-line) (point)) (point))))
(content (buffer-string))
(comments '(font-lock-comment-face font-lock-comment-delimiter-face)))
(with-temp-buffer
(insert content)
(goto-char (point-min))
;; thingatpt breaks if there are overlays with their own faces
(let* ((commentp (has-face-at-point comments))
(margin
(if commentp (face-start comments) 0))
assumed-margin pre-comment commented-lines)
(while (not (eobp))
(move-end-of-line 1)
(cond
((and (has-face-at-point comments)
commentp) ; this is a comment continued from
; the previous line
(setq assumed-margin (face-start comments)
pre-comment
(buffer-substring-no-properties
(save-excursion (move-beginning-of-line 1))
(save-excursion (beginning-of-line)
(forward-char assumed-margin) (point))))
(if (every
(lambda (c) (or (char-equal c ?\ ) (char-equal c ?\t)))
pre-comment)
;; This is the comment preceded by whitespace
(setq commentp nil margin 0 commented-lines 0)
(if (<= assumed-margin margin)
;; The comment found starts on the left of
;; the margin of the comments found so far
(save-excursion
(beginning-of-line)
(forward-char assumed-margin)
(insert (make-string (- margin assumed-margin) ?\ ))
(incf commented-lines))
;; This could be optimized by going forward and
;; collecting as many comments there are, but
;; it is simpler to return and re-indent comments
;; (assuming there won't be many such cases anyway.
(setq margin assumed-margin)
(move-end-of-line (1- (- commented-lines))))))
((has-face-at-point comments)
;; This is the fresh comment
;; This entire block needs refactoring, it is
;; a repetition of the half the previous blockp
(setq assumed-margin (face-start comments)
pre-comment
(buffer-substring-no-properties
(save-excursion (move-beginning-of-line 1))
(save-excursion (beginning-of-line)
(forward-char assumed-margin) (point))))
(unless (every
(lambda (c)
(or (char-equal c ?\ ) (char-equal c ?\t)))
pre-comment)
(setq commentp t margin assumed-margin commented-lines 0)))
(commentp
;; This is the line directly after a block of comments
(setq commentp nil margin assumed-margin commented-lines 0)))
(unless (eobp) (forward-char)))
;; Retrieve back the formatted contnent
(setq content (buffer-string))))
(erase-buffer)
(insert content)
(beginning-of-buffer)
(forward-line (car pos))
(end-of-line)
(backward-char (cdr pos))))
我还在pastebin上复制了它以提高可读性:http://pastebin.com/C2L9PRDM
编辑:这应该恢复鼠标位置但不会恢复滚动位置(可能会工作,也许,我只需要查看滚动的存储方式)。
答案 1 :(得分:1)
align-regexp
是您需要的精彩emacs魔法:
(defun align-comments ()
"align R comments depending on whether at start or in the middle."
(interactive)
(align-regexp (point-min) (point-max)
"^\\(\\s-*?\\)\\([^[:space:]]+\\)\\(\\s-+\\)#" 3 1 nil) ;type 2 regex
(align-regexp (point-min) (point-max)
"^\\(\\s-*\\)\\(\\s-*\\)#" 2 0 nil)) ;type 1 regex
之前:
# a comment type 1
## another comment type 1
a=1 ###### and a comment type 2 with lots of #####'s
a.much.longer.variable.name=2 # and another, slightly longer type 2 comment
## and a final type 1
后:
# a comment type 1
## another comment type 1
a=1 ###### and a comment type 2 with lots of #####'s
a.much.longer.variable.name=2 # and another, slightly longer type 2 comment
## and a final type 1
答案 2 :(得分:0)
尝试
(replace-regexp "^\\(\\s-+\\)#" "\\1bla" nil (point-min) (point-max))
然后
(replace-regexp "^\\(\\s-+\\)bla+" "\\1#" nil (point-min) (point-max))
但如果我理解你,我可能会做一些事情:
(align-string "\b\s-#" begin end)