]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/ruby-mode.el
* lisp/progmodes/ruby-mode.el (ruby-custom-encoding-magic-comment-template):
[gnu-emacs] / lisp / progmodes / ruby-mode.el
index cb5fe11ada63262bf4b87eda64b7261e77006b84..0e507b821154db5124eda078d5cb1311e08c8119 100644 (file)
@@ -256,7 +256,12 @@ explicitly declared in magic comment."
   :group 'ruby)
 
 (defcustom ruby-insert-encoding-magic-comment t
-  "Insert a magic Emacs 'coding' comment upon save if this is non-nil."
+  "Insert a magic Ruby encoding comment upon save if this is non-nil.
+The encoding will be auto-detected.  The format of the encoding comment
+is customizable via `ruby-encoding-magic-comment-style'.
+
+When set to `always-utf8' an utf-8 comment will always be added,
+even if it's not required."
   :type 'boolean :group 'ruby)
 
 (defcustom ruby-encoding-magic-comment-style 'ruby
@@ -267,7 +272,7 @@ explicitly declared in magic comment."
           (const :tag "Custom Style" custom))
   :group 'ruby)
 
-(defcustom ruby-custom-encoding-magic-comment-template "# coding: %s"
+(defcustom ruby-custom-encoding-magic-comment-template "# encoding: %s"
   "The encoding comment template to be used when
 `ruby-encoding-magic-comment-style' is set to `custom'."
   :type 'string
@@ -310,10 +315,10 @@ explicitly declared in magic comment."
              ("unless" insts "end")
              ("if" if-body "end")
              ("case"  cases "end"))
-       (formal-params ("opening-|" exp "|"))
+       (formal-params ("opening-|" exp "closing-|"))
        (for-body (for-head ";" insts))
        (for-head (id "in" exp))
-       (cases (exp "then" insts) ;; FIXME: Ruby also allows (exp ":" insts).
+       (cases (exp "then" insts)
               (cases "when" cases) (insts "else" insts))
        (expseq (exp) );;(expseq "," expseq)
        (hashvals (id "=>" exp1) (hashvals "," hashvals))
@@ -337,9 +342,8 @@ explicitly declared in magic comment."
        (left ".." "...")
        (left "+" "-")
        (left "*" "/" "%" "**")
-       ;; (left "|") ; FIXME: Conflicts with | after block parameters.
        (left "&&" "||")
-       (left "^" "&")
+       (left "^" "&" "|")
        (nonassoc "<=>")
        (nonassoc ">" ">=" "<" "<=")
        (nonassoc "==" "===" "!=")
@@ -365,7 +369,8 @@ explicitly declared in magic comment."
                   (string-match "\\`\\s." (save-excursion
                                             (ruby-smie--backward-token))))
              (and (eq (char-before) ?|)
-                  (eq (char-before (1- (point))) ?|))
+                  (member (save-excursion (ruby-smie--backward-token))
+                          '("|" "||")))
              (and (eq (car (syntax-after (1- (point)))) 2)
                   (member (save-excursion (ruby-smie--backward-token))
                           '("iuwu-mod" "and" "or")))
@@ -385,6 +390,12 @@ explicitly declared in magic comment."
     (or (eq ?\{ (char-before))
         (looking-back "\\_<do" (- (point) 2)))))
 
+(defun ruby-smie--closing-pipe-p ()
+  (save-excursion
+    (if (eq ?| (char-before)) (forward-char -1))
+    (and (re-search-backward "|" (line-beginning-position) t)
+         (ruby-smie--opening-pipe-p))))
+
 (defun ruby-smie--args-separator-p (pos)
   (and
    (< pos (line-end-position))
@@ -442,7 +453,10 @@ explicitly declared in magic comment."
            ((string-match-p "\\`|[*&]?\\'" tok)
             (forward-char (- 1 (length tok)))
             (setq tok "|")
-            (if (ruby-smie--opening-pipe-p) "opening-|" tok))
+            (cond
+             ((ruby-smie--opening-pipe-p) "opening-|")
+             ((ruby-smie--closing-pipe-p) "closing-|")
+             (t tok)))
            ((and (equal tok "") (looking-at "\\\\\n"))
             (goto-char (match-end 0)) (ruby-smie--forward-token))
            ((equal tok "do")
@@ -482,7 +496,10 @@ explicitly declared in magic comment."
           (if (ruby-smie--bosp)
               tok "iuwu-mod"))
          ((equal tok "|")
-          (if (ruby-smie--opening-pipe-p) "opening-|" tok))
+          (cond
+           ((ruby-smie--opening-pipe-p) "opening-|")
+           ((ruby-smie--closing-pipe-p) "closing-|")
+           (t tok)))
          ((string-match-p "\\`|[*&]\\'" tok)
           (forward-char 1)
           (substring tok 1))
@@ -545,7 +562,7 @@ explicitly declared in magic comment."
      (if (not (smie-rule-sibling-p)) 0)) ;; ruby-indent-level
     (`(:after . ,(or "=" "iuwu-mod" "+" "-" "*" "/" "&&" "||" "%" "**" "^" "&"
                      "<=>" ">" "<" ">=" "<=" "==" "===" "!=" "<<" ">>"
-                     "+=" "-=" "*=" "/=" "%=" "**=" "&=" "|=" "^="
+                     "+=" "-=" "*=" "/=" "%=" "**=" "&=" "|=" "^=" "|"
                      "<<=" ">>=" "&&=" "||=" "and" "or"))
      (if (smie-rule-parent-p ";" nil) ruby-indent-level))
     (`(:before . "begin")
@@ -621,51 +638,60 @@ explicitly declared in magic comment."
   (setq-local paragraph-separate paragraph-start)
   (setq-local paragraph-ignore-fill-prefix t))
 
+(defun ruby--insert-coding-comment (encoding)
+  "Insert a magic coding comment for ENCODING.
+The style of the comment is controlled by `ruby-encoding-magic-comment-style'."
+  (let ((encoding-magic-comment-template
+         (pcase ruby-encoding-magic-comment-style
+           (`ruby "# coding: %s")
+           (`emacs "# -*- coding: %s -*-")
+           (`custom
+            ruby-custom-encoding-magic-comment-template))))
+    (insert
+     (format encoding-magic-comment-template encoding)
+     "\n")))
+
+(defun ruby--detect-encoding ()
+  (if (eq ruby-insert-encoding-magic-comment 'always-utf8)
+      "utf-8"
+    (let ((coding-system
+           (or save-buffer-coding-system
+               buffer-file-coding-system)))
+      (if coding-system
+          (setq coding-system
+                (or (coding-system-get coding-system 'mime-charset)
+                    (coding-system-change-eol-conversion coding-system nil))))
+      (if coding-system
+          (symbol-name
+           (if ruby-use-encoding-map
+               (let ((elt (assq coding-system ruby-encoding-map)))
+                 (if elt (cdr elt) coding-system))
+             coding-system))
+        "ascii-8bit"))))
+
+(defun ruby--encoding-comment-required-p ()
+  (or (eq ruby-insert-encoding-magic-comment 'always-utf8)
+      (re-search-forward "[^\0-\177]" nil t)))
+
 (defun ruby-mode-set-encoding ()
   "Insert a magic comment header with the proper encoding if necessary."
   (save-excursion
     (widen)
     (goto-char (point-min))
-    (when (re-search-forward "[^\0-\177]" nil t)
+    (when (ruby--encoding-comment-required-p)
       (goto-char (point-min))
-      (let ((coding-system
-             (or save-buffer-coding-system
-                 buffer-file-coding-system)))
-        (if coding-system
-            (setq coding-system
-                  (or (coding-system-get coding-system 'mime-charset)
-                      (coding-system-change-eol-conversion coding-system nil))))
-        (setq coding-system
-              (if coding-system
-                  (symbol-name
-                   (if ruby-use-encoding-map
-                       (let ((elt (assq coding-system ruby-encoding-map)))
-                         (if elt (cdr elt) coding-system))
-                     coding-system))
-                "ascii-8bit"))
+      (let ((coding-system (ruby--detect-encoding)))
         (when coding-system
           (if (looking-at "^#!") (beginning-of-line 2))
-          (cond ((looking-at "\\s *#.*-\*-\\s *\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)\\s *\\(;\\|-\*-\\)")
+          (cond ((looking-at "\\s *#\\s *.*\\(en\\)?coding\\s *:\\s *\\([-a-z0-9_]*\\)")
+                 ;; update existing encoding comment if necessary
                  (unless (string= (match-string 2) coding-system)
                    (goto-char (match-beginning 2))
                    (delete-region (point) (match-end 2))
-                   (and (looking-at "-\*-")
-                        (let ((n (skip-chars-backward " ")))
-                          (cond ((= n 0) (insert "  ") (backward-char))
-                                ((= n -1) (insert " "))
-                                ((forward-char)))))
                    (insert coding-system)))
                 ((looking-at "\\s *#.*coding\\s *[:=]"))
                 (t (when ruby-insert-encoding-magic-comment
-                     (let ((encoding-magic-comment-template
-                            (pcase ruby-encoding-magic-comment-style
-                              (`ruby "# coding: %s")
-                              (`emacs "# -*- coding: %s -*-")
-                              (`custom
-                               ruby-custom-encoding-magic-comment-template))))
-                       (insert
-                        (format encoding-magic-comment-template coding-system)
-                        "\n")))))
+                     (ruby--insert-coding-comment coding-system))))
           (when (buffer-modified-p)
             (basic-save-buffer-1)))))))
 
@@ -1564,8 +1590,9 @@ If the result is do-end block, it will always be multiline."
   (let ((start (point)) beg end)
     (end-of-line)
     (unless
-        (if (and (re-search-backward "\\({\\)\\|\\_<do\\(\\s \\|$\\||\\)")
+        (if (and (re-search-backward "\\(?:[^#]\\)\\({\\)\\|\\(\\_<do\\_>\\)")
                  (progn
+                   (goto-char (or (match-beginning 1) (match-beginning 2)))
                    (setq beg (point))
                    (save-match-data (ruby-forward-sexp))
                    (setq end (point))
@@ -1899,7 +1926,7 @@ See `font-lock-syntax-table'.")
     "\\_<\\(?:BEGIN\\|END\\)\\_>\\|^__END__$"
     ;; Variables.
     (,(concat ruby-font-lock-keyword-beg-re
-              "\\_<\\(nil\\|self\\|true\\|false\\)\\>")
+              "\\_<\\(nil\\|self\\|true\\|false\\)\\_>")
      1 font-lock-variable-name-face)
     ;; Keywords that evaluate to certain values.
     ("\\_<__\\(?:LINE\\|ENCODING\\|FILE\\)__\\_>"