diff options
| author | Dmitry Gutov | 2012-11-14 16:17:21 +0400 |
|---|---|---|
| committer | Dmitry Gutov | 2012-11-14 16:17:21 +0400 |
| commit | c62792e7dfa403db8c36cb92f32fb69258a199ef (patch) | |
| tree | b66f89060cd2f882a04b508896cbbbd424b08412 | |
| parent | 710f581278f6eaea5dbc5c0bcc7c206be9690746 (diff) | |
| download | emacs-c62792e7dfa403db8c36cb92f32fb69258a199ef.tar.gz emacs-c62792e7dfa403db8c36cb92f32fb69258a199ef.zip | |
* 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.
| -rw-r--r-- | lisp/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 32 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/ruby-mode-tests.el | 30 |
4 files changed, 62 insertions, 13 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 19623bd06b7..99bfabb8115 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -2,6 +2,15 @@ | |||
| 2 | 2 | ||
| 3 | * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection | 3 | * progmodes/ruby-mode.el (ruby-expr-beg): Make heredoc detection |
| 4 | more strict. Add docstring. | 4 | more strict. Add docstring. |
| 5 | (ruby-expression-expansion-re): Extract from | ||
| 6 | `ruby-match-expression-expansion'. | ||
| 7 | (ruby-syntax-propertize-function): After everything else, search | ||
| 8 | for expansions in string literals, mark their insides as | ||
| 9 | whitespace syntax and save match data for font-lock. | ||
| 10 | (ruby-font-lock-keywords): Use the 2nd group from expression | ||
| 11 | expansion matches. | ||
| 12 | (ruby-match-expression-expansion): Use the match data saved to the | ||
| 13 | text property in ruby-syntax-propertize-function. | ||
| 5 | 14 | ||
| 6 | 2012-11-14 Stefan Monnier <monnier@iro.umontreal.ca> | 15 | 2012-11-14 Stefan Monnier <monnier@iro.umontreal.ca> |
| 7 | 16 | ||
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 @@ | |||
| 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. |
| @@ -1249,7 +1252,19 @@ It will be properly highlighted even when the call omits parens.")) | |||
| 1249 | ;; Handle percent literals: %w(), %q{}, etc. | 1252 | ;; Handle percent literals: %w(), %q{}, etc. |
| 1250 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) | 1253 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) |
| 1251 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) | 1254 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) |
| 1252 | (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))))) | ||
| 1253 | 1268 | ||
| 1254 | (defun ruby-syntax-propertize-heredoc (limit) | 1269 | (defun ruby-syntax-propertize-heredoc (limit) |
| 1255 | (let ((ppss (syntax-ppss)) | 1270 | (let ((ppss (syntax-ppss)) |
| @@ -1582,7 +1597,7 @@ See `font-lock-syntax-table'.") | |||
| 1582 | '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-constant-face) | 1597 | '("\\(^\\s *\\|[\[\{\(,]\\s *\\|\\sw\\s +\\)\\(\\(\\sw\\|_\\)+\\):[^:]" 2 font-lock-constant-face) |
| 1583 | ;; expression expansion | 1598 | ;; expression expansion |
| 1584 | '(ruby-match-expression-expansion | 1599 | '(ruby-match-expression-expansion |
| 1585 | 0 font-lock-variable-name-face t) | 1600 | 2 font-lock-variable-name-face t) |
| 1586 | ;; warn lower camel case | 1601 | ;; warn lower camel case |
| 1587 | ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" | 1602 | ;'("\\<[a-z]+[a-z0-9]*[A-Z][A-Za-z0-9]*\\([!?]?\\|\\>\\)" |
| 1588 | ; 0 font-lock-warning-face) | 1603 | ; 0 font-lock-warning-face) |
| @@ -1590,9 +1605,14 @@ See `font-lock-syntax-table'.") | |||
| 1590 | "Additional expressions to highlight in Ruby mode.") | 1605 | "Additional expressions to highlight in Ruby mode.") |
| 1591 | 1606 | ||
| 1592 | (defun ruby-match-expression-expansion (limit) | 1607 | (defun ruby-match-expression-expansion (limit) |
| 1593 | (when (re-search-forward "[^\\]\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\)\\)" limit 'move) | 1608 | (let ((prop 'ruby-expansion-match-data) pos value) |
| 1594 | (or (ruby-in-ppss-context-p 'string) | 1609 | (when (and (setq pos (next-single-char-property-change (point) prop |
| 1595 | (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))))) | ||
| 1596 | 1616 | ||
| 1597 | ;;;###autoload | 1617 | ;;;###autoload |
| 1598 | (define-derived-mode ruby-mode prog-mode "Ruby" | 1618 | (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 @@ | |||
| 3 | * automated/ruby-mode-tests.el (ruby-indent-singleton-class): Pass. | 3 | * automated/ruby-mode-tests.el (ruby-indent-singleton-class): Pass. |
| 4 | (ruby-indent-inside-heredoc-after-operator) | 4 | (ruby-indent-inside-heredoc-after-operator) |
| 5 | (ruby-indent-inside-heredoc-after-space): New tests. | 5 | (ruby-indent-inside-heredoc-after-space): New tests. |
| 6 | Change direct font-lock face references to var references. | ||
| 7 | (ruby-interpolation-suppresses-syntax-inside): New test. | ||
| 8 | (ruby-interpolation-inside-percent-literal-with-paren): New | ||
| 9 | failing test. | ||
| 6 | 10 | ||
| 7 | 2012-11-13 Dmitry Gutov <dgutov@yandex.ru> | 11 | 2012-11-13 Dmitry Gutov <dgutov@yandex.ru> |
| 8 | 12 | ||
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." | |||
| 80 | 80 | ||
| 81 | (ert-deftest ruby-heredoc-font-lock () | 81 | (ert-deftest ruby-heredoc-font-lock () |
| 82 | (let ((s "foo <<eos.gsub('^ *', '')")) | 82 | (let ((s "foo <<eos.gsub('^ *', '')")) |
| 83 | (ruby-assert-face s 9 'font-lock-string-face) | 83 | (ruby-assert-face s 9 font-lock-string-face) |
| 84 | (ruby-assert-face s 10 nil))) | 84 | (ruby-assert-face s 10 nil))) |
| 85 | 85 | ||
| 86 | (ert-deftest ruby-singleton-class-no-heredoc-font-lock () | 86 | (ert-deftest ruby-singleton-class-no-heredoc-font-lock () |
| @@ -262,19 +262,35 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 262 | (should (string= "foo do |b|\n b + 1\nend" (buffer-string))))) | 262 | (should (string= "foo do |b|\n b + 1\nend" (buffer-string))))) |
| 263 | 263 | ||
| 264 | (ert-deftest ruby-recognize-symbols-starting-with-at-character () | 264 | (ert-deftest ruby-recognize-symbols-starting-with-at-character () |
| 265 | (ruby-assert-face ":@abc" 3 'font-lock-constant-face)) | 265 | (ruby-assert-face ":@abc" 3 font-lock-constant-face)) |
| 266 | 266 | ||
| 267 | (ert-deftest ruby-hash-character-not-interpolation () | 267 | (ert-deftest ruby-hash-character-not-interpolation () |
| 268 | (ruby-assert-face "\"This is #{interpolation}\"" 15 | 268 | (ruby-assert-face "\"This is #{interpolation}\"" 15 |
| 269 | 'font-lock-variable-name-face) | 269 | font-lock-variable-name-face) |
| 270 | (ruby-assert-face "\"This is \\#{no interpolation} despite the #\"" | 270 | (ruby-assert-face "\"This is \\#{no interpolation} despite the #\"" |
| 271 | 15 'font-lock-string-face) | 271 | 15 font-lock-string-face) |
| 272 | (ruby-assert-face "\n#@comment, not ruby code" 5 'font-lock-comment-face) | 272 | (ruby-assert-face "\n#@comment, not ruby code" 5 font-lock-comment-face) |
| 273 | (ruby-assert-state "\n#@comment, not ruby code" 4 t) | 273 | (ruby-assert-state "\n#@comment, not ruby code" 4 t) |
| 274 | (ruby-assert-face "# A comment cannot have #{an interpolation} in it" | 274 | (ruby-assert-face "# A comment cannot have #{an interpolation} in it" |
| 275 | 30 'font-lock-comment-face) | 275 | 30 font-lock-comment-face) |
| 276 | (ruby-assert-face "# #{comment}\n \"#{interpolation}\"" 16 | 276 | (ruby-assert-face "# #{comment}\n \"#{interpolation}\"" 16 |
| 277 | 'font-lock-variable-name-face)) | 277 | font-lock-variable-name-face)) |
| 278 | |||
| 279 | (ert-deftest ruby-interpolation-suppresses-syntax-inside () | ||
| 280 | (let ((s "\"<ul><li>#{@files.join(\"</li><li>\")}</li></ul>\"")) | ||
| 281 | (ruby-assert-state s 8 nil) | ||
| 282 | (ruby-assert-face s 9 font-lock-string-face) | ||
| 283 | (ruby-assert-face s 10 font-lock-variable-name-face) | ||
| 284 | (ruby-assert-face s 41 font-lock-string-face))) | ||
| 285 | |||
| 286 | (ert-deftest ruby-interpolation-inside-percent-literal-with-paren () | ||
| 287 | :expected-result :failed | ||
| 288 | (let ((s "%(^#{\")\"}^)")) | ||
| 289 | (ruby-assert-face s 3 font-lock-string-face) | ||
| 290 | (ruby-assert-face s 4 font-lock-variable-name-face) | ||
| 291 | (ruby-assert-face s 10 font-lock-string-face) | ||
| 292 | ;; It's confused by the closing paren in the middle. | ||
| 293 | (ruby-assert-state s 8 nil))) | ||
| 278 | 294 | ||
| 279 | (ert-deftest ruby-add-log-current-method-examples () | 295 | (ert-deftest ruby-add-log-current-method-examples () |
| 280 | (let ((pairs '(("foo" . "#foo") | 296 | (let ((pairs '(("foo" . "#foo") |