[英]Regexp Emacs for R comments
我想在 Emacs 中構建一個正則表達式來清理我的 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
}
}
#
我找到了一個正則表達式來代替第一種,所以我能夠按段落(標記段落)對齊它們。 那工作得很好。
那么問題是回代:
(replace-regexp "^\\s-+#+" "bla" nil (point-min) (point-max))
這將從一行的開頭替換為任意數量的空格和任意數量的注釋字符,例如:
#########
進入
bla
問題是我想將它們替換回原來的樣子,所以“bla”必須回到相同數量的空格和相同數量的#。
希望有人理解我正在嘗試做的事情,並且對方法有更好的想法或知道如何解決這個正則表達式部分。
好吧,這是我認為你想要做的一些瘋狂嘗試。 看起來可行,但需要大量的測試和打磨:
(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
編輯:這應該恢復鼠標位置,但不會恢復滾動位置(可以工作,也許,我只需要尋找滾動的存儲方式)。
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
嘗試
(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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.