* 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).
This commit is contained in:
Dmitry Gutov 2012-09-07 08:15:56 +04:00
parent 1d43a35f49
commit 0ba2d4b646
4 changed files with 65 additions and 19 deletions

View file

@ -51,6 +51,23 @@
Let-bind `isearch-word' to the argument `delimited-flag'.
(Bug#10885, bug#10887)
2012-09-07 Dmitry Gutov <dgutov@yandex.ru>
* 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.
2012-09-05 Martin Rudalics <rudalics@gmx.at>
* help.el (temp-buffer-max-height): New default value.

View file

@ -64,8 +64,8 @@
"Regexp to match keywords that nest without blocks.")
(defconst ruby-indent-beg-re
(concat "\\(\\s *" (regexp-opt '("class" "module" "def") t) "\\)\\|"
(regexp-opt '("if" "unless" "case" "while" "until" "for" "begin")))
(concat "^\\s *" (regexp-opt '("class" "module" "def" "if" "unless" "case"
"while" "until" "for" "begin")) "\\_>")
"Regexp to match where the indentation gets deeper.")
(defconst ruby-modifier-beg-keywords
@ -848,19 +848,18 @@ move forward."
With ARG, move forward multiple defuns. Negative ARG means
move backward."
(interactive "p")
(and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\($\\|\\b[^_]\\)")
nil 'move (or arg 1))
(and (re-search-forward ruby-indent-beg-re nil 'move (or arg 1))
(beginning-of-line))
(forward-line 1))
(defun ruby-beginning-of-indent ()
"TODO: document"
;; I don't understand this function.
;; It seems like it should move to the line where indentation should deepen,
;; but ruby-indent-beg-re only accounts for whitespace before class, module and def,
;; so this will only match other block beginners at the beginning of the line.
(and (re-search-backward (concat "^\\(" ruby-indent-beg-re "\\)\\_>") nil 'move)
(beginning-of-line)))
"Backtrack to a line which can be used as a reference for
calculating indentation on the lines after it."
(while (and (re-search-backward ruby-indent-beg-re nil 'move)
(if (ruby-in-ppss-context-p 'anything)
t
;; We can stop, then.
(beginning-of-line)))))
(defun ruby-move-to-block (n)
"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."))
(ruby-syntax-enclosing-percent-literal end)
(funcall
(syntax-propertize-rules
;; #{ }, #$hoge, #@foo are not comments.
("\\(#\\)[{$@]" (1 "."))
;; $' $" $` .... are variables.
;; ?' ?" ?` are ascii codes.
("\\([?$]\\)[#\"'`]"
@ -1304,8 +1301,7 @@ This should only be called after matching against `ruby-here-doc-end-re'."
(concat "-?\\([\"']\\|\\)" contents "\\1"))))))
(defconst ruby-font-lock-syntactic-keywords
`( ;; #{ }, #$hoge, #@foo are not comments
("\\(#\\)[{$@]" 1 (1 . nil))
`(
;; the last $', $", $` in the respective string is not variable
;; the last ?', ?", ?` in the respective string is not ascii code
("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
@ -1527,6 +1523,9 @@ See `font-lock-syntax-table'.")
;; variables
'("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>"
2 font-lock-variable-name-face)
;; symbols
'("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|@?\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
2 font-lock-reference-face)
;; variables
'("\\(\\$\\([^a-zA-Z0-9 \n]\\|[0-9]\\)\\)\\W"
1 font-lock-variable-name-face)
@ -1535,12 +1534,9 @@ See `font-lock-syntax-table'.")
;; constants
'("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
2 font-lock-type-face)
;; symbols
'("\\(^\\|[^:]\\)\\(:\\([-+~]@?\\|[/%&|^`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|![~=]?\\|\\[\\]=?\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b_*\\)\\|#{[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\)\\)"
2 font-lock-reference-face)
'("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-reference-face)
;; expression expansion
'("#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)"
'(ruby-match-expression-expansion
0 font-lock-variable-name-face t)
;; warn lower camel case
;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)"
@ -1548,6 +1544,10 @@ See `font-lock-syntax-table'.")
)
"Additional expressions to highlight in Ruby mode.")
(defun ruby-match-expression-expansion (limit)
(when (re-search-forward "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)" limit 'move)
(ruby-in-ppss-context-p 'string)))
;;;###autoload
(define-derived-mode ruby-mode prog-mode "Ruby"
"Major mode for editing Ruby scripts.

View file

@ -1,3 +1,7 @@
2012-09-07 Dmitry Gutov <dgutov@yandex.ru>
* automated/ruby-mode-tests.el: New tests (Bug#11613).
2012-08-28 Chong Yidong <cyd@gnu.org>
* automated/files.el: Test every combination of values for

View file

@ -57,6 +57,13 @@ VALUES-PLIST is a list with alternating index and value elements."
(cadr values-plist)))
(setq values-plist (cddr values-plist)))))
(defun ruby-assert-face (content pos face)
(with-temp-buffer
(insert content)
(ruby-mode)
(font-lock-fontify-buffer)
(should (eq face (get-text-property pos 'face)))))
(ert-deftest ruby-indent-after-symbol-made-from-string-interpolation ()
"It can indent the line after symbol made using string interpolation."
(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."
(ruby-should-indent "foo = {\na: b" ruby-indent-level)
(ruby-should-indent "foo(\na" ruby-indent-level)))
(ert-deftest ruby-indent-after-keyword-in-a-string ()
(ruby-should-indent "a = \"abc\nif\"\n " 0)
(ruby-should-indent "a = %w[abc\n def]\n " 0)
(ruby-should-indent "a = \"abc\n def\"\n " 0))
(ert-deftest ruby-indent-simple ()
(ruby-should-indent-buffer
"if foo
@ -217,6 +229,19 @@ VALUES-PLIST is a list with alternating index and value elements."
(should (string= "foo {|b|\n}\n" (buffer-substring-no-properties
(point-min) (point-max))))))
(ert-deftest ruby-recognize-symbols-starting-with-at-character ()
(ruby-assert-face ":@abc" 3 'font-lock-constant-face))
(ert-deftest ruby-hash-character-not-interpolation ()
(ruby-assert-face "\"This is #{interpolation}\"" 15
'font-lock-variable-name-face)
(ruby-assert-face "\"This is \\#{no interpolation} despite the #\""
15 'font-lock-string-face)
(ruby-assert-face "#@comment, not ruby code" 3 'font-lock-comment-face)
(ruby-assert-state "#@comment, not ruby code" 4 t)
(ruby-assert-face "# A comment cannot have #{an interpolation} in it"
30 'font-lock-comment-face))
(provide 'ruby-mode-tests)
;;; ruby-mode-tests.el ends here