diff options
Diffstat (limited to 'lisp/progmodes')
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 122 |
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. |
| 391 | OPTION specifies the type of the expression. | ||
| 392 | Can 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 |
| 869 | or blocks containing the current block." | 874 | current 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. |
| 911 | With ARG, move out of multiple blocks." | 931 | With 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" |