Skip to content

Commit

Permalink
auto merge of #12486 : MicahChalmer/rust/emacs-fixes-round-3, r=brson
Browse files Browse the repository at this point in the history
I've added details in the description of each comment as to what it does, which I won't redundantly repeat here in the PR.  They all relate to indentation in the emacs rust-mode.

What I will note here is that this closes #8787.  It addresses the last remaining case (not in the original issue description but in a comment), of indenting `match` statements.  With the changes here, I believe every problem described in the issue description or comments of #8787 is addressed.
  • Loading branch information
bors committed Feb 27, 2014
2 parents fd02f90 + 04dc3e4 commit 780adff
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 47 deletions.
169 changes: 168 additions & 1 deletion src/etc/emacs/rust-mode-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,108 @@ fn foo()
"
))

(ert-deftest indent-match ()
(test-indent
"
fn foo() {
match blah {
Pattern => stuff(),
_ => whatever
}
}
"
))

(ert-deftest indent-match-multiline-pattern ()
(test-indent
"
fn foo() {
match blah {
Pattern |
Pattern2 => {
hello()
},
_ => whatever
}
}
"
))

(ert-deftest indent-indented-match ()
(test-indent
"
fn foo() {
let x =
match blah {
Pattern |
Pattern2 => {
hello()
},
_ => whatever
};
y();
}
"
))

(ert-deftest indent-curly-braces-within-parens ()
(test-indent
"
fn foo() {
let x =
foo(bar(|x| {
only_one_indent_here();
}));
y();
}
"
))

(ert-deftest indent-weirdly-indented-block ()
(rust-test-manip-code
"
fn foo() {
{
this_block_is_over_to_the_left_for_some_reason();
}
}
"
16
#'indent-for-tab-command
"
fn foo() {
{
this_block_is_over_to_the_left_for_some_reason();
}
}
"
))

(ert-deftest indent-multi-line-attrib ()
(test-indent
"
#[attrib(
this,
that,
theotherthing)]
fn function_with_multiline_attribute() {}
"
))


;; Make sure that in effort to cover match patterns we don't mistreat || or expressions
(ert-deftest indent-nonmatch-or-expression ()
(test-indent
"
fn foo() {
let x = foo() ||
bar();
}
"
))

(setq rust-test-motion-string
"
fn fn1(arg: int) -> bool {
Expand All @@ -450,6 +552,26 @@ struct Foo {
}
"
rust-test-region-string rust-test-motion-string
rust-test-indent-motion-string
"
fn blank_line(arg:int) -> bool {
}
fn indenting_closing_brace() {
if(true) {
}
}
fn indenting_middle_of_line() {
if(true) {
push_me_out();
} else {
pull_me_back_in();
}
}
"

;; Symbol -> (line column)
rust-test-positions-alist '((start-of-fn1 (2 0))
(start-of-fn1-middle-of-line (2 15))
Expand All @@ -464,7 +586,17 @@ struct Foo {
(middle-of-fn3 (16 4))
(middle-of-struct (21 10))
(before-start-of-struct (19 0))
(after-end-of-struct (23 0))))
(after-end-of-struct (23 0))
(blank-line-indent-start (3 0))
(blank-line-indent-target (3 4))
(closing-brace-indent-start (8 1))
(closing-brace-indent-target (8 5))
(middle-push-indent-start (13 2))
(middle-push-indent-target (13 9))
(after-whitespace-indent-start (13 1))
(after-whitespace-indent-target (13 8))
(middle-pull-indent-start (15 19))
(middle-pull-indent-target (15 12))))

(defun rust-get-buffer-pos (pos-symbol)
"Get buffer position from POS-SYMBOL.
Expand Down Expand Up @@ -626,3 +758,38 @@ All positions are position symbols found in `rust-test-positions-alist'."
'middle-of-struct
'before-start-of-struct 'after-end-of-struct
#'mark-defun))

(ert-deftest indent-line-blank-line-motion ()
(rust-test-motion
rust-test-indent-motion-string
'blank-line-indent-start
'blank-line-indent-target
#'indent-for-tab-command))

(ert-deftest indent-line-closing-brace-motion ()
(rust-test-motion
rust-test-indent-motion-string
'closing-brace-indent-start
'closing-brace-indent-target
#'indent-for-tab-command))

(ert-deftest indent-line-middle-push-motion ()
(rust-test-motion
rust-test-indent-motion-string
'middle-push-indent-start
'middle-push-indent-target
#'indent-for-tab-command))

(ert-deftest indent-line-after-whitespace-motion ()
(rust-test-motion
rust-test-indent-motion-string
'after-whitespace-indent-start
'after-whitespace-indent-target
#'indent-for-tab-command))

(ert-deftest indent-line-middle-pull-motion ()
(rust-test-motion
rust-test-indent-motion-string
'middle-pull-indent-start
'middle-pull-indent-target
#'indent-for-tab-command))
117 changes: 71 additions & 46 deletions src/etc/emacs/rust-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -59,70 +59,95 @@
(backward-word 1))
(current-column))))

(defun rust-rewind-to-beginning-of-current-level-expr ()
(let ((current-level (rust-paren-level)))
(back-to-indentation)
(while (> (rust-paren-level) current-level)
(backward-up-list)
(back-to-indentation))))

(defun rust-mode-indent-line ()
(interactive)
(let ((indent
(save-excursion
(back-to-indentation)
(let ((level (rust-paren-level)))
;; Point is now at beginning of current line
(let* ((level (rust-paren-level))
(baseline
;; Our "baseline" is one level out from the indentation of the expression
;; containing the innermost enclosing opening bracket. That
;; way if we are within a block that has a different
;; indentation than this mode would give it, we still indent
;; the inside of it correctly relative to the outside.
(if (= 0 level)
0
(save-excursion
(backward-up-list)
(rust-rewind-to-beginning-of-current-level-expr)
(+ (current-column) rust-indent-offset)))))
(cond
;; A function return type is indented to the corresponding function arguments
((looking-at "->")
(save-excursion
(backward-list)
(or (rust-align-to-expr-after-brace)
(* rust-indent-offset (+ 1 level)))))
(+ baseline rust-indent-offset))))

;; A closing brace is 1 level unindended
((looking-at "}") (* rust-indent-offset (- level 1)))
((looking-at "}") (- baseline rust-indent-offset))

;; Doc comments in /** style with leading * indent to line up the *s
((and (nth 4 (syntax-ppss)) (looking-at "*"))
(+ 1 (* rust-indent-offset level)))
(+ 1 baseline))

;; If we're in any other token-tree / sexp, then:
;; - [ or ( means line up with the opening token
;; - { means indent to either nesting-level * rust-indent-offset,
;; or one further indent from that if either current line
;; begins with 'else', or previous line didn't end in
;; semi, comma or brace (other than whitespace and line
;; comments) , and wasn't an attribute. But if we have
;; something after the open brace and ending with a comma,
;; treat it as fields and align them. PHEW.
((> level 0)
(let ((pt (point)))
(rust-rewind-irrelevant)
(backward-up-list)
(or (and (looking-at "[[({]")
(rust-align-to-expr-after-brace))
(progn
(goto-char pt)
(back-to-indentation)
(if (looking-at "\\<else\\>")
(* rust-indent-offset (+ 1 level))
(progn
(goto-char pt)
(beginning-of-line)
(rust-rewind-irrelevant)
(end-of-line)
(if (looking-back
"[[,;{}(][[:space:]]*\\(?://.*\\)?")
(* rust-indent-offset level)
(back-to-indentation)
(if (looking-at "#")
(* rust-indent-offset level)
(* rust-indent-offset (+ 1 level))))))))))

;; Otherwise we're in a column-zero definition
(t 0))))))
(cond
;; If we're to the left of the indentation, reindent and jump to it.
((<= (current-column) indent)
(indent-line-to indent))

;; We're to the right; if it needs indent, do so but save excursion.
((not (eq (current-indentation) indent))
(save-excursion (indent-line-to indent))))))
(t
(or
;; If we are inside a pair of braces, with something after the
;; open brace on the same line and ending with a comma, treat
;; it as fields and align them.
(when (> level 0)
(save-excursion
(rust-rewind-irrelevant)
(backward-up-list)
;; Point is now at the beginning of the containing set of braces
(rust-align-to-expr-after-brace)))

(progn
(back-to-indentation)
;; Point is now at the beginning of the current line
(if (or
;; If this line begins with "else" or "{", stay on the
;; baseline as well (we are continuing an expression,
;; but the "else" or "{" should align with the beginning
;; of the expression it's in.)
(looking-at "\\<else\\>\\|{")

(save-excursion
(rust-rewind-irrelevant)
;; Point is now at the end of the previous ine
(or
;; If we are at the first line, no indentation is needed, so stay at baseline...
(= 1 (line-number-at-pos (point)))
;; ..or if the previous line ends with any of these:
;; { ? : ( , ; [ }
;; then we are at the beginning of an expression, so stay on the baseline...
(looking-back "[(,:;?[{}]\\|[^|]|")
;; or if the previous line is the end of an attribute, stay at the baseline...
(progn (rust-rewind-to-beginning-of-current-level-expr) (looking-at "#")))))
baseline

;; Otherwise, we are continuing the same expression from the previous line,
;; so add one additional indent level
(+ baseline rust-indent-offset))))))))))
(when (not (eq (current-indentation) indent))
;; If we're at the beginning of the line (before or at the current
;; indentation), jump with the indentation change. Otherwise, save the
;; excursion so that adding the indentations will leave us at the
;; equivalent position within the line to where we were before.
(if (<= (current-column) (current-indentation))
(indent-line-to indent)
(save-excursion (indent-line-to indent))))))


;; Font-locking definitions and helpers
Expand Down

0 comments on commit 780adff

Please sign in to comment.