diff options
| author | Dmitry Gutov | 2013-05-31 10:04:33 +0400 |
|---|---|---|
| committer | Dmitry Gutov | 2013-05-31 10:04:33 +0400 |
| commit | 19bb8e629352f9438e95e62559bf73940cd3d885 (patch) | |
| tree | e3961dcd8917d9bd15873252ac0c87534119cac5 | |
| parent | fc186a96df6853da2a94b76b40b6f3f8b24e52ac (diff) | |
| download | emacs-19bb8e629352f9438e95e62559bf73940cd3d885.tar.gz emacs-19bb8e629352f9438e95e62559bf73940cd3d885.zip | |
* 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.
| -rw-r--r-- | lisp/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 110 | ||||
| -rw-r--r-- | test/ChangeLog | 5 | ||||
| -rw-r--r-- | test/automated/ruby-mode-tests.el | 17 |
4 files changed, 93 insertions, 48 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 87774cdb2a5..c4dc36245f2 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2013-05-31 Dmitry Gutov <dgutov@yandex.ru> | ||
| 2 | |||
| 3 | * progmodes/ruby-mode.el (ruby-syntax-expansion-allowed-p): New | ||
| 4 | function, checks if point is inside a literal that allows | ||
| 5 | expression expansion. | ||
| 6 | (ruby-syntax-propertize-expansion): Use it. | ||
| 7 | (ruby-syntax-propertize-function): Bind `case-fold-search' to nil | ||
| 8 | around the body. | ||
| 9 | |||
| 1 | 2013-05-30 Juri Linkov <juri@jurta.org> | 10 | 2013-05-30 Juri Linkov <juri@jurta.org> |
| 2 | 11 | ||
| 3 | * isearch.el (isearch-mode-map): Bind `isearch-toggle-invisible' | 12 | * isearch.el (isearch-mode-map): Bind `isearch-toggle-invisible' |
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index a96ee64a229..b7a635199ab 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el | |||
| @@ -1349,6 +1349,7 @@ If the result is do-end block, it will always be multiline." | |||
| 1349 | (declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit)) | 1349 | (declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit)) |
| 1350 | ;; Unusual code layout confuses the byte-compiler. | 1350 | ;; Unusual code layout confuses the byte-compiler. |
| 1351 | (declare-function ruby-syntax-propertize-expansion "ruby-mode" ()) | 1351 | (declare-function ruby-syntax-propertize-expansion "ruby-mode" ()) |
| 1352 | (declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state)) | ||
| 1352 | 1353 | ||
| 1353 | (if (eval-when-compile (fboundp #'syntax-propertize-rules)) | 1354 | (if (eval-when-compile (fboundp #'syntax-propertize-rules)) |
| 1354 | ;; New code that works independently from font-lock. | 1355 | ;; New code that works independently from font-lock. |
| @@ -1380,51 +1381,52 @@ It will be properly highlighted even when the call omits parens.") | |||
| 1380 | 1381 | ||
| 1381 | (defun ruby-syntax-propertize-function (start end) | 1382 | (defun ruby-syntax-propertize-function (start end) |
| 1382 | "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." | 1383 | "Syntactic keywords for Ruby mode. See `syntax-propertize-function'." |
| 1383 | (goto-char start) | 1384 | (let (case-fold-search) |
| 1384 | (remove-text-properties start end '(ruby-expansion-match-data)) | 1385 | (goto-char start) |
| 1385 | (ruby-syntax-propertize-heredoc end) | 1386 | (remove-text-properties start end '(ruby-expansion-match-data)) |
| 1386 | (ruby-syntax-enclosing-percent-literal end) | 1387 | (ruby-syntax-propertize-heredoc end) |
| 1387 | (funcall | 1388 | (ruby-syntax-enclosing-percent-literal end) |
| 1388 | (syntax-propertize-rules | 1389 | (funcall |
| 1389 | ;; $' $" $` .... are variables. | 1390 | (syntax-propertize-rules |
| 1390 | ;; ?' ?" ?` are ascii codes. | 1391 | ;; $' $" $` .... are variables. |
| 1391 | ("\\([?$]\\)[#\"'`]" | 1392 | ;; ?' ?" ?` are ascii codes. |
| 1392 | (1 (unless (save-excursion | 1393 | ("\\([?$]\\)[#\"'`]" |
| 1393 | ;; Not within a string. | 1394 | (1 (unless (save-excursion |
| 1394 | (nth 3 (syntax-ppss (match-beginning 0)))) | 1395 | ;; Not within a string. |
| 1395 | (string-to-syntax "\\")))) | 1396 | (nth 3 (syntax-ppss (match-beginning 0)))) |
| 1396 | ;; Regular expressions. Start with matching unescaped slash. | 1397 | (string-to-syntax "\\")))) |
| 1397 | ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)" | 1398 | ;; Regular expressions. Start with matching unescaped slash. |
| 1398 | (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1))))) | 1399 | ("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)" |
| 1399 | (when (or | 1400 | (1 (let ((state (save-excursion (syntax-ppss (match-beginning 1))))) |
| 1400 | ;; Beginning of a regexp. | 1401 | (when (or |
| 1401 | (and (null (nth 8 state)) | 1402 | ;; Beginning of a regexp. |
| 1402 | (save-excursion | 1403 | (and (null (nth 8 state)) |
| 1403 | (forward-char -1) | 1404 | (save-excursion |
| 1404 | (looking-back ruby-syntax-before-regexp-re | 1405 | (forward-char -1) |
| 1405 | (point-at-bol)))) | 1406 | (looking-back ruby-syntax-before-regexp-re |
| 1406 | ;; End of regexp. We don't match the whole | 1407 | (point-at-bol)))) |
| 1407 | ;; regexp at once because it can have | 1408 | ;; End of regexp. We don't match the whole |
| 1408 | ;; string interpolation inside, or span | 1409 | ;; regexp at once because it can have |
| 1409 | ;; several lines. | 1410 | ;; string interpolation inside, or span |
| 1410 | (eq ?/ (nth 3 state))) | 1411 | ;; several lines. |
| 1411 | (string-to-syntax "\"/"))))) | 1412 | (eq ?/ (nth 3 state))) |
| 1412 | ;; Expression expansions in strings. We're handling them | 1413 | (string-to-syntax "\"/"))))) |
| 1413 | ;; here, so that the regexp rule never matches inside them. | 1414 | ;; Expression expansions in strings. We're handling them |
| 1414 | (ruby-expression-expansion-re | 1415 | ;; here, so that the regexp rule never matches inside them. |
| 1415 | (0 (ignore (ruby-syntax-propertize-expansion)))) | 1416 | (ruby-expression-expansion-re |
| 1416 | ("^=en\\(d\\)\\_>" (1 "!")) | 1417 | (0 (ignore (ruby-syntax-propertize-expansion)))) |
| 1417 | ("^\\(=\\)begin\\_>" (1 "!")) | 1418 | ("^=en\\(d\\)\\_>" (1 "!")) |
| 1418 | ;; Handle here documents. | 1419 | ("^\\(=\\)begin\\_>" (1 "!")) |
| 1419 | ((concat ruby-here-doc-beg-re ".*\\(\n\\)") | 1420 | ;; Handle here documents. |
| 1420 | (7 (unless (ruby-singleton-class-p (match-beginning 0)) | 1421 | ((concat ruby-here-doc-beg-re ".*\\(\n\\)") |
| 1421 | (put-text-property (match-beginning 7) (match-end 7) | 1422 | (7 (unless (ruby-singleton-class-p (match-beginning 0)) |
| 1422 | 'syntax-table (string-to-syntax "\"")) | 1423 | (put-text-property (match-beginning 7) (match-end 7) |
| 1423 | (ruby-syntax-propertize-heredoc end)))) | 1424 | 'syntax-table (string-to-syntax "\"")) |
| 1424 | ;; Handle percent literals: %w(), %q{}, etc. | 1425 | (ruby-syntax-propertize-heredoc end)))) |
| 1425 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) | 1426 | ;; Handle percent literals: %w(), %q{}, etc. |
| 1426 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) | 1427 | ((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re) |
| 1427 | (point) end)) | 1428 | (1 (prog1 "|" (ruby-syntax-propertize-percent-literal end))))) |
| 1429 | (point) end))) | ||
| 1428 | 1430 | ||
| 1429 | (defun ruby-syntax-propertize-heredoc (limit) | 1431 | (defun ruby-syntax-propertize-heredoc (limit) |
| 1430 | (let ((ppss (syntax-ppss)) | 1432 | (let ((ppss (syntax-ppss)) |
| @@ -1496,9 +1498,10 @@ It will be properly highlighted even when the call omits parens.") | |||
| 1496 | (defun ruby-syntax-propertize-expansion () | 1498 | (defun ruby-syntax-propertize-expansion () |
| 1497 | ;; Save the match data to a text property, for font-locking later. | 1499 | ;; Save the match data to a text property, for font-locking later. |
| 1498 | ;; Set the syntax of all double quotes and backticks to punctuation. | 1500 | ;; Set the syntax of all double quotes and backticks to punctuation. |
| 1499 | (let ((beg (match-beginning 2)) | 1501 | (let* ((beg (match-beginning 2)) |
| 1500 | (end (match-end 2))) | 1502 | (end (match-end 2)) |
| 1501 | (when (and beg (save-excursion (nth 3 (syntax-ppss beg)))) | 1503 | (state (and beg (save-excursion (syntax-ppss beg))))) |
| 1504 | (when (ruby-syntax-expansion-allowed-p state) | ||
| 1502 | (put-text-property beg (1+ beg) 'ruby-expansion-match-data | 1505 | (put-text-property beg (1+ beg) 'ruby-expansion-match-data |
| 1503 | (match-data)) | 1506 | (match-data)) |
| 1504 | (goto-char beg) | 1507 | (goto-char beg) |
| @@ -1506,6 +1509,17 @@ It will be properly highlighted even when the call omits parens.") | |||
| 1506 | (put-text-property (match-beginning 0) (match-end 0) | 1509 | (put-text-property (match-beginning 0) (match-end 0) |
| 1507 | 'syntax-table (string-to-syntax ".")))))) | 1510 | 'syntax-table (string-to-syntax ".")))))) |
| 1508 | 1511 | ||
| 1512 | (defun ruby-syntax-expansion-allowed-p (parse-state) | ||
| 1513 | "Return non-nil if expression expansion is allowed." | ||
| 1514 | (let ((term (nth 3 parse-state))) | ||
| 1515 | (cond | ||
| 1516 | ((memq term '(?\" ?` ?\n))) | ||
| 1517 | ((eq term t) | ||
| 1518 | (save-match-data | ||
| 1519 | (save-excursion | ||
| 1520 | (goto-char (nth 8 parse-state)) | ||
| 1521 | (looking-at "%\\(?:[QWrx]\\|\\W\\)"))))))) | ||
| 1522 | |||
| 1509 | (defun ruby-syntax-propertize-expansions (start end) | 1523 | (defun ruby-syntax-propertize-expansions (start end) |
| 1510 | (save-excursion | 1524 | (save-excursion |
| 1511 | (goto-char start) | 1525 | (goto-char start) |
diff --git a/test/ChangeLog b/test/ChangeLog index 56e019ec4af..98fb2e3da1f 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-05-31 Dmitry Gutov <dgutov@yandex.ru> | ||
| 2 | |||
| 3 | * automated/ruby-mode-tests.el: New tests, for percent literals | ||
| 4 | and expression expansion. | ||
| 5 | |||
| 1 | 2013-05-29 Leo Liu <sdl.web@gmail.com> | 6 | 2013-05-29 Leo Liu <sdl.web@gmail.com> |
| 2 | 7 | ||
| 3 | * indent/octave.m: Tweak. | 8 | * indent/octave.m: Tweak. |
diff --git a/test/automated/ruby-mode-tests.el b/test/automated/ruby-mode-tests.el index e52927a2968..6ed2a8ad377 100644 --- a/test/automated/ruby-mode-tests.el +++ b/test/automated/ruby-mode-tests.el | |||
| @@ -353,6 +353,23 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 353 | ;; It's confused by the closing paren in the middle. | 353 | ;; It's confused by the closing paren in the middle. |
| 354 | (ruby-assert-state s 8 nil))) | 354 | (ruby-assert-state s 8 nil))) |
| 355 | 355 | ||
| 356 | (ert-deftest ruby-interpolation-inside-double-quoted-percent-literals () | ||
| 357 | (ruby-assert-face "%Q{foo #@bar}" 8 font-lock-variable-name-face) | ||
| 358 | (ruby-assert-face "%W{foo #@bar}" 8 font-lock-variable-name-face) | ||
| 359 | (ruby-assert-face "%r{foo #@bar}" 8 font-lock-variable-name-face) | ||
| 360 | (ruby-assert-face "%x{foo #@bar}" 8 font-lock-variable-name-face)) | ||
| 361 | |||
| 362 | (ert-deftest ruby-no-interpolation-in-single-quoted-literals () | ||
| 363 | (ruby-assert-face "'foo #@bar'" 7 font-lock-string-face) | ||
| 364 | (ruby-assert-face "%q{foo #@bar}" 8 font-lock-string-face) | ||
| 365 | (ruby-assert-face "%w{foo #@bar}" 8 font-lock-string-face) | ||
| 366 | (ruby-assert-face "%s{foo #@bar}" 8 font-lock-string-face)) | ||
| 367 | |||
| 368 | (ert-deftest ruby-no-unknown-percent-literals () | ||
| 369 | ;; No folding of case. | ||
| 370 | (ruby-assert-face "%S{foo}" 4 nil) | ||
| 371 | (ruby-assert-face "%R{foo}" 4 nil)) | ||
| 372 | |||
| 356 | (ert-deftest ruby-add-log-current-method-examples () | 373 | (ert-deftest ruby-add-log-current-method-examples () |
| 357 | (let ((pairs '(("foo" . "#foo") | 374 | (let ((pairs '(("foo" . "#foo") |
| 358 | ("C.foo" . ".foo") | 375 | ("C.foo" . ".foo") |