From: Dmitry Gutov Date: Wed, 14 Nov 2012 12:17:21 +0000 (+0400) Subject: * lisp/progmodes/ruby-mode.el X-Git-Tag: emacs-24.3.90~173^2~18^2~108 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=c62792e7dfa403db8c36cb92f32fb69258a199ef;p=emacs.git * lisp/progmodes/ruby-mode.el (ruby-syntax-propertize-function): After everything else, search for expansions in string literals, mark their insides as whitespace syntax and save match data for font-lock. (ruby-font-lock-keywords): Highlight just the 2nd group from expression expansion matches. (ruby-match-expression-expansion): Use the match data saved to the text property in ruby-syntax-propertize-function. * test/automated/ruby-mode-tests.el Change direct font-lock face references to var references. (ruby-interpolation-suppresses-syntax-inside): New test. (ruby-interpolation-inside-percent-literal-with-paren): New failing test. --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 19623bd06b7..99bfabb8115 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -2,6 +2,15 @@ * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection more strict. Add docstring. + (ruby-expression-expansion-re): Extract from + `ruby-match-expression-expansion'. + (ruby-syntax-propertize-function): After everything else, search + for expansions in string literals, mark their insides as + whitespace syntax and save match data for font-lock. + (ruby-font-lock-keywords): Use the 2nd group from expression + expansion matches. + (ruby-match-expression-expansion): Use the match data saved to the + text property in ruby-syntax-propertize-function. 2012-11-14 Stefan Monnier diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 686bec89a95..9d78b20ba4c 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -105,7 +105,10 @@ (eval-and-compile (defconst ruby-here-doc-beg-re "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" - "Regexp to match the beginning of a heredoc.")) + "Regexp to match the beginning of a heredoc.") + + (defconst ruby-expression-expansion-re + "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)")) (defun ruby-here-doc-end-match () "Return a regexp to find the end of a heredoc. @@ -1249,7 +1252,19 @@ It will be properly highlighted even when the call omits parens.")) ;; Handle percent literals: %w(), %q{}, etc. ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) - (point) end)) + (point) end) + (remove-text-properties start end '(ruby-expansion-match-data)) + (goto-char start) + ;; Find all expression expansions and + ;; - set the syntax of all text inside to whitespace, + ;; - save the match data to a text property, for font-locking later. + (while (re-search-forward ruby-expression-expansion-re end 'move) + (when (ruby-in-ppss-context-p 'string) + (put-text-property (match-beginning 2) (match-end 2) + 'syntax-table (string-to-syntax "-")) + (put-text-property (match-beginning 2) (1+ (match-beginning 2)) + 'ruby-expansion-match-data + (match-data))))) (defun ruby-syntax-propertize-heredoc (limit) (let ((ppss (syntax-ppss)) @@ -1582,7 +1597,7 @@ See `font-lock-syntax-table'.") '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-constant-face) ;; expression expansion '(ruby-match-expression-expansion - 0 font-lock-variable-name-face t) + 2 font-lock-variable-name-face t) ;; warn lower camel case ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" ; 0 font-lock-warning-face) @@ -1590,9 +1605,14 @@ 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) - (or (ruby-in-ppss-context-p 'string) - (ruby-match-expression-expansion limit)))) + (let ((prop 'ruby-expansion-match-data) pos value) + (when (and (setq pos (next-single-char-property-change (point) prop + nil limit)) + (> pos (point))) + (goto-char pos) + (or (and (setq value (get-text-property pos prop)) + (progn (set-match-data value) t)) + (ruby-match-expression-expansion limit))))) ;;;###autoload (define-derived-mode ruby-mode prog-mode "Ruby" diff --git a/test/ChangeLog b/test/ChangeLog index 5a796408a3b..f11325d0318 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -3,6 +3,10 @@ * automated/ruby-mode-tests.el (ruby-indent-singleton-class): Pass. (ruby-indent-inside-heredoc-after-operator) (ruby-indent-inside-heredoc-after-space): New tests. + Change direct font-lock face references to var references. + (ruby-interpolation-suppresses-syntax-inside): New test. + (ruby-interpolation-inside-percent-literal-with-paren): New + failing test. 2012-11-13 Dmitry Gutov diff --git a/test/automated/ruby-mode-tests.el b/test/automated/ruby-mode-tests.el index 7d633be0f53..ad48413b030 100644 --- a/test/automated/ruby-mode-tests.el +++ b/test/automated/ruby-mode-tests.el @@ -80,7 +80,7 @@ VALUES-PLIST is a list with alternating index and value elements." (ert-deftest ruby-heredoc-font-lock () (let ((s "foo <
  • #{@files.join(\"
  • \")}
  • \"")) + (ruby-assert-state s 8 nil) + (ruby-assert-face s 9 font-lock-string-face) + (ruby-assert-face s 10 font-lock-variable-name-face) + (ruby-assert-face s 41 font-lock-string-face))) + +(ert-deftest ruby-interpolation-inside-percent-literal-with-paren () + :expected-result :failed + (let ((s "%(^#{\")\"}^)")) + (ruby-assert-face s 3 font-lock-string-face) + (ruby-assert-face s 4 font-lock-variable-name-face) + (ruby-assert-face s 10 font-lock-string-face) + ;; It's confused by the closing paren in the middle. + (ruby-assert-state s 8 nil))) (ert-deftest ruby-add-log-current-method-examples () (let ((pairs '(("foo" . "#foo")