aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2012-04-24 13:08:55 -0400
committerStefan Monnier2012-04-24 13:08:55 -0400
commit1ec00a232a98f971c7b4c46f74636d14e48990a2 (patch)
treefd11dadb7d6b2b9b18271fd53cc81f2ea6adec49
parentb613912badfb9050e6310ee14fddc90e0fd16b2c (diff)
parentdfbd787fe6a5684d699926d698aaf9166812a81b (diff)
downloademacs-1ec00a232a98f971c7b4c46f74636d14e48990a2.tar.gz
emacs-1ec00a232a98f971c7b4c46f74636d14e48990a2.zip
* ruby-mode.el: Handle general delimited literals.
Fixes: debbugs:6286
-rw-r--r--lisp/ChangeLog22
-rw-r--r--lisp/progmodes/ruby-mode.el89
-rw-r--r--test/ChangeLog4
-rw-r--r--test/indent/ruby.rb19
4 files changed, 120 insertions, 14 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 269d72e3754..0eda6b28936 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,25 @@
12012-04-24 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * progmodes/ruby-mode.el: Simplify last change, and cleanup code.
4 (ruby-syntax-propertize-regexp): Remove.
5 (ruby-syntax-propertize-function): Split regexp into chunks.
6 Match following code directly.
7
82012-04-24 Dmitry Gutov <dgutov@yandex.ru>
9
10 * progmodes/ruby-mode.el: Handle Cucumber defs (bug#6286).
11 (ruby-syntax-propertize-regexp): New function.
12 (ruby-syntax-propertize-function): Use it to handle regexp not preceded
13 by a special keyword.
14
15 * progmodes/ruby-mode.el: Handle general delimited literals (bug#6286).
16 (ruby-syntax-general-delimiters-goto-beg)
17 (ruby-syntax-propertize-general-delimiters): New functions.
18 (ruby-syntax-propertize-function): Use them to handle GDL.
19 (ruby-font-lock-keywords): Move old handling of GDL...
20 (ruby-font-lock-syntactic-keywords): .. to here.
21 (ruby-calculate-indent): Adjust indentation for GDL.
22
12012-04-24 Michael Albinus <michael.albinus@gmx.de> 232012-04-24 Michael Albinus <michael.albinus@gmx.de>
2 24
3 * notifications.el (notifications-interface) 25 * notifications.el (notifications-interface)
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 66aa256f947..5d79437c3c2 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -784,7 +784,7 @@ and `\\' when preceded by `?'."
784 (not (looking-at "[a-z_]")))) 784 (not (looking-at "[a-z_]"))))
785 (and (looking-at ruby-operator-re) 785 (and (looking-at ruby-operator-re)
786 (not (ruby-special-char-p)) 786 (not (ruby-special-char-p))
787 ;; operator at the end of line 787 ;; Operator at the end of line.
788 (let ((c (char-after (point)))) 788 (let ((c (char-after (point))))
789 (and 789 (and
790;; (or (null begin) 790;; (or (null begin)
@@ -794,8 +794,9 @@ and `\\' when preceded by `?'."
794;; (not (or (eolp) (looking-at "#") 794;; (not (or (eolp) (looking-at "#")
795;; (and (eq (car (nth 1 state)) ?{) 795;; (and (eq (car (nth 1 state)) ?{)
796;; (looking-at "|")))))) 796;; (looking-at "|"))))))
797 (or (not (eq ?/ c)) 797 ;; Not a regexp or general delimited literal.
798 (null (nth 0 (ruby-parse-region (or begin parse-start) (point))))) 798 (null (nth 0 (ruby-parse-region (or begin parse-start)
799 (point))))
799 (or (not (eq ?| (char-after (point)))) 800 (or (not (eq ?| (char-after (point))))
800 (save-excursion 801 (save-excursion
801 (or (eolp) (forward-char -1)) 802 (or (eolp) (forward-char -1))
@@ -1110,6 +1111,8 @@ See `add-log-current-defun-function'."
1110 mlist))))) 1111 mlist)))))
1111 1112
1112(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit)) 1113(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit))
1114(declare-function ruby-syntax-general-delimiters-goto-beg "ruby-mode" ())
1115(declare-function ruby-syntax-propertize-general-delimiters "ruby-mode" (limit))
1113 1116
1114(if (eval-when-compile (fboundp #'syntax-propertize-rules)) 1117(if (eval-when-compile (fboundp #'syntax-propertize-rules))
1115 ;; New code that works independently from font-lock. 1118 ;; New code that works independently from font-lock.
@@ -1118,26 +1121,48 @@ See `add-log-current-defun-function'."
1118 "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." 1121 "Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
1119 (goto-char start) 1122 (goto-char start)
1120 (ruby-syntax-propertize-heredoc end) 1123 (ruby-syntax-propertize-heredoc end)
1124 (ruby-syntax-general-delimiters-goto-beg)
1121 (funcall 1125 (funcall
1122 (syntax-propertize-rules 1126 (syntax-propertize-rules
1123 ;; #{ }, #$hoge, #@foo are not comments 1127 ;; #{ }, #$hoge, #@foo are not comments.
1124 ("\\(#\\)[{$@]" (1 ".")) 1128 ("\\(#\\)[{$@]" (1 "."))
1125 ;; $' $" $` .... are variables 1129 ;; $' $" $` .... are variables.
1126 ;; ?' ?" ?` are ascii codes 1130 ;; ?' ?" ?` are ascii codes.
1127 ("\\([?$]\\)[#\"'`]" 1131 ("\\([?$]\\)[#\"'`]"
1128 (1 (unless (save-excursion 1132 (1 (unless (save-excursion
1129 ;; Not within a string. 1133 ;; Not within a string.
1130 (nth 3 (syntax-ppss (match-beginning 0)))) 1134 (nth 3 (syntax-ppss (match-beginning 0))))
1131 (string-to-syntax "\\")))) 1135 (string-to-syntax "\\"))))
1132 ;; regexps 1136 ;; Regexps: regexps are distinguished from division either because
1133 ("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)" 1137 ;; of the keyword/symbol before them, or because of the code
1134 (4 "\"/") 1138 ;; following them.
1135 (6 "\"/")) 1139 ((concat
1140 ;; Special tokens that can't be followed by a division operator.
1141 "\\(?:\\(^\\|[[=(,~?:;<>]\\|\\(?:^\\|\\s \\)"
1142 (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
1143 "or" "&&" "||"
1144 "gsub" "gsub!" "sub" "sub!" "scan" "split" "split!"))
1145 "\\)\\s *\\)?"
1146 ;; The regular expression itself.
1147 "\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)"
1148 ;; Special code that cannot follow a division operator.
1149 ;; FIXME: Just because the second slash of "/foo/ do bar" can't
1150 ;; be a division, doesn't mean it can't *start* a regexp, as in
1151 ;; "x = toto/foo; if /do bar/".
1152 "\\([imxo]*\\s *\\(?:,\\|\\_<do\\_>\\)\\)?")
1153 (2 (when (or (match-beginning 1) (match-beginning 4))
1154 (string-to-syntax "\"/")))
1155 (3 (if (or (match-beginning 1) (match-beginning 4))
1156 (string-to-syntax "\"/")
1157 (goto-char (match-end 2)))))
1136 ("^=en\\(d\\)\\_>" (1 "!")) 1158 ("^=en\\(d\\)\\_>" (1 "!"))
1137 ("^\\(=\\)begin\\_>" (1 "!")) 1159 ("^\\(=\\)begin\\_>" (1 "!"))
1138 ;; Handle here documents. 1160 ;; Handle here documents.
1139 ((concat ruby-here-doc-beg-re ".*\\(\n\\)") 1161 ((concat ruby-here-doc-beg-re ".*\\(\n\\)")
1140 (7 (prog1 "\"" (ruby-syntax-propertize-heredoc end))))) 1162 (7 (prog1 "\"" (ruby-syntax-propertize-heredoc end))))
1163 ;; Handle percent literals: %w(), %q{}, etc.
1164 ("\\(?:^\\|[[ \t\n<+(,=]\\)\\(%\\)[qQrswWx]?\\([[:punct:]]\\)"
1165 (1 (prog1 "|" (ruby-syntax-propertize-general-delimiters end)))))
1141 (point) end)) 1166 (point) end))
1142 1167
1143 (defun ruby-syntax-propertize-heredoc (limit) 1168 (defun ruby-syntax-propertize-heredoc (limit)
@@ -1163,6 +1188,41 @@ See `add-log-current-defun-function'."
1163 ;; Make extra sure we don't move back, lest we could fall into an 1188 ;; Make extra sure we don't move back, lest we could fall into an
1164 ;; inf-loop. 1189 ;; inf-loop.
1165 (if (< (point) start) (goto-char start)))))) 1190 (if (< (point) start) (goto-char start))))))
1191
1192 (defun ruby-syntax-general-delimiters-goto-beg ()
1193 (let ((state (syntax-ppss)))
1194 ;; Move to the start of the literal, in case it's multiline.
1195 ;; TODO: determine the literal type more reliably here?
1196 (when (eq t (nth 3 state))
1197 (goto-char (nth 8 state))
1198 (beginning-of-line))))
1199
1200 (defun ruby-syntax-propertize-general-delimiters (limit)
1201 (goto-char (match-beginning 2))
1202 (let* ((op (char-after))
1203 (ops (char-to-string op))
1204 (cl (or (cdr (aref (syntax-table) op))
1205 (cdr (assoc op '((?< . ?>))))))
1206 parse-sexp-lookup-properties)
1207 (ignore-errors
1208 (if cl
1209 (progn ; Paired delimiters.
1210 ;; Delimiter pairs of the same kind can be nested
1211 ;; inside the literal, as long as they are balanced.
1212 ;; Create syntax table that ignores other characters.
1213 (with-syntax-table (make-char-table 'syntax-table nil)
1214 (modify-syntax-entry op (concat "(" (char-to-string cl)))
1215 (modify-syntax-entry cl (concat ")" ops))
1216 (modify-syntax-entry ?\\ "\\")
1217 (save-restriction
1218 (narrow-to-region (point) limit)
1219 (forward-list)))) ; skip to the paired character
1220 ;; Single character delimiter.
1221 (re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
1222 (regexp-quote ops)) limit nil))
1223 ;; If we reached here, the closing delimiter was found.
1224 (put-text-property (1- (point)) (point)
1225 'syntax-table (string-to-syntax "|")))))
1166 ) 1226 )
1167 1227
1168 ;; For Emacsen where syntax-propertize-rules is not (yet) available, 1228 ;; For Emacsen where syntax-propertize-rules is not (yet) available,
@@ -1207,6 +1267,10 @@ This should only be called after matching against `ruby-here-doc-end-re'."
1207 (4 (7 . ?/)) 1267 (4 (7 . ?/))
1208 (6 (7 . ?/))) 1268 (6 (7 . ?/)))
1209 ("^=en\\(d\\)\\_>" 1 "!") 1269 ("^=en\\(d\\)\\_>" 1 "!")
1270 ;; General delimited string.
1271 ("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
1272 (3 "\"")
1273 (5 "\""))
1210 ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax)) 1274 ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax))
1211 ;; Currently, the following case is highlighted incorrectly: 1275 ;; Currently, the following case is highlighted incorrectly:
1212 ;; 1276 ;;
@@ -1415,9 +1479,6 @@ See `font-lock-syntax-table'.")
1415 1 font-lock-variable-name-face) 1479 1 font-lock-variable-name-face)
1416 '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+" 1480 '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+"
1417 0 font-lock-variable-name-face) 1481 0 font-lock-variable-name-face)
1418 ;; general delimited string
1419 '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
1420 (2 font-lock-string-face))
1421 ;; constants 1482 ;; constants
1422 '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" 1483 '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
1423 2 font-lock-type-face) 1484 2 font-lock-type-face)
diff --git a/test/ChangeLog b/test/ChangeLog
index 66f8592c79c..ff38a8fa9e1 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,7 @@
12012-04-24 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * indent/ruby.rb: New file, to test new syntax-propertize code.
4
12012-04-11 Glenn Morris <rgm@gnu.org> 52012-04-11 Glenn Morris <rgm@gnu.org>
2 6
3 * automated/vc-bzr.el (vc-bzr-test-faulty-bzr-autoloads): New test. 7 * automated/vc-bzr.el (vc-bzr-test-faulty-bzr-autoloads): New test.
diff --git a/test/indent/ruby.rb b/test/indent/ruby.rb
new file mode 100644
index 00000000000..c4a747a1c78
--- /dev/null
+++ b/test/indent/ruby.rb
@@ -0,0 +1,19 @@
1# Don't mis-match "sub" at the end of words.
2a = asub / aslb + bsub / bslb;
3
4b = %Q{This is a "string"}
5c = %w(foo
6 bar
7 baz)
8d = %!hello!
9
10# A "do" after a slash means that slash is not a division, but it doesn't imply
11# it's a regexp-ender, since it can be a regexp-starter instead!
12x = toto / foo; if /do bar/ then
13 toto = 1
14 end
15
16# Some Cucumber code:
17Given /toto/ do
18 print "hello"
19end