unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* General delimited literals in ruby-mode patch
@ 2012-02-07 23:32 Dmitry Gutov
  2012-02-10  0:42 ` Dmitry Gutov
  0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Gutov @ 2012-02-07 23:32 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 897 bytes --]


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.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: general delimited literals patch --]
[-- Type: text/x-patch, Size: 4421 bytes --]

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, #@foo 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,

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: General delimited literals in ruby-mode patch
  2012-02-07 23:32 General delimited literals in ruby-mode patch Dmitry Gutov
@ 2012-02-10  0:42 ` Dmitry Gutov
  2012-02-10  5:03   ` Dmitry Gutov
  0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Gutov @ 2012-02-10  0:42 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 746 bytes --]

Dmitry Gutov <dgutov@yandex.ru> writes:

> The bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6286.

I missed an entry for general delimited strings in
`font-lock-ruby-keywords'. It didn't break anything, just did
unnecessary work in the certain narrow case which it supported.

Now moved it to `ruby-font-lock-syntactic-keywords' with appropriate
conversion.

Also removed `ruby-general-delimiter-beg-re' as a separate variable,
since its value is used only once.

Not sure if I should touch `ruby-parse-partial', `ruby-forward-sexp',
`ruby-backward-sexp', and `ruby-expr-beg'.

P.S.
Why is the case of (fboundp #'syntax-propertize-rules) being nil still
being handled, by the way?
This ruby-mode is not compatible with Emacs 23 either way.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: general delimited literals patch v2 --]
[-- Type: text/x-patch, Size: 4920 bytes --]

diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index bf26497..e93f8b3 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -793,8 +793,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 +1117,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, #@foo are not comments
@@ -1136,7 +1137,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.
+          ("\\(?:^\\|[[ \t\n<+(,=]\\)\\(%\\)[qQrswWx]?\\([[:punct:]]\\)"
+           (1 (prog1 "|" (ruby-syntax-propertize-general-delimiters end)))))
          (point) end))
 
       (defun ruby-syntax-propertize-heredoc (limit)
@@ -1162,6 +1166,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,
@@ -1206,6 +1245,10 @@ This should only be called after matching against `ruby-here-doc-end-re'."
      (4 (7 . ?/))
      (6 (7 . ?/)))
     ("^=en\\(d\\)\\_>" 1 "!")
+    ;; general delimited string
+    ("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
+     (3 "\"")
+     (5 "\""))
     ("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax))
     ;; Currently, the following case is highlighted incorrectly:
     ;;
@@ -1414,9 +1457,6 @@ See `font-lock-syntax-table'.")
      1 font-lock-variable-name-face)
    '("\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+"
      0 font-lock-variable-name-face)
-   ;; general delimited string
-   '("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
-     (2 font-lock-string-face))
    ;; constants
    '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
      2 font-lock-type-face)

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: General delimited literals in ruby-mode patch
  2012-02-10  0:42 ` Dmitry Gutov
@ 2012-02-10  5:03   ` Dmitry Gutov
  0 siblings, 0 replies; 3+ messages in thread
From: Dmitry Gutov @ 2012-02-10  5:03 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 468 bytes --]

>> The bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6286.

And here's a tentative patch for the last example (regexp as a first
parameter in a paren-less method invocation).

It adds a check whether the regexp is followed by a comma or a
block, though, so the full example should look like this:

Given /A user is logged in/ do
  # whatever
end

AFAIK, all Cucumber step definitions need a block (that's where the
definition goes), so it shouldn't be a problem.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: regexp in paren-less call patch --]
[-- Type: text/x-patch, Size: 1888 bytes --]

diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index e93f8b3..a0a6509 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -1130,9 +1130,8 @@ See `add-log-current-defun-function'."
                         (nth 3 (syntax-ppss (match-beginning 0))))
                 (string-to-syntax "\\"))))
           ;; regexps
-          ("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
-           (4 "\"/")
-           (6 "\"/"))
+          ("\\(^\\|[[=(,~?:;<>]\\|\\(?:^\\|\\s \\)\\(?:if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)?\\s *\\(/\\)[^/\n\\\\]*\\(?:\\\\.[^/\n\\\\]*\\)*\\(/\\)"
+           (2 (ruby-syntax-propertize-regexp)))
           ("^=en\\(d\\)\\_>" (1 "!"))
           ("^\\(=\\)begin\\_>" (1 "!"))
           ;; Handle here documents.
@@ -1143,6 +1142,21 @@ See `add-log-current-defun-function'."
            (1 (prog1 "|" (ruby-syntax-propertize-general-delimiters end)))))
          (point) end))
 
+      (defun ruby-syntax-propertize-regexp ()
+        (let ((syn (string-to-syntax "\"/")))
+          (goto-char (match-end 3))
+          (if (or
+               ;; after paren, comma, operator, control flow keyword,
+               ;; or a method from hardcoded list
+               (match-beginning 1)
+               ;; followed by comma or block
+               (looking-at "[imxo]*\\s *\\(?:,\\|\\<do\\>\\)"))
+              (progn
+                (put-text-property (1- (point)) (point)
+                                   'syntax-table syn)
+                syn)
+            (goto-char (match-end 2)))))
+
       (defun ruby-syntax-propertize-heredoc (limit)
         (let ((ppss (syntax-ppss))
               (res '()))

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-02-10  5:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-07 23:32 General delimited literals in ruby-mode patch Dmitry Gutov
2012-02-10  0:42 ` Dmitry Gutov
2012-02-10  5:03   ` Dmitry Gutov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).