summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust-mode-tests.el64
-rw-r--r--rust-mode.el100
2 files changed, 127 insertions, 37 deletions
diff --git a/rust-mode-tests.el b/rust-mode-tests.el
index c0543b6..bdd7d63 100644
--- a/rust-mode-tests.el
+++ b/rust-mode-tests.el
@@ -452,6 +452,70 @@ fn foo() {
"
))
+(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)]
+mod 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
diff --git a/rust-mode.el b/rust-mode.el
index a2e1fc0..b304df8 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -59,61 +59,87 @@
(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, brace or single pipe (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))))))
+ (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