[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
General delimited literals in ruby-mode patch
From: |
Dmitry Gutov |
Subject: |
General delimited literals in ruby-mode patch |
Date: |
Wed, 08 Feb 2012 03:32:10 +0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.0.93 (windows-nt) |
Hi all,
The bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6286.
I wrote a patch that fixes all examples except the last one (which is a
different issue), and also supports nesting delimiters of the same type
inside the literal: %r(//([^/])*/)
This would be my first patch for Emacs, so I'd love to have someone more
familiar with ruby-mode and/or font-lock look at it.
--
Do I submit the final patch here, or to the Ruby Redmine tracker?
As I understand, the upstream version is maintained to be compatible
with earlier Emacs versions, and I'm using the
syntax-propertize-function feature here.
Am I trying to be too clever with the syntax table in
`ruby-syntax-propertize-general-delimiters'? I figured it's the easiest
way to avoid reimplementing `scan-lists'.
In general, if I have an undercooked patch, should I post a message
here, or just attach it to the related bug?
Dmitry.
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index bf26497..747598c 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -114,6 +114,10 @@ This should only be called after matching against
`ruby-here-doc-beg-re'."
(match-string 5)
(match-string 6)))))
+(defconst ruby-general-delimiter-beg-re
+ "\\(?:^\\|[[ \t\n<+(,=]\\)\\(%\\)[qQrswWx]?\\([[:punct:]]\\)"
+ "Regexp to match the beginning of a general delimited literal.")
+
(defconst ruby-delimiter
(concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
ruby-block-beg-re
@@ -793,8 +797,8 @@ and `\\' when preceded by `?'."
;; (not (or (eolp) (looking-at "#")
;; (and (eq (car (nth 1 state)) ?{)
;; (looking-at "|"))))))
- (or (not (eq ?/ c))
- (null (nth 0 (ruby-parse-region (or begin
parse-start) (point)))))
+ ;; not a regexp or general delimited literal
+ (null (nth 0 (ruby-parse-region (or begin parse-start)
(point))))
(or (not (eq ?| (char-after (point))))
(save-excursion
(or (eolp) (forward-char -1))
@@ -1117,6 +1121,7 @@ See `add-log-current-defun-function'."
"Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
(goto-char start)
(ruby-syntax-propertize-heredoc end)
+ (ruby-syntax-general-delimiters-goto-beg)
(funcall
(syntax-propertize-rules
;; #{ }, #$hoge, address@hidden are not comments
@@ -1136,7 +1141,10 @@ See `add-log-current-defun-function'."
("^\\(=\\)begin\\_>" (1 "!"))
;; Handle here documents.
((concat ruby-here-doc-beg-re ".*\\(\n\\)")
- (7 (prog1 "\"" (ruby-syntax-propertize-heredoc end)))))
+ (7 (prog1 "\"" (ruby-syntax-propertize-heredoc end))))
+ ;; Handle percent literals: %w(), %q{}, etc.
+ (ruby-general-delimiter-beg-re
+ (1 (prog1 "|" (ruby-syntax-propertize-general-delimiters end)))))
(point) end))
(defun ruby-syntax-propertize-heredoc (limit)
@@ -1162,6 +1170,41 @@ See `add-log-current-defun-function'."
;; Make extra sure we don't move back, lest we could fall into an
;; inf-loop.
(if (< (point) start) (goto-char start))))))
+
+ (defun ruby-syntax-general-delimiters-goto-beg ()
+ (let ((state (syntax-ppss)))
+ ;; Move to the start of the literal, in case it's multiline.
+ ;; TODO: determine the literal type more reliably here?
+ (when (eq t (nth 3 state))
+ (goto-char (nth 8 state))
+ (beginning-of-line))))
+
+ (defun ruby-syntax-propertize-general-delimiters (limit)
+ (goto-char (match-beginning 2))
+ (let* ((op (char-after))
+ (ops (char-to-string op))
+ (cl (or (cdr (aref (syntax-table) op))
+ (cdr (assoc op '((?< . ?>))))))
+ parse-sexp-lookup-properties)
+ (ignore-errors
+ (if cl
+ (progn ; 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))
+ ;; if we reached here, the closing delimiter was found
+ (put-text-property (1- (point)) (point)
+ 'syntax-table (string-to-syntax "|")))))
)
;; For Emacsen where syntax-propertize-rules is not (yet) available,
- General delimited literals in ruby-mode patch,
Dmitry Gutov <=