简体   繁体   English

用于 R 注释的正则表达式 Emacs

[英]Regexp Emacs for R comments

I would like to build a regexp in Emacs for cleaning up my R code.我想在 Emacs 中构建一个正则表达式来清理我的 R 代码。

One of the problems I ran into was that there are different types of comments: You have those with a certain amount of whitespace (1), eg:我遇到的问题之一是有不同类型的评论:您有一定数量的空格 (1),例如:

        # This is a comment:
# This is also a comment

or you have situations like this (2):或者你有这样的情况(2):

require(lattice) # executable while the comment is informative

The idea is that I want to align the comments when they are of the second kind (after something that's executable), while excluding those of the first kind.这个想法是,当它们属于第二种(可执行的东西之后)时,我想对齐注释,同时排除第一种。

Ideally, it will align all the comments BETWEEN those of the first kind, but not those of the first kind.理想情况下,它将对齐第一种评论之间的所有评论,但不会对齐第一种评论。

Example:例子:

funfun <- function(a, b) {
# This is a function
    if (a == b) { # if a equals b
      c <- 1 # c is 1 
    }
  }  
#

To:到:

funfun <- function(a, b) {
# This is a function
    if (a == b) { # if a equals b
      c <- 1      # c is 1 
    }
  }  
# 

I found a regexp to do a replacement for those of the first kind, so then I was able to align them per paragraph (mark-paragraph).我找到了一个正则表达式来代替第一种,所以我能够按段落(标记段落)对齐它们。 That worked kind of well.那工作得很好。

Problem is then the backsubstitution:那么问题是回代:

(replace-regexp "^\\s-+#+" "bla" nil (point-min) (point-max))

This replaces from the start of a line, with any amount of whitespace and any amount of comment characters like:这将从一行的开头替换为任意数量的空格和任意数量的注释字符,例如:

     #########   

into进入

     bla

The problem is that I would like to replace them back into what they are originally, so "bla" has to go back into the same amount of whitespace and same amount of #.问题是我想将它们替换回原来的样子,所以“bla”必须回到相同数量的空格和相同数量的#。

Hopefully someone understands what I am trying to do and has either a better idea for an approach or knows how to solve this regexp part.希望有人理解我正在尝试做的事情,并且对方法有更好的想法或知道如何解决这个正则表达式部分。

在此处输入图片说明

Well, here's some crazy attempt at doing something I thought you were after.好吧,这是我认为你想要做的一些疯狂尝试。 It seems to work, but it needs a lot of testing and polishing:看起来可行,但需要大量的测试和打磨:

(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))))

I've also duplicated it on pastebin for better readability: http://pastebin.com/C2L9PRDM为了更好的可读性,我还在 pastebin 上复制了它: http : //pastebin.com/C2L9PRDM

EDIT: This should restore the mouse position but will not restore the scroll position (could be worked to, perhaps, I'd just need to look for how scrolling is stored).编辑:这应该恢复鼠标位置,但不会恢复滚动位置(可以工作,也许,我只需要寻找滚动的存储方式)。

align-regexp is the awesome bit of emacs magic you need: 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

before:前:

# 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

after:后:

      # 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

Try尝试

(replace-regexp "^\\(\\s-+\\)#" "\\1bla" nil (point-min) (point-max))

then然后

(replace-regexp "^\\(\\s-+\\)bla+" "\\1#" nil (point-min) (point-max))

but If I understood you well, I would probably do something like :但如果我理解你,我可能会做这样的事情:

(align-string "\b\s-#" begin end)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM