summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-22 00:51:35 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-22 00:51:35 +0000
commit1bcbc29d9554030b6e681ed6f1b111b26a7f3738 (patch)
treeeaee1dd171828a6628fb09e8db8cdcce9b623935 /misc
parent56e28fcf98feea4dbac057a716002af15ac36cf8 (diff)
* misc/ruby-mode.el: fix here-doc strings with inner quotes. patches
by Nathan Weizenbaum <nex342 AT gmail.com> from [ruby-core:17615] through [ruby-core:17910]. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18150 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'misc')
-rw-r--r--misc/ruby-mode.el142
1 files changed, 96 insertions, 46 deletions
diff --git a/misc/ruby-mode.el b/misc/ruby-mode.el
index 01f22898b3..3c70a64967 100644
--- a/misc/ruby-mode.el
+++ b/misc/ruby-mode.el
@@ -49,15 +49,27 @@
(defconst ruby-block-end-re "\\<end\\>")
(defconst ruby-here-doc-beg-re
- "<<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
+ "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
+
+(defconst ruby-here-doc-end-re
+ "^\\([ \t]+\\)?\\(.*\\)\\(.\\)$")
(defun ruby-here-doc-end-match ()
(concat "^"
- (if (match-string 1) "[ \t]*" nil)
+ (if (match-string 2) "[ \t]*" nil)
(regexp-quote
- (or (match-string 3)
- (match-string 4)
- (match-string 5)))))
+ (or (match-string 4)
+ (match-string 5)
+ (match-string 6)))))
+
+(defun ruby-here-doc-beg-match ()
+ (let ((contents (regexp-quote (concat (match-string 2) (match-string 3)))))
+ (concat "<<"
+ (let ((match (match-string 1)))
+ (if (and match (> (length match) 0))
+ (concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)" (match-string 1) "\\)"
+ contents "\\(\\1\\|\\2\\)")
+ (concat "-?\\([\"']\\|\\)" contents "\\1"))))))
(defconst ruby-delimiter
(concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
@@ -172,8 +184,8 @@ Also ignores spaces after parenthesis when 'space."
(eval-when-compile (require 'cl))
(defun ruby-imenu-create-index-in-block (prefix beg end)
- (let ((index-alist '()) (case-fold-search nil)
- name next pos decl sing)
+ (let ((index-alist '())
+ name next pos decl sing)
(goto-char beg)
(while (re-search-forward "^\\s *\\(\\(class\\>\\(\\s *<<\\)?\\|module\\>\\)\\s *\\([^\(<\n ]+\\)\\|\\(def\\|alias\\)\\>\\s *\\([^\(\n ]+\\)\\)" end t)
(setq sing (match-beginning 3))
@@ -220,6 +232,7 @@ Also ignores spaces after parenthesis when 'space."
(defun ruby-mode-variables ()
(set-syntax-table ruby-mode-syntax-table)
(setq local-abbrev-table ruby-mode-abbrev-table)
+ (setq case-fold-search nil)
(make-local-variable 'indent-line-function)
(setq indent-line-function 'ruby-indent-line)
(make-local-variable 'require-final-newline)
@@ -235,6 +248,8 @@ Also ignores spaces after parenthesis when 'space."
(setq indent-tabs-mode ruby-indent-tabs-mode)
(make-local-variable 'parse-sexp-ignore-comments)
(setq parse-sexp-ignore-comments t)
+ (make-local-variable 'parse-sexp-lookup-properties)
+ (setq parse-sexp-lookup-properties t)
(make-local-variable 'paragraph-start)
(setq paragraph-start (concat "$\\|" page-delimiter))
(make-local-variable 'paragraph-separate)
@@ -645,7 +660,6 @@ The variable ruby-indent-level controls the amount of indentation.
(save-excursion
(beginning-of-line)
(let ((indent-point (point))
- (case-fold-search nil)
state bol eol begin op-end
(paren (progn (skip-syntax-forward " ")
(and (char-after) (matching-paren (char-after)))))
@@ -1090,7 +1104,7 @@ balanced expression is found."
(setq font-lock-variable-name-face font-lock-type-face))
(setq ruby-font-lock-syntactic-keywords
- '(
+ `(
;; #{ }, #$hoge, #@foo are not comments
("\\(#\\)[{$@]" 1 (1 . nil))
;; the last $', $", $` in the respective string is not variable
@@ -1106,7 +1120,76 @@ balanced expression is found."
(4 (7 . ?/))
(6 (7 . ?/)))
("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
- ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
+ ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))
+ (,(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))))
+
+ (defun ruby-in-non-here-doc-string-p ()
+ (let ((syntax (syntax-ppss)))
+ (or (nth 4 syntax)
+ ;; In a string *without* a generic delimiter
+ ;; If it's generic, it's a heredoc and we don't care
+ ;; See `parse-partial-sexp'
+ (numberp (nth 3 syntax)))))
+
+ (defun ruby-in-here-doc-p ()
+ (save-excursion
+ (let ((old-point (point)))
+ (beginning-of-line)
+ (catch 'found-beg
+ (while (re-search-backward ruby-here-doc-beg-re nil t)
+ (if (not (or (syntax-ppss-context (syntax-ppss))
+ (ruby-here-doc-find-end old-point)))
+ (throw 'found-beg t)))))))
+
+ (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 (save-excursion (end-of-line) (point)))
+ ;; 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))
+
+ (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))
+
+ (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-here-doc-beg-syntax ()
+ (save-excursion
+ (goto-char (match-beginning 0))
+ (unless (or (ruby-in-non-here-doc-string-p)
+ (ruby-in-here-doc-p))
+ (string-to-syntax "|"))))
+
+ (defun ruby-here-doc-end-syntax ()
+ (save-excursion
+ (goto-char (match-end 0))
+ (let ((old-point (point))
+ (beg-exists (re-search-backward (ruby-here-doc-beg-match) nil t))
+ (eol (save-excursion (end-of-line) (point))))
+ (if (and beg-exists ; If there is a heredoc that matches this line...
+ (null (syntax-ppss-context (syntax-ppss))) ; 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)))
+ (eq old-point (ruby-here-doc-find-end old-point))) ; And it ends at this point...
+ (string-to-syntax "|")))))
(if (featurep 'xemacs)
(put 'ruby-mode 'font-lock-defaults
@@ -1147,35 +1230,7 @@ balanced expression is found."
(modify-syntax-entry ?_ "w" tbl)
tbl))
- (defun ruby-font-lock-here-docs (limit)
- (if (re-search-forward ruby-here-doc-beg-re limit t)
- (let (beg)
- (beginning-of-line)
- (forward-line)
- (setq beg (point))
- (if (re-search-forward (ruby-here-doc-end-match) nil t)
- (progn
- (set-match-data (list beg (point)))
- t)))))
-
- (defun ruby-font-lock-maybe-here-docs (limit)
- (let (beg)
- (save-excursion
- (if (re-search-backward ruby-here-doc-beg-re nil t)
- (progn
- (beginning-of-line)
- (forward-line)
- (setq beg (point)))))
- (if (and beg
- (let ((end-match (ruby-here-doc-end-match)))
- (and (not (re-search-backward end-match beg t))
- (re-search-forward end-match nil t))))
- (progn
- (set-match-data (list beg (point)))
- t)
- nil)))
-
- (defvar ruby-font-lock-keywords
+ (defconst ruby-font-lock-keywords
(list
;; functions
'("^\\s *def\\s +\\([^( \t\n]+\\)"
@@ -1224,6 +1279,8 @@ balanced expression is found."
"\\|")
"\\)\\>\\)")
2)
+ ;; here-doc beginnings
+ (list ruby-here-doc-beg-re 0 'font-lock-string-face)
;; variables
'("\\(^\\|[^_:.@$]\\|\\.\\.\\)\\b\\(nil\\|self\\|true\\|false\\)\\>"
2 font-lock-variable-name-face)
@@ -1237,13 +1294,6 @@ balanced expression is found."
0 font-lock-comment-face t)
'(ruby-font-lock-maybe-docs
0 font-lock-comment-face t)
- ;; "here" document
- '(ruby-font-lock-here-docs
- 0 font-lock-string-face t)
- '(ruby-font-lock-maybe-here-docs
- 0 font-lock-string-face t)
- `(,ruby-here-doc-beg-re
- 0 font-lock-string-face t)
;; general delimited string
'("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
(2 font-lock-string-face))