Emacs,ruby:将结束块转换为花括号,反之亦然

时间:2011-07-15 19:15:13

标签: ruby emacs

我经常发现自己会像这样转换代码:

before do 
  :something
end

before { :something }

有没有办法在emacs中自动执行此任务?我使用ruby-mode和rinary,但它们在这里不太有用。

3 个答案:

答案 0 :(得分:5)

我相信它可以做得更短更好,但是现在我有以下内容:

(defun ruby-get-containing-block ()
  (let ((pos (point))
        (block nil))
    (save-match-data
      (save-excursion
        (catch 'break
          ;; If in the middle of or at end of do, go back until at start
          (while (and (not (looking-at "do"))
                      (string-equal (word-at-point) "do"))
            (backward-char 1))
          ;; Keep searching for the containing block (i.e. the block that begins
          ;; before our point, and ends after it)
          (while (not block)
            (if (looking-at "do\\|{")
                (let ((start (point)))
                  (ruby-forward-sexp)
                  (if (> (point) pos)
                      (setq block (cons start (point)))
                    (goto-char start))))
            (if (not (search-backward-regexp "do\\|{" (point-min) t))
                (throw 'break nil))))))
        block))

(defun ruby-goto-containing-block-start ()
  (interactive)
  (let ((block (ruby-get-containing-block)))
    (if block
        (goto-char (car block)))))

(defun ruby-flip-containing-block-type ()
  (interactive)
  (save-excursion
    (let ((block (ruby-get-containing-block)))
      (goto-char (car block))
      (save-match-data
        (let ((strings (if (looking-at "do")
                           (cons
                            (if (= 3 (count-lines (car block) (cdr block)))
                                "do\\( *|[^|]+|\\)? *\n *\\(.*?\\) *\n *end"
                              "do\\( *|[^|]+|\\)? *\\(\\(.*\n?\\)+\\) *end")
                            "{\\1 \\2 }")
                         (cons
                          "{\\( *|[^|]+|\\)? *\\(\\(.*\n?\\)+\\) *}"
                          (if (= 1 (count-lines (car block) (cdr block)))
                              "do\\1\n\\2\nend"
                            "do\\1\\2end")))))
          (when (re-search-forward (car strings) (cdr block) t)
            (replace-match (cdr strings) t)
            (delete-trailing-whitespace (match-beginning 0) (match-end 0))
            (indent-region (match-beginning 0) (match-end 0))))))))

有两个要绑定到键的函数:ruby-goto-containing-block-startruby-flip-containing-block-type

任何一个命令都可以在块内的任何位置运行,并且希望它们可以跳过应该跳过的块 - 尽管如果要转换为短块格式,这应该不是问题。

ruby-flip-containing-block-type折叠三行do .. end block to single line {},反之亦然。如果这些块不是正好3行而是1行,那么它应该不管它们。

我现在正在我的ruby设置上使用它,所以我希望有所改进。

答案 1 :(得分:1)

您可以使用跨越换行符的正则表达式。

/ do(C-q C-j \?)*(。*)(C-q C-j \?)* end /

并替换为

{\2 } 

这样的事情可行。然后你可以自定义它,直到它完全符合你的需要,然后将它绑定到一个宏上,这样你就可以把它甩出来,随时给你的朋友留下深刻的印象!

我在vi(我选择的编辑器)中测试了上面的正则表达式并且他们工作了。所以类似的东西应该适合你。

有关详情,请务必查看emacs wiki

答案 2 :(得分:1)

Here是一个功能。我是一名elisp初学者。它只走一条路;从do到{。让我知道它是否适合你。