diff options
| author | Dmitry Gutov | 2012-09-07 08:15:56 +0400 |
|---|---|---|
| committer | Dmitry Gutov | 2012-09-07 08:15:56 +0400 |
| commit | 0ba2d4b6465b0b66d34e6ef47c151bd5920fbe54 (patch) | |
| tree | adb7447fb81dd81374d12a3765716b8d60e01fe6 | |
| parent | 1d43a35f49f7403f7f50f36dddf88167a7c81f11 (diff) | |
| download | emacs-0ba2d4b6465b0b66d34e6ef47c151bd5920fbe54.tar.gz emacs-0ba2d4b6465b0b66d34e6ef47c151bd5920fbe54.zip | |
* lisp/progmodes/ruby-mode.el (ruby-indent-beg-re): Add pieces from
ruby-beginning-of-indent, simplify, allow all keywords to have
indentation before them.
(ruby-beginning-of-indent): Adjust for above. Search until the
found point is not inside a string or comment.
(ruby-font-lock-keywords): Allow symbols to start with "@"
character, give them higher priority than variables.
(ruby-syntax-propertize-function)
(ruby-font-lock-syntactic-keywords): Remove the "not comments"
matchers. Expression expansions are not comments when inside a
string, and there comment syntax status is irrelevant.
(ruby-match-expression-expansion): New function. Check that
expression expansion is inside a string, and it's not escaped.
(ruby-font-lock-keywords): Use it.
* test/automated/ruby-mode-tests.el: New tests (Bug#11613).
| -rw-r--r-- | lisp/ChangeLog | 17 | ||||
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 38 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/ruby-mode-tests.el | 25 |
4 files changed, 65 insertions, 19 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 37064b6680b..2f7dac68467 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -51,6 +51,23 @@ | |||
| 51 | Let-bind `isearch-word' to the argument `delimited-flag'. | 51 | Let-bind `isearch-word' to the argument `delimited-flag'. |
| 52 | (Bug#10885, bug#10887) | 52 | (Bug#10885, bug#10887) |
| 53 | 53 | ||
| 54 | 2012-09-07 Dmitry Gutov <dgutov@yandex.ru> | ||
| 55 | |||
| 56 | * progmodes/ruby-mode.el (ruby-indent-beg-re): Add pieces from | ||
| 57 | ruby-beginning-of-indent, simplify, allow all keywords to have | ||
| 58 | indentation before them. | ||
| 59 | (ruby-beginning-of-indent): Adjust for above. Search until the | ||
| 60 | found point is not inside a string or comment. | ||
| 61 | (ruby-font-lock-keywords): Allow symbols to start with "@" | ||
| 62 | character, give them higher priority than variables. | ||
| 63 | (ruby-syntax-propertize-function) | ||
| 64 | (ruby-font-lock-syntactic-keywords): Remove the "not comments" | ||
| 65 | matchers. Expression expansions are not comments when inside a | ||
| 66 | string, and there comment syntax status is irrelevant. | ||
| 67 | (ruby-match-expression-expansion): New function. Check that | ||
| 68 | expression expansion is inside a string, and it's not escaped. | ||
| 69 | (ruby-font-lock-keywords): Use it. | ||
| 70 | |||
| 54 | 2012-09-05 Martin Rudalics <rudalics@gmx.at> | 71 | 2012-09-05 Martin Rudalics <rudalics@gmx.at> |
| 55 | 72 | ||
| 56 | * help.el (temp-buffer-max-height): New default value. | 73 | * help.el (temp-buffer-max-height): New default value. |
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 3f93ffa84ba..bcebada5e86 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el | |||
| @@ -64,8 +64,8 @@ | |||
| 64 | "Regexp to match keywords that nest without blocks.") | 64 | "Regexp to match keywords that nest without blocks.") |
| 65 | 65 | ||
| 66 | (defconst ruby-indent-beg-re | 66 | (defconst ruby-indent-beg-re |
| 67 | (concat "\\(\\s *" (regexp-opt '("class" "module" "def") t) "\\)\\|" | 67 | (concat "^\\s *" (regexp-opt '("class" "module" "def" "if" "unless" "case" |
| 68 | (regexp-opt '("if" "unless" "case" "while" "until" "for" "begin"))) | 68 | "while" "until" "for" "begin")) "\\_>") |
| 69 | "Regexp to match where the indentation gets deeper.") | 69 | "Regexp to match where the indentation gets deeper.") |
| 70 | 70 | ||
| 71 | (defconst ruby-modifier-beg-keywords | 71 | (defconst ruby-modifier-beg-keywords |
| @@ -848,19 +848,18 @@ move forward." | |||
| 848 | With ARG, move forward multiple defuns. Negative ARG means | 848 | With ARG, move forward multiple defuns. Negative ARG means |
| 849 | move backward." | 849 | move backward." |
| 850 | (interactive "p") | 850 | (interactive "p") |
| 851 | (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)") | 851 | (and (re-search-forward ruby-indent-beg-re nil 'move (or arg 1)) |
| 852 | nil 'move (or arg 1)) | ||
| 853 | (beginning-of-line)) | 852 | (beginning-of-line)) |
| 854 | (forward-line 1)) | 853 | (forward-line 1)) |
| 855 | 854 | ||
| 856 | (defun ruby-beginning-of-indent () | 855 | (defun ruby-beginning-of-indent () |
| 857 | "TODO: document" | 856 | "Backtrack to a line which can be used as a reference for |
| 858 | ;; I don't understand this function. | 857 | calculating indentation on the lines after it." |
| 859 | ;; It seems like it should move to the line where indentation should deepen, | 858 | (while (and (re-search-backward ruby-indent-beg-re nil 'move) |
| 860 | ;; but ruby-indent-beg-re only accounts for whitespace before class, module and def, | 859 | (if (ruby-in-ppss-context-p 'anything) |
| 861 | ;; so this will only match other block beginners at the beginning of the line. | 860 | t |
| 862 | (and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\_>") nil 'move) | 861 | ;; We can stop, then. |
| 863 | (beginning-of-line))) | 862 | (beginning-of-line))))) |
| 864 | 863 | ||
| 865 | (defun ruby-move-to-block (n) | 864 | (defun ruby-move-to-block (n) |
| 866 | "Move to the beginning (N < 0) or the end (N > 0) of the current block | 865 | "Move to the beginning (N < 0) or the end (N > 0) of the current block |
| @@ -1171,8 +1170,6 @@ It will be properly highlighted even when the call omits parens.")) | |||
| 1171 | (ruby-syntax-enclosing-percent-literal end) | 1170 | (ruby-syntax-enclosing-percent-literal end) |
| 1172 | (funcall | 1171 | (funcall |
| 1173 | (syntax-propertize-rules | 1172 | (syntax-propertize-rules |
| 1174 | ;; #{ }, #$hoge, #@foo are not comments. | ||
| 1175 | ("\\(#\\)[{$@]" (1 ".")) | ||
| 1176 | ;; $' $" $` .... are variables. | 1173 | ;; $' $" $` .... are variables. |
| 1177 | ;; ?' ?" ?` are ascii codes. | 1174 | ;; ?' ?" ?` are ascii codes. |
| 1178 | ("\\([?$]\\)[#\"'`]" | 1175 | ("\\([?$]\\)[#\"'`]" |
| @@ -1304,8 +1301,7 @@ This should only be called after matching against `ruby-here-doc-end-re'." | |||
| 1304 | (concat "-?\\([\"']\\|\\)" contents "\\1")))))) | 1301 | (concat "-?\\([\"']\\|\\)" contents "\\1")))))) |
| 1305 | 1302 | ||
| 1306 | (defconst ruby-font-lock-syntactic-keywords | 1303 | (defconst ruby-font-lock-syntactic-keywords |
| 1307 | `( ;; #{ }, #$hoge, #@foo are not comments | 1304 | `( |
| 1308 | ("\\(#\\)[{$@]" 1 (1 . nil)) | ||
| 1309 | ;; the last $', $", $` in the respective string is not variable | 1305 | ;; the last $', $", $` in the respective string is not variable |
| 1310 | ;; the last ?', ?", ?` in the respective string is not ascii code | 1306 | ;; the last ?', ?", ?` in the respective string is not ascii code |
| 1311 | ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" | 1307 | ("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)" |
| @@ -1527,6 +1523,9 @@ See `font-lock-syntax-table'.") | |||
| 1527 | ;; variables | 1523 | ;; variables |
| 1528 | '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>" | 1524 | '("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>" |
| 1529 | 2 font-lock-variable-name-face) | 1525 | 2 font-lock-variable-name-face) |
| 1526 | ;; symbols | ||
| 1527 | '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|@?\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)" | ||
| 1528 | 2 font-lock-reference-face) | ||
| 1530 | ;; variables | 1529 | ;; variables |
| 1531 | '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W" | 1530 | '("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W" |
| 1532 | 1 font-lock-variable-name-face) | 1531 | 1 font-lock-variable-name-face) |
| @@ -1535,12 +1534,9 @@ See `font-lock-syntax-table'.") | |||
| 1535 | ;; constants | 1534 | ;; constants |
| 1536 | '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" | 1535 | '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" |
| 1537 | 2 font-lock-type-face) | 1536 | 2 font-lock-type-face) |
| 1538 | ;; symbols | ||
| 1539 | '("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)" | ||
| 1540 | 2 font-lock-reference-face) | ||
| 1541 | '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face) | 1537 | '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face) |
| 1542 | ;; expression expansion | 1538 | ;; expression expansion |
| 1543 | '("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)" | 1539 | '(ruby-match-expression-expansion |
| 1544 | 0 font-lock-variable-name-face t) | 1540 | 0 font-lock-variable-name-face t) |
| 1545 | ;; warn lower camel case | 1541 | ;; warn lower camel case |
| 1546 | ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" | 1542 | ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" |
| @@ -1548,6 +1544,10 @@ See `font-lock-syntax-table'.") | |||
| 1548 | ) | 1544 | ) |
| 1549 | "Additional expressions to highlight in Ruby mode.") | 1545 | "Additional expressions to highlight in Ruby mode.") |
| 1550 | 1546 | ||
| 1547 | (defun ruby-match-expression-expansion (limit) | ||
| 1548 | (when (re-search-forward "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)" limit 'move) | ||
| 1549 | (ruby-in-ppss-context-p 'string))) | ||
| 1550 | |||
| 1551 | ;;;###autoload | 1551 | ;;;###autoload |
| 1552 | (define-derived-mode ruby-mode prog-mode "Ruby" | 1552 | (define-derived-mode ruby-mode prog-mode "Ruby" |
| 1553 | "Major mode for editing Ruby scripts. | 1553 | "Major mode for editing Ruby scripts. |
diff --git a/test/ChangeLog b/test/ChangeLog index f523f6f59a9..541937ec4e7 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2012-09-07 Dmitry Gutov <dgutov@yandex.ru> | ||
| 2 | |||
| 3 | * automated/ruby-mode-tests.el: New tests (Bug#11613). | ||
| 4 | |||
| 1 | 2012-08-28 Chong Yidong <cyd@gnu.org> | 5 | 2012-08-28 Chong Yidong <cyd@gnu.org> |
| 2 | 6 | ||
| 3 | * automated/files.el: Test every combination of values for | 7 | * automated/files.el: Test every combination of values for |
diff --git a/test/automated/ruby-mode-tests.el b/test/automated/ruby-mode-tests.el index df51aa0d15a..1adc4acdfa0 100644 --- a/test/automated/ruby-mode-tests.el +++ b/test/automated/ruby-mode-tests.el | |||
| @@ -57,6 +57,13 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 57 | (cadr values-plist))) | 57 | (cadr values-plist))) |
| 58 | (setq values-plist (cddr values-plist))))) | 58 | (setq values-plist (cddr values-plist))))) |
| 59 | 59 | ||
| 60 | (defun ruby-assert-face (content pos face) | ||
| 61 | (with-temp-buffer | ||
| 62 | (insert content) | ||
| 63 | (ruby-mode) | ||
| 64 | (font-lock-fontify-buffer) | ||
| 65 | (should (eq face (get-text-property pos 'face))))) | ||
| 66 | |||
| 60 | (ert-deftest ruby-indent-after-symbol-made-from-string-interpolation () | 67 | (ert-deftest ruby-indent-after-symbol-made-from-string-interpolation () |
| 61 | "It can indent the line after symbol made using string interpolation." | 68 | "It can indent the line after symbol made using string interpolation." |
| 62 | (ruby-should-indent "def foo(suffix)\n :\"bar#{suffix}\"\n" | 69 | (ruby-should-indent "def foo(suffix)\n :\"bar#{suffix}\"\n" |
| @@ -84,6 +91,11 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 84 | (ruby-should-indent "foo = {\na: b" ruby-indent-level) | 91 | (ruby-should-indent "foo = {\na: b" ruby-indent-level) |
| 85 | (ruby-should-indent "foo(\na" ruby-indent-level))) | 92 | (ruby-should-indent "foo(\na" ruby-indent-level))) |
| 86 | 93 | ||
| 94 | (ert-deftest ruby-indent-after-keyword-in-a-string () | ||
| 95 | (ruby-should-indent "a = \"abc\nif\"\n " 0) | ||
| 96 | (ruby-should-indent "a = %w[abc\n def]\n " 0) | ||
| 97 | (ruby-should-indent "a = \"abc\n def\"\n " 0)) | ||
| 98 | |||
| 87 | (ert-deftest ruby-indent-simple () | 99 | (ert-deftest ruby-indent-simple () |
| 88 | (ruby-should-indent-buffer | 100 | (ruby-should-indent-buffer |
| 89 | "if foo | 101 | "if foo |
| @@ -217,6 +229,19 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 217 | (should (string= "foo {|b|\n}\n" (buffer-substring-no-properties | 229 | (should (string= "foo {|b|\n}\n" (buffer-substring-no-properties |
| 218 | (point-min) (point-max)))))) | 230 | (point-min) (point-max)))))) |
| 219 | 231 | ||
| 232 | (ert-deftest ruby-recognize-symbols-starting-with-at-character () | ||
| 233 | (ruby-assert-face ":@abc" 3 'font-lock-constant-face)) | ||
| 234 | |||
| 235 | (ert-deftest ruby-hash-character-not-interpolation () | ||
| 236 | (ruby-assert-face "\"This is #{interpolation}\"" 15 | ||
| 237 | 'font-lock-variable-name-face) | ||
| 238 | (ruby-assert-face "\"This is \\#{no interpolation} despite the #\"" | ||
| 239 | 15 'font-lock-string-face) | ||
| 240 | (ruby-assert-face "#@comment, not ruby code" 3 'font-lock-comment-face) | ||
| 241 | (ruby-assert-state "#@comment, not ruby code" 4 t) | ||
| 242 | (ruby-assert-face "# A comment cannot have #{an interpolation} in it" | ||
| 243 | 30 'font-lock-comment-face)) | ||
| 244 | |||
| 220 | (provide 'ruby-mode-tests) | 245 | (provide 'ruby-mode-tests) |
| 221 | 246 | ||
| 222 | ;;; ruby-mode-tests.el ends here | 247 | ;;; ruby-mode-tests.el ends here |