From: Stefan Monnier Date: Sat, 5 Oct 2013 18:37:08 +0000 (-0400) Subject: Get Ruby's SMIE code to pass the test suite. X-Git-Tag: emacs-24.3.90~173^2^2~42^2~45^2~387^2~1376 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=34d1a1337df479908d6a7076a35d693050ae518d;p=emacs.git Get Ruby's SMIE code to pass the test suite. * lisp/progmodes/ruby-mode.el (ruby-use-smie): Change default. (ruby-comment-column): Follow the global default, by default. (ruby-smie-grammar): Add assignment syntax. (ruby-smie--implicit-semi-p): No implicit semi-colon after an open-paren, a comma, or a \. (ruby-smie--forward-token, ruby-smie--backward-token): Handle heredocs, and line continuations. (ruby-smie-rules): Adjust handling of open-paren, now that it's never followed by implicit semi-colons. Add rule for string concatenation and for indentation at BOB. (ruby-forward-sexp, ruby-backward-sexp): Adjust for when smie is in use. * lisp/emacs-lisp/smie.el (smie-next-sexp): Don't go back to pos before calling next-sexp, since next-token may have skipped chars which next-sexp doesn't know should be skipped! * test/indent/ruby.rb: Port a few cases from automated/ruby-mode-tests.el. Adjust indentation of continued line to the new SMIE behavior. --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e3ca8751535..a7fbec849b5 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,7 +1,25 @@ +2013-10-05 Stefan Monnier + + * progmodes/ruby-mode.el (ruby-use-smie): Change default. + (ruby-comment-column): Follow the global default, by default. + (ruby-smie-grammar): Add assignment syntax. + (ruby-smie--implicit-semi-p): No implicit semi-colon after an + open-paren, a comma, or a \. + (ruby-smie--forward-token, ruby-smie--backward-token): Handle heredocs, + and line continuations. + (ruby-smie-rules): Adjust handling of open-paren, now that it's never + followed by implicit semi-colons. Add rule for string concatenation + and for indentation at BOB. + (ruby-forward-sexp, ruby-backward-sexp): Adjust for when smie is in use. + + * emacs-lisp/smie.el (smie-next-sexp): Don't go back to pos before + calling next-sexp, since next-token may have skipped chars which + next-sexp doesn't know should be skipped! + 2013-10-05 Leo Liu - * progmodes/octave.el (octave-send-region): Call - compilation-forget-errors. + * progmodes/octave.el (octave-send-region): + Call compilation-forget-errors. 2013-10-04 Xue Fuqiao diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el index f9d0fd9366b..e35cb4a8fc2 100644 --- a/lisp/emacs-lisp/smie.el +++ b/lisp/emacs-lisp/smie.el @@ -707,7 +707,7 @@ Possible return values: ((null toklevels) (when (zerop (length token)) (condition-case err - (progn (goto-char pos) (funcall next-sexp 1) nil) + (progn (funcall next-sexp 1) nil) (scan-error (let ((pos (nth 2 err))) (throw 'return diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 95206c15390..662cef82259 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -144,7 +144,7 @@ This should only be called after matching against `ruby-here-doc-beg-re'." (define-abbrev-table 'ruby-mode-abbrev-table () "Abbrev table in use in Ruby mode buffers.") -(defvar ruby-use-smie nil) +(defvar ruby-use-smie t) (defvar ruby-mode-map (let ((map (make-sparse-keymap))) @@ -198,7 +198,7 @@ This should only be called after matching against `ruby-here-doc-beg-re'." "Indentation of Ruby statements." :type 'integer :group 'ruby) -(defcustom ruby-comment-column 32 +(defcustom ruby-comment-column (default-value 'comment-column) "Indentation column of comments." :type 'integer :group 'ruby) @@ -246,7 +246,7 @@ Also ignores spaces after parenthesis when 'space." '((id) (insts (inst) (insts ";" insts)) (inst (exp) (inst "iuwu-mod" exp)) - (exp (exp1) (exp "," exp)) + (exp (exp1) (exp "," exp) (exp "=" exp)) (exp1 (exp2) (exp2 "?" exp1 ":" exp1)) (exp2 ("def" insts "end") ("begin" insts-rescue-insts "end") @@ -265,7 +265,7 @@ Also ignores spaces after parenthesis when 'space." (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)) + (cases "when" cases) (insts "else" insts)) (expseq (exp) );;(expseq "," expseq) (hashvals (id "=>" exp1) (hashvals "," hashvals)) (insts-rescue-insts (insts) @@ -274,7 +274,7 @@ Also ignores spaces after parenthesis when 'space." (itheni (insts) (exp "then" insts)) (ielsei (itheni) (itheni "else" insts)) (if-body (ielsei) (if-body "elsif" if-body))) - '((nonassoc "in") (assoc ";") (assoc ",")) + '((nonassoc "in") (assoc ";") (assoc ",") (right "=")) '((assoc "when")) '((assoc "elsif")) '((assoc "rescue" "ensure")) @@ -288,7 +288,8 @@ Also ignores spaces after parenthesis when 'space." (save-excursion (skip-chars-backward " \t") (not (or (bolp) - (and (memq (char-before) '(?\; ?- ?+ ?* ?/ ?: ?.)) + (and (memq (char-before) + '(?\; ?- ?+ ?* ?/ ?: ?. ?, ?\[ ?\( ?\{ ?\\)) ;; Make sure it's not the end of a regexp. (not (eq (car (syntax-after (1- (point)))) 7))) (and (memq (char-before) '(?\? ?=)) @@ -305,12 +306,13 @@ Also ignores spaces after parenthesis when 'space." (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)) - ";") + (cond + ((looking-at "\\s\"") "") ;A heredoc or a string. + ((and (looking-at "[\n#]") + (ruby-smie--implicit-semi-p)) ;Only add implicit ; when needed. + (if (eolp) (forward-char 1) (forward-comment 1)) + ";") + (t (forward-comment (point-max)) (if (looking-at ":\\s.+") (progn (goto-char (match-end 0)) (match-string 0)) ;; bug#15208. @@ -321,15 +323,18 @@ Also ignores spaces after parenthesis when 'space." tok "iuwu-mod")) ((equal tok "|") (if (ruby-smie--opening-pipe-p) "opening-|" tok)) - (t tok)))))) + ((and (equal tok "") (looking-at "\\\\\n")) + (goto-char (match-end 0)) (ruby-smie--forward-token)) + (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") - ";") + (cond + ((and (> pos (line-end-position)) (ruby-smie--implicit-semi-p)) + (skip-chars-forward " \t") ";") + ((and (bolp) (not (bobp))) "") ;Presumably a heredoc. + (t (let ((tok (smie-default-backward-token))) (when (and (eq ?: (char-before)) (string-match "\\`\\s." tok)) (forward-char -1) (setq tok (concat ":" tok))) ;; bug#15208. @@ -339,20 +344,31 @@ Also ignores spaces after parenthesis when 'space." tok "iuwu-mod")) ((equal tok "|") (if (ruby-smie--opening-pipe-p) "opening-|" tok)) - (t tok)))))) + ((and (equal tok "") (eq ?\\ (char-before)) (looking-at "\n")) + (forward-char -1) (ruby-smie--backward-token)) + (t tok))))))) (defun ruby-smie-rules (kind token) (pcase (cons kind token) (`(:elem . basic) ruby-indent-level) + ;; "foo" "bar" is the concatenation of the two strings, so the second + ;; should be aligned with the first. + (`(:elem . args) (if (looking-at "\\s\"") 0)) + ;; (`(:after . ",") (smie-rule-separator kind)) (`(:after . ";") (if (smie-rule-parent-p "def" "begin" "do" "class" "module" "for" - "[" "{" "while" "until" "unless" + "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 `"(" `"[" `"{")) + ;; Treat purely syntactic block-constructs as being part of their parent, + ;; when the opening statement is hanging. + (if (smie-rule-hanging-p) (smie-rule-parent))) + (`(:after . "=") 2) (`(:before . "do") (when (save-excursion @@ -369,8 +385,9 @@ Also ignores spaces after parenthesis when 'space." (`(: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))) + ;; appear on a separate line. "" is for the case where the "previous + ;; separator" was not an implicit ";" but the BOB. + (`(:list-intro . ,(or `";" `"")) t))) (defun ruby-imenu-create-index-in-block (prefix beg end) "Create an imenu index of methods inside a block." @@ -1095,8 +1112,10 @@ With ARG, move out of multiple blocks." With ARG, do it many times. Negative ARG means move backward." ;; TODO: Document body (interactive "p") - (if (and (numberp arg) (< arg 0)) - (ruby-backward-sexp (- arg)) + (cond + (ruby-use-smie (forward-sexp arg)) + ((and (numberp arg) (< arg 0)) (ruby-backward-sexp (- arg))) + (t (let ((i (or arg 1))) (condition-case nil (while (> i 0) @@ -1131,15 +1150,17 @@ With ARG, do it many times. Negative ARG means move backward." (not expr)))) (setq i (1- i))) ((error) (forward-word 1))) - i))) + i)))) (defun ruby-backward-sexp (&optional arg) "Move backward across one balanced expression (sexp). With ARG, do it many times. Negative ARG means move forward." ;; TODO: Document body (interactive "p") - (if (and (numberp arg) (< arg 0)) - (ruby-forward-sexp (- arg)) + (cond + (ruby-use-smie (backward-sexp arg)) + ((and (numberp arg) (< arg 0)) (ruby-forward-sexp (- arg))) + (t (let ((i (or arg 1))) (condition-case nil (while (> i 0) @@ -1178,7 +1199,7 @@ With ARG, do it many times. Negative ARG means move forward." nil)) (setq i (1- i))) ((error))) - i))) + i)))) (defun ruby-indent-exp (&optional ignored) "Indent each line in the balanced expression following the point." diff --git a/test/ChangeLog b/test/ChangeLog index b3bcdd9a5bd..ac98b1c3040 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,8 @@ +2013-10-05 Stefan Monnier + + * indent/ruby.rb: Port a few cases from automated/ruby-mode-tests.el. + Adjust indentation of continued line to the new SMIE behavior. + 2013-10-04 Stefan Monnier * automated/completion-tests.el: diff --git a/test/indent/ruby.rb b/test/indent/ruby.rb index 6c9b9775b48..15315bcf653 100644 --- a/test/indent/ruby.rb +++ b/test/indent/ruby.rb @@ -1,3 +1,10 @@ +if something_wrong? # ruby-move-to-block-skips-heredoc + ActiveSupport::Deprecation.warn(<<-eowarn) + boo hoo + end + eowarn +end + # Percent literals. b = %Q{This is a "string"} c = %w!foo @@ -21,6 +28,26 @@ a = asub / aslb + bsub / bslb; # Highlight the regexp after "if". x = toto / foo if /do bar/ =~ "dobar" +bar(class: XXX) do # ruby-indent-keyword-label + foo +end +bar + +foo = [1, # ruby-deep-indent + 2] + +foo = { # ruby-deep-indent-disabled + a : b +} + +foo = [ # ruby-deep-indent-disabled + 1 +] + +foo( # ruby-deep-indent-disabled + a +) + # Multiline regexp. /bars tees # toots @@ -74,4 +101,4 @@ end # Bug#15369 MSG = 'Separate every 3 digits in the integer portion of a number' \ - 'with underscores(_).' + 'with underscores(_).'