* lisp/progmodes/ruby-mode.el Use `syntax-propertize-function'
unconditionally. Remove now unnecessary forward declarations. Remove XEmacs-specific setup. (ruby-here-doc-end-re, ruby-here-doc-beg-match) (ruby-font-lock-syntactic-keywords) (ruby-comment-beg-syntax, ruby-in-here-doc-p) (ruby-here-doc-find-end, ruby-here-doc-beg-syntax) (ruby-here-doc-end-syntax): Remove. (ruby-mode): Don't check whether `syntax-propertize-rules' is defined as function.
This commit is contained in:
parent
a3996a2eba
commit
7ffd37219b
2 changed files with 178 additions and 342 deletions
|
@ -1,3 +1,16 @@
|
|||
2013-11-02 Dmitry Gutov <dgutov@yandex.ru>
|
||||
|
||||
* progmodes/ruby-mode.el Use `syntax-propertize-function'
|
||||
unconditionally. Remove now unnecessary forward declarations.
|
||||
Remove XEmacs-specific setup.
|
||||
(ruby-here-doc-end-re, ruby-here-doc-beg-match)
|
||||
(ruby-font-lock-syntactic-keywords)
|
||||
(ruby-comment-beg-syntax, ruby-in-here-doc-p)
|
||||
(ruby-here-doc-find-end, ruby-here-doc-beg-syntax)
|
||||
(ruby-here-doc-end-syntax): Remove.
|
||||
(ruby-mode): Don't check whether `syntax-propertize-rules' is
|
||||
defined as function.
|
||||
|
||||
2013-11-02 Bozhidar Batsov <bozhidar@batsov.com>
|
||||
|
||||
* progmodes/ruby-mode.el (ruby-mode-variables, ruby-mode): Use `setq-local'.
|
||||
|
|
|
@ -1515,349 +1515,182 @@ If the result is do-end block, it will always be multiline."
|
|||
(ruby-do-end-to-brace beg end)))
|
||||
(goto-char start))))
|
||||
|
||||
(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit))
|
||||
(declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit))
|
||||
(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))
|
||||
(declare-function ruby-syntax-propertize-function "ruby-mode" (start end))
|
||||
(eval-and-compile
|
||||
(defconst ruby-percent-literal-beg-re
|
||||
"\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
|
||||
"Regexp to match the beginning of percent literal.")
|
||||
|
||||
(if (eval-when-compile (fboundp #'syntax-propertize-rules))
|
||||
;; New code that works independently from font-lock.
|
||||
(progn
|
||||
(eval-and-compile
|
||||
(defconst ruby-percent-literal-beg-re
|
||||
"\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
|
||||
"Regexp to match the beginning of percent literal.")
|
||||
|
||||
(defconst ruby-syntax-methods-before-regexp
|
||||
'("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
|
||||
"assert_match" "Given" "Then" "When")
|
||||
"Methods that can take regexp as the first argument.
|
||||
(defconst ruby-syntax-methods-before-regexp
|
||||
'("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
|
||||
"assert_match" "Given" "Then" "When")
|
||||
"Methods that can take regexp as the first argument.
|
||||
It will be properly highlighted even when the call omits parens.")
|
||||
|
||||
(defvar ruby-syntax-before-regexp-re
|
||||
(concat
|
||||
;; Special tokens that can't be followed by a division operator.
|
||||
"\\(^\\|[[=(,~;<>]"
|
||||
;; Distinguish ternary operator tokens.
|
||||
;; FIXME: They don't really have to be separated with spaces.
|
||||
"\\|[?:] "
|
||||
;; Control flow keywords and operators following bol or whitespace.
|
||||
"\\|\\(?:^\\|\\s \\)"
|
||||
(regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
|
||||
"or" "not" "&&" "||"))
|
||||
;; Method name from the list.
|
||||
"\\|\\_<"
|
||||
(regexp-opt ruby-syntax-methods-before-regexp)
|
||||
"\\)\\s *")
|
||||
"Regexp to match text that can be followed by a regular expression."))
|
||||
(defvar ruby-syntax-before-regexp-re
|
||||
(concat
|
||||
;; Special tokens that can't be followed by a division operator.
|
||||
"\\(^\\|[[=(,~;<>]"
|
||||
;; Distinguish ternary operator tokens.
|
||||
;; FIXME: They don't really have to be separated with spaces.
|
||||
"\\|[?:] "
|
||||
;; Control flow keywords and operators following bol or whitespace.
|
||||
"\\|\\(?:^\\|\\s \\)"
|
||||
(regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
|
||||
"or" "not" "&&" "||"))
|
||||
;; Method name from the list.
|
||||
"\\|\\_<"
|
||||
(regexp-opt ruby-syntax-methods-before-regexp)
|
||||
"\\)\\s *")
|
||||
"Regexp to match text that can be followed by a regular expression."))
|
||||
|
||||
(defun ruby-syntax-propertize-function (start end)
|
||||
"Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
|
||||
(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 character literals (one-char strings in 1.9+).
|
||||
("\\([?$]\\)[#\"'`]"
|
||||
(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 (or (nth 8 (save-excursion
|
||||
(syntax-ppss (match-beginning 0))))
|
||||
(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-function (start end)
|
||||
"Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
|
||||
(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 character literals (one-char strings in 1.9+).
|
||||
("\\([?$]\\)[#\"'`]"
|
||||
(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 (or (nth 8 (save-excursion
|
||||
(syntax-ppss (match-beginning 0))))
|
||||
(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))
|
||||
(res '()))
|
||||
(when (eq ?\n (nth 3 ppss))
|
||||
(save-excursion
|
||||
(goto-char (nth 8 ppss))
|
||||
(beginning-of-line)
|
||||
(while (re-search-forward ruby-here-doc-beg-re
|
||||
(line-end-position) t)
|
||||
(unless (ruby-singleton-class-p (match-beginning 0))
|
||||
(push (concat (ruby-here-doc-end-match) "\n") res))))
|
||||
(save-excursion
|
||||
;; With multiple openers on the same line, we don't know in which
|
||||
;; part `start' is, so we have to go back to the beginning.
|
||||
(when (cdr res)
|
||||
(goto-char (nth 8 ppss))
|
||||
(setq res (nreverse res)))
|
||||
(while (and res (re-search-forward (pop res) limit 'move))
|
||||
(if (null res)
|
||||
(put-text-property (1- (point)) (point)
|
||||
'syntax-table (string-to-syntax "\""))))
|
||||
;; End up at bol following the heredoc openers.
|
||||
;; Propertize expression expansions from this point forward.
|
||||
))))
|
||||
|
||||
(defun ruby-syntax-enclosing-percent-literal (limit)
|
||||
(let ((state (syntax-ppss))
|
||||
(start (point)))
|
||||
;; When already inside percent literal, re-propertize it.
|
||||
(when (eq t (nth 3 state))
|
||||
(goto-char (nth 8 state))
|
||||
(when (looking-at ruby-percent-literal-beg-re)
|
||||
(ruby-syntax-propertize-percent-literal limit))
|
||||
(when (< (point) start) (goto-char start)))))
|
||||
|
||||
(defun ruby-syntax-propertize-percent-literal (limit)
|
||||
(goto-char (match-beginning 2))
|
||||
;; Not inside a simple string or comment.
|
||||
(when (eq t (nth 3 (syntax-ppss)))
|
||||
(let* ((op (char-after))
|
||||
(ops (char-to-string op))
|
||||
(cl (or (cdr (aref (syntax-table) op))
|
||||
(cdr (assoc op '((?< . ?>))))))
|
||||
parse-sexp-lookup-properties)
|
||||
(save-excursion
|
||||
(condition-case nil
|
||||
(progn
|
||||
(if cl ; Paired delimiters.
|
||||
;; Delimiter pairs of the same kind can be nested
|
||||
;; inside the literal, as long as they are balanced.
|
||||
;; Create syntax table that ignores other characters.
|
||||
(with-syntax-table (make-char-table 'syntax-table nil)
|
||||
(modify-syntax-entry op (concat "(" (char-to-string cl)))
|
||||
(modify-syntax-entry cl (concat ")" ops))
|
||||
(modify-syntax-entry ?\\ "\\")
|
||||
(save-restriction
|
||||
(narrow-to-region (point) limit)
|
||||
(forward-list))) ; skip to the paired character
|
||||
;; Single character delimiter.
|
||||
(re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
|
||||
(regexp-quote ops)) limit nil))
|
||||
;; Found the closing delimiter.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table
|
||||
(string-to-syntax "|")))
|
||||
;; Unclosed literal, do nothing.
|
||||
((scan-error search-failed)))))))
|
||||
|
||||
(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))
|
||||
(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)
|
||||
(while (re-search-forward "[\"`]" end 'move)
|
||||
(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 "%\\(?:[QWrxI]\\|\\W\\)")))))))
|
||||
|
||||
(defun ruby-syntax-propertize-expansions (start end)
|
||||
(save-excursion
|
||||
(goto-char start)
|
||||
(while (re-search-forward ruby-expression-expansion-re end 'move)
|
||||
(ruby-syntax-propertize-expansion))))
|
||||
)
|
||||
|
||||
;; For Emacsen where syntax-propertize-rules is not (yet) available,
|
||||
;; fallback on the old font-lock-syntactic-keywords stuff.
|
||||
|
||||
(defconst ruby-here-doc-end-re
|
||||
"^\\([ \t]+\\)?\\(.*\\)\\(\n\\)"
|
||||
"Regexp to match the end of heredocs.
|
||||
|
||||
This will actually match any line with one or more characters.
|
||||
It's useful in that it divides up the match string so that
|
||||
`ruby-here-doc-beg-match' can search for the beginning of the heredoc.")
|
||||
|
||||
(defun ruby-here-doc-beg-match ()
|
||||
"Return a regexp to find the beginning of a heredoc.
|
||||
|
||||
This should only be called after matching against `ruby-here-doc-end-re'."
|
||||
(let ((contents (concat
|
||||
(regexp-quote (concat (match-string 2) (match-string 3)))
|
||||
(if (string= (match-string 3) "_") "\\B" "\\b"))))
|
||||
(concat "<<"
|
||||
(let ((match (match-string 1)))
|
||||
(if (and match (> (length match) 0))
|
||||
(concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)"
|
||||
(match-string 1) "\\)"
|
||||
contents "\\(\\1\\|\\2\\)")
|
||||
(concat "-?\\([\"']\\|\\)" contents "\\1"))))))
|
||||
|
||||
(defconst ruby-font-lock-syntactic-keywords
|
||||
`(
|
||||
;; the last $', $", $` in the respective string is not variable
|
||||
;; the last ?', ?", ?` in the respective string is not ascii code
|
||||
("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
|
||||
(2 (7 . nil))
|
||||
(4 (7 . nil)))
|
||||
;; $' $" $` .... are variables
|
||||
;; ?' ?" ?` are ascii codes
|
||||
("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil))
|
||||
;; regexps
|
||||
("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
|
||||
(4 (7 . ?/))
|
||||
(6 (7 . ?/)))
|
||||
("^=en\\(d\\)\\_>" 1 "!")
|
||||
;; Percent literal.
|
||||
("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
|
||||
(3 "\"")
|
||||
(5 "\""))
|
||||
("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax))
|
||||
;; Currently, the following case is highlighted incorrectly:
|
||||
;;
|
||||
;; <<FOO
|
||||
;; FOO
|
||||
;; <<BAR
|
||||
;; <<BAZ
|
||||
;; BAZ
|
||||
;; BAR
|
||||
;;
|
||||
;; This is because all here-doc beginnings are highlighted before any endings,
|
||||
;; so although <<BAR is properly marked as a beginning, when we get to <<BAZ
|
||||
;; it thinks <<BAR is part of a string so it's marked as well.
|
||||
;;
|
||||
;; This may be fixable by modifying ruby-in-here-doc-p to use
|
||||
;; ruby-in-non-here-doc-string-p rather than syntax-ppss-context,
|
||||
;; but I don't want to try that until we've got unit tests set up
|
||||
;; to make sure I don't break anything else.
|
||||
(,(concat ruby-here-doc-beg-re ".*\\(\n\\)")
|
||||
,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re))
|
||||
(ruby-here-doc-beg-syntax))
|
||||
(,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax)))
|
||||
"Syntactic keywords for Ruby mode. See `font-lock-syntactic-keywords'.")
|
||||
|
||||
(defun ruby-comment-beg-syntax ()
|
||||
"Return the syntax cell for a the first character of a =begin.
|
||||
See the definition of `ruby-font-lock-syntactic-keywords'.
|
||||
|
||||
This returns a comment-delimiter cell as long as the =begin
|
||||
isn't in a string or another comment."
|
||||
(when (not (nth 3 (syntax-ppss)))
|
||||
(string-to-syntax "!")))
|
||||
|
||||
(defun ruby-in-here-doc-p ()
|
||||
"Return whether or not the point is in a heredoc."
|
||||
(save-excursion
|
||||
(let ((old-point (point)) (case-fold-search nil))
|
||||
(defun ruby-syntax-propertize-heredoc (limit)
|
||||
(let ((ppss (syntax-ppss))
|
||||
(res '()))
|
||||
(when (eq ?\n (nth 3 ppss))
|
||||
(save-excursion
|
||||
(goto-char (nth 8 ppss))
|
||||
(beginning-of-line)
|
||||
(catch 'found-beg
|
||||
(while (and (re-search-backward ruby-here-doc-beg-re nil t)
|
||||
(not (ruby-singleton-class-p)))
|
||||
(if (not (or (ruby-in-ppss-context-p 'anything)
|
||||
(ruby-here-doc-find-end old-point)))
|
||||
(throw 'found-beg t)))))))
|
||||
(while (re-search-forward ruby-here-doc-beg-re
|
||||
(line-end-position) t)
|
||||
(unless (ruby-singleton-class-p (match-beginning 0))
|
||||
(push (concat (ruby-here-doc-end-match) "\n") res))))
|
||||
(save-excursion
|
||||
;; With multiple openers on the same line, we don't know in which
|
||||
;; part `start' is, so we have to go back to the beginning.
|
||||
(when (cdr res)
|
||||
(goto-char (nth 8 ppss))
|
||||
(setq res (nreverse res)))
|
||||
(while (and res (re-search-forward (pop res) limit 'move))
|
||||
(if (null res)
|
||||
(put-text-property (1- (point)) (point)
|
||||
'syntax-table (string-to-syntax "\""))))
|
||||
;; End up at bol following the heredoc openers.
|
||||
;; Propertize expression expansions from this point forward.
|
||||
))))
|
||||
|
||||
(defun ruby-here-doc-find-end (&optional limit)
|
||||
"Expects the point to be on a line with one or more heredoc openers.
|
||||
Returns the buffer position at which all heredocs on the line
|
||||
are terminated, or nil if they aren't terminated before the
|
||||
buffer position `limit' or the end of the buffer."
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(catch 'done
|
||||
(let ((eol (point-at-eol))
|
||||
(case-fold-search nil)
|
||||
;; Fake match data such that (match-end 0) is at eol
|
||||
(end-match-data (progn (looking-at ".*$") (match-data)))
|
||||
beg-match-data end-re)
|
||||
(while (re-search-forward ruby-here-doc-beg-re eol t)
|
||||
(setq beg-match-data (match-data))
|
||||
(setq end-re (ruby-here-doc-end-match))
|
||||
(defun ruby-syntax-enclosing-percent-literal (limit)
|
||||
(let ((state (syntax-ppss))
|
||||
(start (point)))
|
||||
;; When already inside percent literal, re-propertize it.
|
||||
(when (eq t (nth 3 state))
|
||||
(goto-char (nth 8 state))
|
||||
(when (looking-at ruby-percent-literal-beg-re)
|
||||
(ruby-syntax-propertize-percent-literal limit))
|
||||
(when (< (point) start) (goto-char start)))))
|
||||
|
||||
(set-match-data end-match-data)
|
||||
(goto-char (match-end 0))
|
||||
(unless (re-search-forward end-re limit t) (throw 'done nil))
|
||||
(setq end-match-data (match-data))
|
||||
(defun ruby-syntax-propertize-percent-literal (limit)
|
||||
(goto-char (match-beginning 2))
|
||||
;; Not inside a simple string or comment.
|
||||
(when (eq t (nth 3 (syntax-ppss)))
|
||||
(let* ((op (char-after))
|
||||
(ops (char-to-string op))
|
||||
(cl (or (cdr (aref (syntax-table) op))
|
||||
(cdr (assoc op '((?< . ?>))))))
|
||||
parse-sexp-lookup-properties)
|
||||
(save-excursion
|
||||
(condition-case nil
|
||||
(progn
|
||||
(if cl ; Paired delimiters.
|
||||
;; Delimiter pairs of the same kind can be nested
|
||||
;; inside the literal, as long as they are balanced.
|
||||
;; Create syntax table that ignores other characters.
|
||||
(with-syntax-table (make-char-table 'syntax-table nil)
|
||||
(modify-syntax-entry op (concat "(" (char-to-string cl)))
|
||||
(modify-syntax-entry cl (concat ")" ops))
|
||||
(modify-syntax-entry ?\\ "\\")
|
||||
(save-restriction
|
||||
(narrow-to-region (point) limit)
|
||||
(forward-list))) ; skip to the paired character
|
||||
;; Single character delimiter.
|
||||
(re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
|
||||
(regexp-quote ops)) limit nil))
|
||||
;; Found the closing delimiter.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table
|
||||
(string-to-syntax "|")))
|
||||
;; Unclosed literal, do nothing.
|
||||
((scan-error search-failed)))))))
|
||||
|
||||
(set-match-data beg-match-data)
|
||||
(goto-char (match-end 0)))
|
||||
(set-match-data end-match-data)
|
||||
(goto-char (match-end 0))
|
||||
(point)))))
|
||||
(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))
|
||||
(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)
|
||||
(while (re-search-forward "[\"`]" end 'move)
|
||||
(put-text-property (match-beginning 0) (match-end 0)
|
||||
'syntax-table (string-to-syntax "."))))))
|
||||
|
||||
(defun ruby-here-doc-beg-syntax ()
|
||||
"Return the syntax cell for a line that may begin a heredoc.
|
||||
See the definition of `ruby-font-lock-syntactic-keywords'.
|
||||
|
||||
This sets the syntax cell for the newline ending the line
|
||||
containing the heredoc beginning so that cases where multiple
|
||||
heredocs are started on one line are handled correctly."
|
||||
(save-excursion
|
||||
(goto-char (match-beginning 0))
|
||||
(unless (or (ruby-in-ppss-context-p 'non-heredoc)
|
||||
(ruby-in-here-doc-p))
|
||||
(string-to-syntax "\""))))
|
||||
|
||||
(defun ruby-here-doc-end-syntax ()
|
||||
"Return the syntax cell for a line that may end a heredoc.
|
||||
See the definition of `ruby-font-lock-syntactic-keywords'."
|
||||
(let ((pss (syntax-ppss)) (case-fold-search nil))
|
||||
;; If we aren't in a string, we definitely aren't ending a heredoc,
|
||||
;; so we can just give up.
|
||||
;; This means we aren't doing a full-document search
|
||||
;; every time we enter a character.
|
||||
(when (ruby-in-ppss-context-p 'heredoc pss)
|
||||
(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 pss)) ; Go to the beginning of heredoc.
|
||||
(let ((eol (point)))
|
||||
(beginning-of-line)
|
||||
(if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line...
|
||||
(not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment...
|
||||
(progn (goto-char (match-end 0)) ; And it's the last heredoc on its line...
|
||||
(not (re-search-forward ruby-here-doc-beg-re eol t))))
|
||||
(string-to-syntax "\"")))))))
|
||||
(goto-char (nth 8 parse-state))
|
||||
(looking-at "%\\(?:[QWrxI]\\|\\W\\)")))))))
|
||||
|
||||
(unless (functionp 'syntax-ppss)
|
||||
(defun syntax-ppss (&optional pos)
|
||||
(parse-partial-sexp (point-min) (or pos (point)))))
|
||||
)
|
||||
(defun ruby-syntax-propertize-expansions (start end)
|
||||
(save-excursion
|
||||
(goto-char start)
|
||||
(while (re-search-forward ruby-expression-expansion-re end 'move)
|
||||
(ruby-syntax-propertize-expansion))))
|
||||
|
||||
(defun ruby-in-ppss-context-p (context &optional ppss)
|
||||
(let ((ppss (or ppss (syntax-ppss (point)))))
|
||||
|
@ -1880,14 +1713,6 @@ See the definition of `ruby-font-lock-syntactic-keywords'."
|
|||
"context name `" (symbol-name context) "' is unknown"))))
|
||||
t)))
|
||||
|
||||
(if (featurep 'xemacs)
|
||||
(put 'ruby-mode 'font-lock-defaults
|
||||
'((ruby-font-lock-keywords)
|
||||
nil nil nil
|
||||
beginning-of-line
|
||||
(font-lock-syntactic-keywords
|
||||
. ruby-font-lock-syntactic-keywords))))
|
||||
|
||||
(defvar ruby-font-lock-syntax-table
|
||||
(let ((tbl (copy-syntax-table ruby-mode-syntax-table)))
|
||||
(modify-syntax-entry ?_ "w" tbl)
|
||||
|
@ -2082,9 +1907,7 @@ The variable `ruby-indent-level' controls the amount of indentation.
|
|||
(setq-local font-lock-keywords ruby-font-lock-keywords)
|
||||
(setq-local font-lock-syntax-table ruby-font-lock-syntax-table)
|
||||
|
||||
(if (eval-when-compile (fboundp 'syntax-propertize-rules))
|
||||
(setq-local syntax-propertize-function #'ruby-syntax-propertize-function)
|
||||
(setq-local font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))
|
||||
(setq-local syntax-propertize-function #'ruby-syntax-propertize-function))
|
||||
|
||||
;;; Invoke ruby-mode when appropriate
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue