dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

ruby-mode-expansions.el (7186B)


      1 ;;; ruby-mode-expansions.el --- ruby-specific expansions for expand-region
      2 
      3 ;; Copyright (C) 2011-2020  Free Software Foundation, Inc
      4 
      5 ;; Author: Matt Briggs
      6 ;; Based on js-mode-expansions by: Magnar Sveen <magnars@gmail.com>
      7 ;; Keywords: marking region
      8 
      9 ;; This program is free software; you can redistribute it and/or modify
     10 ;; it under the terms of the GNU General Public License as published by
     11 ;; the Free Software Foundation, either version 3 of the License, or
     12 ;; (at your option) any later version.
     13 
     14 ;; This program is distributed in the hope that it will be useful,
     15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 ;; GNU General Public License for more details.
     18 
     19 ;; You should have received a copy of the GNU General Public License
     20 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 ;;; Commentary:
     23 
     24 
     25 ;; LeWang:
     26 ;;
     27 ;;      I think `er/ruby-backward-up' and `er/ruby-forward-up' are nifty
     28 ;;      functions in their own right.
     29 ;;
     30 ;;      I would bind them to C-M-u and C-M-d respectively.
     31 
     32 ;; Expansions:
     33 ;;
     34 ;;
     35 ;;  er/mark-ruby-block-up
     36 ;;
     37 
     38 ;;; Code:
     39 (eval-when-compile (require 'cl))
     40 (require 'expand-region-core)
     41 (require 'ruby-mode)
     42 
     43 (defvar er/ruby-block-end-re
     44   (concat ruby-block-end-re "\\|}")
     45   "like ruby-mode's but also for '}'")
     46 
     47 (defun er/ruby-skip-past-block-end ()
     48   "If line is blockend, move point to next line."
     49   (when (looking-at er/ruby-block-end-re)
     50     (forward-line 1)))
     51 
     52 (defun er/ruby-end-of-block (&optional arg)
     53   "By default `ruby-end-of-block' goes to BOL of line containing end-re.
     54 
     55 This moves point to the next line to include the end of the block"
     56   (interactive "p")
     57   ;; Workaround for `ruby-end-of-block' in Emacs 23.
     58   (when (re-search-forward (concat "\\<\\(" ruby-block-beg-re "\\)\\>")
     59                            (point-at-eol) t)
     60     (goto-char (match-beginning 0)))
     61   (ruby-end-of-block (or arg 1))
     62   (er/ruby-skip-past-block-end))
     63 
     64 (defun er/point-at-indentation ()
     65   "Return the point where current line's indentation ends."
     66   (save-excursion
     67     (back-to-indentation)
     68     (point)))
     69 
     70 (defun er/ruby-backward-up ()
     71   "a la `paredit-backward-up'"
     72   (interactive)
     73   ;; if our current line ends a block, we back a line, otherwise we
     74   (when (save-excursion
     75           (back-to-indentation)
     76           (looking-at-p ruby-block-end-re))
     77     (forward-line -1))
     78   (let ((orig-point (point))
     79         progress-beg
     80         progress-end)
     81 
     82     ;; cover the case when point is in the line of beginning of block
     83     (unless (progn (ruby-end-of-block)
     84                    (ruby-beginning-of-block)
     85                    ;; "Block beginning" is often not at indentation in Emacs 24.
     86                    (< (er/point-at-indentation) orig-point))
     87       (loop do
     88             (ruby-beginning-of-block)
     89             (setq progress-beg (point))
     90             (when (= (point) (point-min))
     91               (return))
     92             (ruby-end-of-block)
     93             (setq progress-end (if (looking-at-p er/ruby-block-end-re)
     94                                    (point-at-bol 0)
     95                                  (point-at-bol 1)))
     96             (goto-char progress-beg)
     97             (when (> progress-end orig-point)
     98               (return))))))
     99 
    100 ;;; This command isn't used here explicitly, but it's symmetrical with
    101 ;;; `er/ruby-backward-up', and nifty for interactive use.
    102 (defun er/ruby-forward-up ()
    103   "a la `paredit-forward-up'"
    104   (interactive)
    105   (er/ruby-backward-up)
    106   (er/ruby-end-of-block))
    107 
    108 (defun er/get-ruby-block (&optional pos)
    109   "return (beg . end) of current block"
    110   (setq pos (or pos (point)))
    111   (save-excursion
    112     (goto-char pos)
    113     (let (beg end)
    114       (cons (progn
    115               (er/ruby-backward-up)
    116               (er/point-at-indentation))
    117             (progn
    118               (er/ruby-end-of-block)
    119               (point))))))
    120 
    121 (defun er/mark-ruby-block-up-1 ()
    122   (er/ruby-backward-up)
    123   (set-mark (er/point-at-indentation))
    124   (er/ruby-end-of-block)
    125   (exchange-point-and-mark))
    126 
    127 (defun er/mark-ruby-block-up (&optional no-recurse)
    128   "mark the next level up."
    129   (interactive)
    130   (if (use-region-p)
    131       (let* ((orig-end (region-end))
    132              (orig-beg (region-beginning))
    133              (orig-len (- orig-end orig-beg))
    134              (prev-block-point
    135               (or (save-excursion
    136                     (goto-char orig-end)
    137                     (forward-line 0)
    138                     (back-to-indentation)
    139                     (cond ((looking-at-p er/ruby-block-end-re)
    140                            (point-at-bol 0))
    141                           ((re-search-forward
    142                             (concat "\\<\\(" ruby-block-beg-re "\\)\\>")
    143                             (point-at-eol)
    144                             t)
    145                            (point-at-bol 2))) )
    146                   (point)))
    147              (prev-block-info (er/get-ruby-block prev-block-point))
    148              (prev-block-beg (car prev-block-info))
    149              (prev-block-end (cdr prev-block-info))
    150              (prev-block-len (- prev-block-end prev-block-beg)))
    151         (if (and (>= orig-beg prev-block-beg)
    152                  (<= orig-end prev-block-end)
    153                  (< orig-len prev-block-len))
    154             ;; expand to previous block if it contains and grows current
    155             ;; region
    156             (progn
    157               (deactivate-mark)
    158               (goto-char prev-block-point)
    159               (or no-recurse
    160                   (er/mark-ruby-block-up 'no-recurse)))
    161           (er/mark-ruby-block-up-1)))
    162     (er/mark-ruby-block-up-1)))
    163 
    164 (defun er/mark-ruby-instance-variable ()
    165   "Marks instance variables in ruby.
    166 Assumes that point is at the @ - if it is inside the word, that will
    167 be marked first anyway."
    168   (when (looking-at "@")
    169     (forward-char 1))
    170   (when (er/looking-back-exact "@")
    171     (er/mark-symbol)
    172     (forward-char -1)))
    173 
    174 (defun er/mark-ruby-heredoc ()
    175   "Marks a heredoc, since `er/mark-inside-quotes' assumes single quote chars."
    176   (let ((ppss (syntax-ppss)))
    177     (when (elt ppss 3)
    178       (let ((s-start (elt ppss 8)))
    179         (goto-char s-start)
    180         (when (save-excursion
    181                 (beginning-of-line)
    182                 (re-search-forward "<<\\(-?\\)['\"]?\\([a-zA-Z0-9_]+\\)" s-start nil))
    183           (let ((allow-indent (string= "-" (match-string 1)))
    184                 (terminator (match-string 2))
    185                 (heredoc-start (save-excursion
    186                                  (forward-line)
    187                                  (point))))
    188             (forward-sexp 1)
    189             (forward-line -1)
    190             (when (looking-at (concat "^" (if allow-indent "[ \t]*" "") terminator "$"))
    191               (set-mark heredoc-start)
    192               (exchange-point-and-mark))))))))
    193 
    194 (defun er/add-ruby-mode-expansions ()
    195   "Adds Ruby-specific expansions for buffers in ruby-mode"
    196   (set (make-local-variable 'er/try-expand-list)
    197        (remove 'er/mark-defun 
    198                (append
    199                 (default-value 'er/try-expand-list)
    200                 '(er/mark-ruby-instance-variable
    201                   er/mark-ruby-block-up
    202                   er/mark-ruby-heredoc)))))
    203 
    204 (er/enable-mode-expansions 'ruby-mode 'er/add-ruby-mode-expansions)
    205 (provide 'ruby-mode-expansions)