Subject: bug#6286: General delimited literals in ruby-mode patch

From: Stefan Monnier <[email-masked]>
Date: Tue, 14 Aug 2012 08:40:04 -0400

> I think the first one is quite important, and I've had a user emailing me
> about it.

Thanks, installed.

> The second one deals with a fairly narrow edge case, so it's kinda optional.

Thanks, installed.

I kind of remember something about this second case, and remember being
bothered by the fact that ruby-syntax-methods-before-regexp would need
to be adjusted by the user since it can depend on its locale
(especially the Given/Then/When).
I also vaguely remember that this problem was related to the reason why
I added the "look after the regexp" test.

It would probably be better if you could commit those changes yourself.
If you want to do that, please request membership in the "emacs" group
from your savannah account (which you may have to create beforehand).

        Stefan

> diff --git a/lisp/ChangeLog b/lisp/ChangeLog
> index 4f52796..f37c346 100644
> --- a/lisp/ChangeLog
> +++ b/lisp/ChangeLog
> @@ -9,6 +9,9 @@
>  	(ruby-syntax-propertize-percent-literal): Only propertize when not
>  	inside a simple string or comment.  When the literal is unclosed,
>  	leave the text after it unpropertized.
> +	(ruby-syntax-methods-before-regexp): New constant.
> +	(ruby-syntax-propertize-function): Use it to recognize regexps.
> +	Don't look at the text after regexp, just use the whitelist.
 
>  2012-08-13  Andreas Schwab  <[email-masked]>
 
> diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
> index 42e1ac7..457c7fe 100644
> --- a/lisp/progmodes/ruby-mode.el
> +++ b/lisp/progmodes/ruby-mode.el
> @@ -1178,7 +1178,13 @@ See `add-log-current-defun-function'."
>        (eval-and-compile
>          (defconst ruby-percent-literal-beg-re
>            "\\(%\\)[qQrswWx]?\\([[:punct:]]\\)"
> -          "Regexp to match the beginning of percent literal."))
> +          "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.
> +It will be properly highlighted even when the call omits parens."))
 
>        (defun ruby-syntax-propertize-function (start end)
>          "Syntactic keywords for Ruby mode.  See `syntax-propertize-function'."
> @@ -1196,28 +1202,23 @@ See `add-log-current-defun-function'."
>                          ;; Not within a string.
>                          (nth 3 (syntax-ppss (match-beginning 0))))
>                  (string-to-syntax "\\"))))
> -          ;; Regexps: regexps are distinguished from division either because
> -          ;; of the keyword/symbol before them, or because of the code
> -          ;; following them.
> +          ;; Regexps: regexps are distinguished from division because
> +          ;; of the keyword, symbol, or method name before them.
>            ((concat
>              ;; Special tokens that can't be followed by a division operator.
> -            "\\(?:\\(^\\|[[=(,~?:;<>]\\|\\(?:^\\|\\s \\)"
> +            "\\(^\\|[[=(,~?:;<>]"
> +            ;; Control flow keywords and operators following bol or whitespace.
> +            "\\|\\(?:^\\|\\s \\)"
>              (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
> -                          "or" "&&" "||"
> -                          "gsub" "gsub!" "sub" "sub!" "scan" "split" "split!"))
> -            "\\)\\s *\\)?"
> +                          "or" "not" "&&" "||"))
> +            ;; Method name from the list.
> +            "\\|\\_<"
> +            (regexp-opt ruby-syntax-methods-before-regexp)
> +            "\\)\\s *"
>              ;; The regular expression itself.
> -            "\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)"
> -            ;; Special code that cannot follow a division operator.
> -            ;; FIXME: Just because the second slash of "/foo/ do bar" can't
> -            ;; be a division, doesn't mean it can't *start* a regexp, as in
> -            ;; "x = toto/foo; if /do bar/".
> -            "\\([imxo]*\\s *\\(?:,\\|\\_<do\\_>\\)\\)?")
> -           (2 (when (or (match-beginning 1) (match-beginning 4))
> -                (string-to-syntax "\"/")))
> -           (3 (if (or (match-beginning 1) (match-beginning 4))
> -                  (string-to-syntax "\"/")
> -                (goto-char (match-end 2)))))
> +            "\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)")
> +           (2 (string-to-syntax "\"/"))
> +           (3 (string-to-syntax "\"/")))
>            ("^=en\\(d\\)\\_>" (1 "!"))
>            ("^\\(=\\)begin\\_>" (1 "!"))
>            ;; Handle here documents.
> diff --git a/test/ChangeLog b/test/ChangeLog
> index 9dbca3d..f1bf458 100644
> --- a/test/ChangeLog
> +++ b/test/ChangeLog
> @@ -1,6 +1,6 @@
>  2012-08-14  Dmitry Gutov  <[email-masked]>
 
> -	* indent/ruby.rb: New examples.
> +	* indent/ruby.rb: Rearrange examples, add new ones.
 
>  2012-08-12  Dmitry Gutov  <[email-masked]>
 
> diff --git a/test/indent/ruby.rb b/test/indent/ruby.rb
> index 7a9d123..4f2e9e6 100644
> --- a/test/indent/ruby.rb
> +++ b/test/indent/ruby.rb
> @@ -1,24 +1,25 @@
> -# Don't mis-match "sub" at the end of words.
> -a = asub / aslb + bsub / bslb;
> -
> +# Percent literals.
>  b = %Q{This is a "string"}
> -c = %w(foo
> +c = %w!foo
>   bar
> - baz)
> -d = %!hello!
> + baz!
> +d = %(hello (nested) world)
 
>  # Don't propertize percent literals inside strings.
>  "(%s, %s)" % [123, 456]
 
> -# Nor inside comments.
> +# Or inside comments.
>  x = # "tot %q/to"; =
>  y = 2 / 3
 
> -# A "do" after a slash means that slash is not a division, but it doesn't imply
> -# it's a regexp-ender, since it can be a regexp-starter instead!
> -x = toto / foo; if /do bar/ then
> -                  toto = 1
> -                end
> +# Regexp after whitelisted method.
> +"abc".sub /b/, 'd'
> +
> +# Don't mis-match "sub" at the end of words.
> +a = asub / aslb + bsub / bslb;
> +
> +# Highlight the regexp after "if".
> +x = toto / foo if /do bar/ =~ "dobar"
 
>  # Some Cucumber code:
>  Given /toto/ do