我经常需要将像这样的代码转换成以下形式:
before do
:something
end
to
before { :something }
有没有一种方法可以在emacs中自动化这个任务?我使用ruby-mode和rinary,但它们在这里并不太有用。
Emacs24.3
及以上版本中的ruby-mode
拥有ruby-toggle-block
命令。
默认绑定键为C-c {
。
(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-start
和ruby-flip-containing-block-type
。ruby-flip-containing-block-type
将三行do..end块折叠为单行{},反之亦然。如果块的长度不是恰好3行或1行,则应保持不变。{\2 }
这样的东西可能会起作用。然后,您可以自定义它,直到它完全符合您的需求,并将其绑定到宏上,以便您随时可以使用它并给朋友留下深刻印象!
我在vi(我的首选编辑器)中测试了上述正则表达式,它们都起作用。因此,类似的东西对您也应该有效。
有关更多信息,请确保查看{{link1:emacs wiki}}!
这里是一个函数。我是一个elisp初学者。它只能从do到{,让我知道它是否适用于你。