Commit 19bb8e62 authored by Dmitry Gutov's avatar Dmitry Gutov

* lisp/progmodes/ruby-mode.el (ruby-syntax-expansion-allowed-p): New

function, checks if expression expansion is allowed in given parse
state.
(ruby-syntax-propertize-expansion): Use it.
(ruby-syntax-propertize-function): Bind `case-fold-search' to nil
around the body.

* test/automated/ruby-mode-tests.el: New tests, for percent literals
and expression expansion.
parent fc186a96
2013-05-31 Dmitry Gutov <dgutov@yandex.ru>
* progmodes/ruby-mode.el (ruby-syntax-expansion-allowed-p): New
function, checks if point is inside a literal that allows
expression expansion.
(ruby-syntax-propertize-expansion): Use it.
(ruby-syntax-propertize-function): Bind `case-fold-search' to nil
around the body.
2013-05-30 Juri Linkov <juri@jurta.org>
* isearch.el (isearch-mode-map): Bind `isearch-toggle-invisible'
......
......@@ -1349,6 +1349,7 @@ If the result is do-end block, it will always be multiline."
(declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit))
;; Unusual code layout confuses the byte-compiler.
(declare-function ruby-syntax-propertize-expansion "ruby-mode" ())
(declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state))
(if (eval-when-compile (fboundp #'syntax-propertize-rules))
;; New code that works independently from font-lock.
......@@ -1380,51 +1381,52 @@ It will be properly highlighted even when the call omits parens.")
(defun ruby-syntax-propertize-function (start end)
"Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
(goto-char start)
(remove-text-properties start end '(ruby-expansion-match-data))
(ruby-syntax-propertize-heredoc end)
(ruby-syntax-enclosing-percent-literal end)
(funcall
(syntax-propertize-rules
;; $' $" $` .... are variables.
;; ?' ?" ?` are ascii codes.
("\\([?$]\\)[#\"'`]"
(1 (unless (save-excursion
;; Not within a string.
(nth 3 (syntax-ppss (match-beginning 0))))
(string-to-syntax "\\"))))
;; Regular expressions. Start with matching unescaped slash.
("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
(1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
(when (or
;; Beginning of a regexp.
(and (null (nth 8 state))
(save-excursion
(forward-char -1)
(looking-back ruby-syntax-before-regexp-re
(point-at-bol))))
;; End of regexp. We don't match the whole
;; regexp at once because it can have
;; string interpolation inside, or span
;; several lines.
(eq ?/ (nth 3 state)))
(string-to-syntax "\"/")))))
;; Expression expansions in strings. We're handling them
;; here, so that the regexp rule never matches inside them.
(ruby-expression-expansion-re
(0 (ignore (ruby-syntax-propertize-expansion))))
("^=en\\(d\\)\\_>" (1 "!"))
("^\\(=\\)begin\\_>" (1 "!"))
;; Handle here documents.
((concat ruby-here-doc-beg-re ".*\\(\n\\)")
(7 (unless (ruby-singleton-class-p (match-beginning 0))
(put-text-property (match-beginning 7) (match-end 7)
'syntax-table (string-to-syntax "\""))
(ruby-syntax-propertize-heredoc end))))
;; Handle percent literals: %w(), %q{}, etc.
((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
(1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
(point) end))
(let (case-fold-search)
(goto-char start)
(remove-text-properties start end '(ruby-expansion-match-data))
(ruby-syntax-propertize-heredoc end)
(ruby-syntax-enclosing-percent-literal end)
(funcall
(syntax-propertize-rules
;; $' $" $` .... are variables.
;; ?' ?" ?` are ascii codes.
("\\([?$]\\)[#\"'`]"
(1 (unless (save-excursion
;; Not within a string.
(nth 3 (syntax-ppss (match-beginning 0))))
(string-to-syntax "\\"))))
;; Regular expressions. Start with matching unescaped slash.
("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
(1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
(when (or
;; Beginning of a regexp.
(and (null (nth 8 state))
(save-excursion
(forward-char -1)
(looking-back ruby-syntax-before-regexp-re
(point-at-bol))))
;; End of regexp. We don't match the whole
;; regexp at once because it can have
;; string interpolation inside, or span
;; several lines.
(eq ?/ (nth 3 state)))
(string-to-syntax "\"/")))))
;; Expression expansions in strings. We're handling them
;; here, so that the regexp rule never matches inside them.
(ruby-expression-expansion-re
(0 (ignore (ruby-syntax-propertize-expansion))))
("^=en\\(d\\)\\_>" (1 "!"))
("^\\(=\\)begin\\_>" (1 "!"))
;; Handle here documents.
((concat ruby-here-doc-beg-re ".*\\(\n\\)")
(7 (unless (ruby-singleton-class-p (match-beginning 0))
(put-text-property (match-beginning 7) (match-end 7)
'syntax-table (string-to-syntax "\""))
(ruby-syntax-propertize-heredoc end))))
;; Handle percent literals: %w(), %q{}, etc.
((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
(1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
(point) end)))
(defun ruby-syntax-propertize-heredoc (limit)
(let ((ppss (syntax-ppss))
......@@ -1496,9 +1498,10 @@ It will be properly highlighted even when the call omits parens.")
(defun ruby-syntax-propertize-expansion ()
;; Save the match data to a text property, for font-locking later.
;; Set the syntax of all double quotes and backticks to punctuation.
(let ((beg (match-beginning 2))
(end (match-end 2)))
(when (and beg (save-excursion (nth 3 (syntax-ppss beg))))
(let* ((beg (match-beginning 2))
(end (match-end 2))
(state (and beg (save-excursion (syntax-ppss beg)))))
(when (ruby-syntax-expansion-allowed-p state)
(put-text-property beg (1+ beg) 'ruby-expansion-match-data
(match-data))
(goto-char beg)
......@@ -1506,6 +1509,17 @@ It will be properly highlighted even when the call omits parens.")
(put-text-property (match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))))))
(defun ruby-syntax-expansion-allowed-p (parse-state)
"Return non-nil if expression expansion is allowed."
(let ((term (nth 3 parse-state)))
(cond
((memq term '(?\" ?` ?\n)))
((eq term t)
(save-match-data
(save-excursion
(goto-char (nth 8 parse-state))
(looking-at "%\\(?:[QWrx]\\|\\W\\)")))))))
(defun ruby-syntax-propertize-expansions (start end)
(save-excursion
(goto-char start)
......
2013-05-31 Dmitry Gutov <dgutov@yandex.ru>
* automated/ruby-mode-tests.el: New tests, for percent literals
and expression expansion.
2013-05-29 Leo Liu <sdl.web@gmail.com>
* indent/octave.m: Tweak.
......
......@@ -353,6 +353,23 @@ VALUES-PLIST is a list with alternating index and value elements."
;; It's confused by the closing paren in the middle.
(ruby-assert-state s 8 nil)))
(ert-deftest ruby-interpolation-inside-double-quoted-percent-literals ()
(ruby-assert-face "%Q{foo #@bar}" 8 font-lock-variable-name-face)
(ruby-assert-face "%W{foo #@bar}" 8 font-lock-variable-name-face)
(ruby-assert-face "%r{foo #@bar}" 8 font-lock-variable-name-face)
(ruby-assert-face "%x{foo #@bar}" 8 font-lock-variable-name-face))
(ert-deftest ruby-no-interpolation-in-single-quoted-literals ()
(ruby-assert-face "'foo #@bar'" 7 font-lock-string-face)
(ruby-assert-face "%q{foo #@bar}" 8 font-lock-string-face)
(ruby-assert-face "%w{foo #@bar}" 8 font-lock-string-face)
(ruby-assert-face "%s{foo #@bar}" 8 font-lock-string-face))
(ert-deftest ruby-no-unknown-percent-literals ()
;; No folding of case.
(ruby-assert-face "%S{foo}" 4 nil)
(ruby-assert-face "%R{foo}" 4 nil))
(ert-deftest ruby-add-log-current-method-examples ()
(let ((pairs '(("foo" . "#foo")
("C.foo" . ".foo")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment