emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r112522: * lisp/progmodes/ruby-mode.e


From: Stefan Monnier
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r112522: * lisp/progmodes/ruby-mode.el: First cut at SMIE support.
Date: Wed, 08 May 2013 16:25:57 -0400
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 112522
committer: Stefan Monnier <address@hidden>
branch nick: trunk
timestamp: Wed 2013-05-08 16:25:57 -0400
message:
  * lisp/progmodes/ruby-mode.el: First cut at SMIE support.
  (ruby-use-smie): New var.
  (ruby-smie-grammar): New constant.
  (ruby-smie--bosp, ruby-smie--implicit-semi-p)
  (ruby-smie--forward-token, ruby-smie--backward-token)
  (ruby-smie-rules): New functions.
  (ruby-mode-variables): Setup SMIE if applicable.
  * test/indent/ruby.rb: Fix indentation after =; add more cases.
modified:
  lisp/ChangeLog
  lisp/progmodes/ruby-mode.el
  test/ChangeLog
  test/indent/ruby.rb
=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-05-08 18:05:40 +0000
+++ b/lisp/ChangeLog    2013-05-08 20:25:57 +0000
@@ -1,3 +1,13 @@
+2013-05-08  Stefan Monnier  <address@hidden>
+
+       * progmodes/ruby-mode.el: First cut at SMIE support.
+       (ruby-use-smie): New var.
+       (ruby-smie-grammar): New constant.
+       (ruby-smie--bosp, ruby-smie--implicit-semi-p)
+       (ruby-smie--forward-token, ruby-smie--backward-token)
+       (ruby-smie-rules): New functions.
+       (ruby-mode-variables): Setup SMIE if applicable.
+
 2013-05-08  Eli Zaretskii  <address@hidden>
 
        * simple.el (line-move-visual): Signal beginning/end of buffer

=== modified file 'lisp/progmodes/ruby-mode.el'
--- a/lisp/progmodes/ruby-mode.el       2013-04-15 23:07:14 +0000
+++ b/lisp/progmodes/ruby-mode.el       2013-05-08 20:25:57 +0000
@@ -148,13 +148,16 @@
 (define-abbrev-table 'ruby-mode-abbrev-table ()
   "Abbrev table in use in Ruby mode buffers.")
 
+(defvar ruby-use-smie nil)
+
 (defvar ruby-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "M-C-b") 'ruby-backward-sexp)
-    (define-key map (kbd "M-C-f") 'ruby-forward-sexp)
+    (unless ruby-use-smie
+      (define-key map (kbd "M-C-b") 'ruby-backward-sexp)
+      (define-key map (kbd "M-C-f") 'ruby-forward-sexp)
+      (define-key map (kbd "M-C-q") 'ruby-indent-exp))
     (define-key map (kbd "M-C-p") 'ruby-beginning-of-block)
     (define-key map (kbd "M-C-n") 'ruby-end-of-block)
-    (define-key map (kbd "M-C-q") 'ruby-indent-exp)
     (define-key map (kbd "C-c {") 'ruby-toggle-block)
     map)
   "Keymap used in Ruby mode.")
@@ -236,6 +239,111 @@
 (put 'ruby-comment-column 'safe-local-variable 'integerp)
 (put 'ruby-deep-arglist 'safe-local-variable 'booleanp)
 
+;;; SMIE support
+
+(require 'smie)
+
+(defconst ruby-smie-grammar
+  ;; FIXME: Add support for Cucumber.
+  (smie-prec2->grammar
+   (smie-bnf->prec2
+    '((id)
+      (insts (inst) (insts ";" insts))
+      (inst (exp) (inst "iuwu-mod" exp))
+      (exp  (exp1) (exp "," exp))
+      (exp1 (exp2) (exp2 "?" exp1 ":" exp1))
+      (exp2 ("def" insts "end")
+            ("begin" insts-rescue-insts "end")
+            ("do" insts "end")
+            ("class" insts "end") ("module" insts "end")
+            ("for" for-body "end")
+            ("[" expseq "]")
+            ("{" hashvals "}")
+            ("while" insts "end")
+            ("until" insts "end")
+            ("unless" insts "end")
+            ("if" if-body "end")
+            ("case"  cases "end"))
+      (for-body (for-head ";" insts))
+      (for-head (id "in" exp))
+      (cases (exp "then" insts) ;; FIXME: Ruby also allows (exp ":" insts).
+             (cases "when" cases) (insts "else" insts))
+      (expseq (exp) );;(expseq "," expseq)
+      (hashvals (id "=>" exp1) (hashvals "," hashvals))
+      (insts-rescue-insts (insts)
+                          (insts-rescue-insts "rescue" insts-rescue-insts)
+                          (insts-rescue-insts "ensure" insts-rescue-insts))
+      (itheni (insts) (exp "then" insts))
+      (ielsei (itheni) (itheni "else" insts))
+      (if-body (ielsei) (if-body "elsif" if-body)))
+    '((nonassoc "in") (assoc ";") (assoc ","))
+    '((assoc "when"))
+    '((assoc "elsif"))
+    '((assoc "rescue" "ensure"))
+    '((assoc ",")))))
+
+(defun ruby-smie--bosp ()
+  (save-excursion (skip-chars-backward " \t")
+                  (or (bolp) (eq (char-before) ?\;))))
+
+(defun ruby-smie--implicit-semi-p ()
+  (save-excursion
+    (skip-chars-backward " \t")
+    (not (or (bolp)
+             (memq (char-before) '(?\; ?- ?+ ?* ?/ ?:))
+             (and (memq (char-before) '(?\? ?=))
+                  (not (memq (char-syntax (char-before (1- (point))))
+                             '(?w ?_))))))))
+
+(defun ruby-smie--forward-token ()
+  (skip-chars-forward " \t")
+  (if (and (looking-at "[\n#]")
+           ;; Only add implicit ; when needed.
+           (ruby-smie--implicit-semi-p))
+      (progn
+        (if (eolp) (forward-char 1) (forward-comment 1))
+        ";")
+    (forward-comment (point-max))
+    (let ((tok (smie-default-forward-token)))
+      (cond
+       ((member tok '("unless" "if" "while" "until"))
+        (if (save-excursion (forward-word -1) (ruby-smie--bosp))
+            tok "iuwu-mod"))
+       (t tok)))))
+
+(defun ruby-smie--backward-token ()
+  (let ((pos (point)))
+    (forward-comment (- (point)))
+    (if (and (> pos (line-end-position))
+             (ruby-smie--implicit-semi-p))
+        (progn (skip-chars-forward " \t")
+               ";")
+      (let ((tok (smie-default-backward-token)))
+        (cond
+         ((member tok '("unless" "if" "while" "until"))
+          (if (ruby-smie--bosp)
+              tok "iuwu-mod"))
+         (t tok))))))
+
+(defun ruby-smie-rules (kind token)
+  (pcase (cons kind token)
+    (`(:elem . basic) ruby-indent-level)
+    (`(:after . ";")
+     (if (smie-rule-parent-p "def" "begin" "do" "class" "module" "for"
+                             "[" "{" "while" "until" "unless"
+                             "if" "then" "elsif" "else" "when"
+                             "rescue" "ensure")
+         (smie-rule-parent ruby-indent-level)
+       ;; For (invalid) code between switch and case.
+       ;; (if (smie-parent-p "switch") 4)
+       0))
+    (`(:before . ,(or `"else" `"then" `"elsif")) 0)
+    (`(:before . ,(or `"when"))
+     (if (not (smie-rule-sibling-p)) 0)) ;; ruby-indent-level
+    ;; Hack attack: Since newlines are separators, don't try to align args that
+    ;; appear on a separate line.
+    (`(:list-intro . ";") t)))
+
 (defun ruby-imenu-create-index-in-block (prefix beg end)
   "Create an imenu index of methods inside a block."
   (let ((index-alist '()) (case-fold-search nil)
@@ -290,7 +398,11 @@
   (set-syntax-table ruby-mode-syntax-table)
   (setq local-abbrev-table ruby-mode-abbrev-table)
   (setq indent-tabs-mode ruby-indent-tabs-mode)
-  (set (make-local-variable 'indent-line-function) 'ruby-indent-line)
+  (if ruby-use-smie
+      (smie-setup ruby-smie-grammar #'ruby-smie-rules
+                  :forward-token  #'ruby-smie--forward-token
+                  :backward-token #'ruby-smie--backward-token)
+    (set (make-local-variable 'indent-line-function) 'ruby-indent-line))
   (set (make-local-variable 'require-final-newline) t)
   (set (make-local-variable 'comment-start) "# ")
   (set (make-local-variable 'comment-end) "")

=== modified file 'test/ChangeLog'
--- a/test/ChangeLog    2013-05-05 02:26:38 +0000
+++ b/test/ChangeLog    2013-05-08 20:25:57 +0000
@@ -1,3 +1,7 @@
+2013-05-08  Stefan Monnier  <address@hidden>
+
+       * indent/ruby.rb: Fix indentation after =; add more cases.
+
 2013-05-05  Stefan Monnier  <address@hidden>
 
        * indent/pascal.pas: Add test for mis-identified comments.

=== modified file 'test/indent/ruby.rb'
--- a/test/indent/ruby.rb       2012-08-14 12:38:11 +0000
+++ b/test/indent/ruby.rb       2013-05-08 20:25:57 +0000
@@ -10,7 +10,7 @@
 
 # Or inside comments.
 x = # "tot %q/to"; =
-y = 2 / 3
+  y = 2 / 3
 
 # Regexp after whitelisted method.
 "abc".sub /b/, 'd'
@@ -21,6 +21,40 @@
 # Highlight the regexp after "if".
 x = toto / foo if /do bar/ =~ "dobar"
 
+def test1(arg)
+  puts "hello"
+end
+
+def test2 (arg)
+  a = "apple"
+
+  if a == 2
+    puts "hello"
+  else
+    puts "there"
+  end
+
+  if a == 2 then
+    puts "hello"
+  elsif a == 3
+    puts "hello3"
+  elsif a == 3 then
+    puts "hello3"
+  else
+    puts "there"
+  end
+
+  case a
+  when "a"
+    6
+  # when "b" :
+  #   7
+  # when "c" : 2
+  when "d"  then 4
+  else 5
+  end
+end
+
 # Some Cucumber code:
 Given /toto/ do
   print "hello"


reply via email to

[Prev in Thread] Current Thread [Next in Thread]