Я уверен, что это можно сделать короче и лучше, но сейчас у меня есть следующее:
(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 строка длиной, они должны быть оставлены в покое.
Сейчас я использую это в своей настройке ruby, поэтому я буду признателен за улучшения.