aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/ruby-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/ruby-mode.el')
-rw-r--r--lisp/progmodes/ruby-mode.el122
1 files changed, 79 insertions, 43 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 7c72b73a879..9d78b20ba4c 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -105,7 +105,10 @@
105(eval-and-compile 105(eval-and-compile
106 (defconst ruby-here-doc-beg-re 106 (defconst ruby-here-doc-beg-re
107 "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" 107 "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)"
108 "Regexp to match the beginning of a heredoc.")) 108 "Regexp to match the beginning of a heredoc.")
109
110 (defconst ruby-expression-expansion-re
111 "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)"))
109 112
110(defun ruby-here-doc-end-match () 113(defun ruby-here-doc-end-match ()
111 "Return a regexp to find the end of a heredoc. 114 "Return a regexp to find the end of a heredoc.
@@ -384,7 +387,9 @@ and `\\' when preceded by `?'."
384 (looking-at "class\\s *<<")))) 387 (looking-at "class\\s *<<"))))
385 388
386(defun ruby-expr-beg (&optional option) 389(defun ruby-expr-beg (&optional option)
387 "TODO: document." 390 "Check if point is possibly at the beginning of an expression.
391OPTION specifies the type of the expression.
392Can be one of `heredoc', `modifier', `expr-qstr', `expr-re'."
388 (save-excursion 393 (save-excursion
389 (store-match-data nil) 394 (store-match-data nil)
390 (let ((space (skip-chars-backward " \t")) 395 (let ((space (skip-chars-backward " \t"))
@@ -397,10 +402,10 @@ and `\\' when preceded by `?'."
397 (or (eq (char-syntax (char-before (point))) ?w) 402 (or (eq (char-syntax (char-before (point))) ?w)
398 (ruby-special-char-p)))) 403 (ruby-special-char-p))))
399 nil) 404 nil)
400 ((and (eq option 'heredoc) (< space 0)) 405 ((looking-at ruby-operator-re))
401 (not (progn (goto-char start) (ruby-singleton-class-p)))) 406 ((eq option 'heredoc)
402 ((or (looking-at ruby-operator-re) 407 (and (< space 0) (not (ruby-singleton-class-p start))))
403 (looking-at "[\\[({,;]") 408 ((or (looking-at "[\\[({,;]")
404 (and (looking-at "[!?]") 409 (and (looking-at "[!?]")
405 (or (not (eq option 'modifier)) 410 (or (not (eq option 'modifier))
406 (bolp) 411 (bolp)
@@ -865,39 +870,54 @@ calculating indentation on the lines after it."
865 (beginning-of-line))))) 870 (beginning-of-line)))))
866 871
867(defun ruby-move-to-block (n) 872(defun ruby-move-to-block (n)
868 "Move to the beginning (N < 0) or the end (N > 0) of the current block 873 "Move to the beginning (N < 0) or the end (N > 0) of the
869or blocks containing the current block." 874current block, a sibling block, or an outer block. Do that (abs N) times."
870 ;; TODO: Make this work for n > 1,
871 ;; make it not loop for n = 0,
872 ;; document body
873 (let ((orig (point)) 875 (let ((orig (point))
874 (start (ruby-calculate-indent)) 876 (start (ruby-calculate-indent))
875 (down (looking-at (if (< n 0) ruby-block-end-re 877 (signum (if (> n 0) 1 -1))
876 (concat "\\<\\(" ruby-block-beg-re "\\)\\>")))) 878 (backward (< n 0))
877 pos done) 879 down pos done)
878 (while (and (not done) (not (if (< n 0) (bobp) (eobp)))) 880 (dotimes (_ (abs n))
879 (forward-line n) 881 (setq done nil)
880 (cond 882 (setq down (save-excursion
881 ((looking-at "^\\s *$")) 883 (back-to-indentation)
882 ((looking-at "^\\s *#")) 884 ;; There is a block start or block end keyword on this
883 ((and (> n 0) (looking-at "^=begin\\>")) 885 ;; line, don't need to look for another block.
884 (re-search-forward "^=end\\>")) 886 (and (re-search-forward
885 ((and (< n 0) (looking-at "^=end\\>")) 887 (if backward ruby-block-end-re
886 (re-search-backward "^=begin\\>")) 888 (concat "\\_<\\(" ruby-block-beg-re "\\)\\_>"))
887 (t 889 (line-end-position) t)
888 (setq pos (current-indentation)) 890 (not (nth 8 (syntax-ppss))))))
891 (while (and (not done) (not (if backward (bobp) (eobp))))
892 (forward-line signum)
889 (cond 893 (cond
890 ((< start pos) 894 ;; Skip empty and commented out lines.
891 (setq down t)) 895 ((looking-at "^\\s *$"))
892 ((and down (= pos start)) 896 ((looking-at "^\\s *#"))
893 (setq done t)) 897 ;; Skip block comments;
894 ((> start pos) 898 ((and (not backward) (looking-at "^=begin\\>"))
895 (setq done t))))) 899 (re-search-forward "^=end\\>"))
896 (if done 900 ((and backward (looking-at "^=end\\>"))
897 (save-excursion 901 (re-search-backward "^=begin\\>"))
898 (back-to-indentation) 902 (t
899 (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>")) 903 (setq pos (current-indentation))
900 (setq done nil))))) 904 (cond
905 ;; Deeper indentation, we found a block.
906 ;; FIXME: We can't recognize empty blocks this way.
907 ((< start pos)
908 (setq down t))
909 ;; Block found, and same indentation as when started, stop.
910 ((and down (= pos start))
911 (setq done t))
912 ;; Shallower indentation, means outer block, can stop now.
913 ((> start pos)
914 (setq done t)))))
915 (if done
916 (save-excursion
917 (back-to-indentation)
918 ;; Not really at the first or last line of the block, move on.
919 (if (looking-at (concat "\\<\\(" ruby-block-mid-re "\\)\\>"))
920 (setq done nil))))))
901 (back-to-indentation))) 921 (back-to-indentation)))
902 922
903(defun ruby-beginning-of-block (&optional arg) 923(defun ruby-beginning-of-block (&optional arg)
@@ -909,8 +929,7 @@ With ARG, move up multiple blocks."
909(defun ruby-end-of-block (&optional arg) 929(defun ruby-end-of-block (&optional arg)
910 "Move forward to the end of the current block. 930 "Move forward to the end of the current block.
911With ARG, move out of multiple blocks." 931With ARG, move out of multiple blocks."
912 ;; Passing a value > 1 to ruby-move-to-block currently doesn't work. 932 (interactive "p")
913 (interactive)
914 (ruby-move-to-block (or arg 1))) 933 (ruby-move-to-block (or arg 1)))
915 934
916(defun ruby-forward-sexp (&optional arg) 935(defun ruby-forward-sexp (&optional arg)
@@ -1233,7 +1252,19 @@ It will be properly highlighted even when the call omits parens."))
1233 ;; Handle percent literals: %w(), %q{}, etc. 1252 ;; Handle percent literals: %w(), %q{}, etc.
1234 ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) 1253 ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
1235 (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) 1254 (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
1236 (point) end)) 1255 (point) end)
1256 (remove-text-properties start end '(ruby-expansion-match-data))
1257 (goto-char start)
1258 ;; Find all expression expansions and
1259 ;; - set the syntax of all text inside to whitespace,
1260 ;; - save the match data to a text property, for font-locking later.
1261 (while (re-search-forward ruby-expression-expansion-re end 'move)
1262 (when (ruby-in-ppss-context-p 'string)
1263 (put-text-property (match-beginning 2) (match-end 2)
1264 'syntax-table (string-to-syntax "-"))
1265 (put-text-property (match-beginning 2) (1+ (match-beginning 2))
1266 'ruby-expansion-match-data
1267 (match-data)))))
1237 1268
1238 (defun ruby-syntax-propertize-heredoc (limit) 1269 (defun ruby-syntax-propertize-heredoc (limit)
1239 (let ((ppss (syntax-ppss)) 1270 (let ((ppss (syntax-ppss))
@@ -1566,7 +1597,7 @@ See `font-lock-syntax-table'.")
1566 '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-constant-face) 1597 '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-constant-face)
1567 ;; expression expansion 1598 ;; expression expansion
1568 '(ruby-match-expression-expansion 1599 '(ruby-match-expression-expansion
1569 0 font-lock-variable-name-face t) 1600 2 font-lock-variable-name-face t)
1570 ;; warn lower camel case 1601 ;; warn lower camel case
1571 ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" 1602 ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)"
1572 ; 0 font-lock-warning-face) 1603 ; 0 font-lock-warning-face)
@@ -1574,9 +1605,14 @@ See `font-lock-syntax-table'.")
1574 "Additional expressions to highlight in Ruby mode.") 1605 "Additional expressions to highlight in Ruby mode.")
1575 1606
1576(defun ruby-match-expression-expansion (limit) 1607(defun ruby-match-expression-expansion (limit)
1577 (when (re-search-forward "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)" limit 'move) 1608 (let ((prop 'ruby-expansion-match-data) pos value)
1578 (or (ruby-in-ppss-context-p 'string) 1609 (when (and (setq pos (next-single-char-property-change (point) prop
1579 (ruby-match-expression-expansion limit)))) 1610 nil limit))
1611 (> pos (point)))
1612 (goto-char pos)
1613 (or (and (setq value (get-text-property pos prop))
1614 (progn (set-match-data value) t))
1615 (ruby-match-expression-expansion limit)))))
1580 1616
1581;;;###autoload 1617;;;###autoload
1582(define-derived-mode ruby-mode prog-mode "Ruby" 1618(define-derived-mode ruby-mode prog-mode "Ruby"