|
89 | 89 | (backward-word 1))
|
90 | 90 | (current-column))))
|
91 | 91 |
|
92 |
| -(defun rust-align-to-method-chain () |
93 |
| - (save-excursion |
94 |
| - (previous-line) |
95 |
| - (end-of-line) |
96 |
| - (backward-word 1) |
97 |
| - (backward-char) |
98 |
| - (when (looking-at "\\..+\(.*\)\n") |
99 |
| - (- (current-column) rust-indent-offset)))) |
100 |
| - |
101 | 92 | (defun rust-rewind-to-beginning-of-current-level-expr ()
|
102 | 93 | (let ((current-level (rust-paren-level)))
|
103 | 94 | (back-to-indentation)
|
104 | 95 | (while (> (rust-paren-level) current-level)
|
105 | 96 | (backward-up-list)
|
106 | 97 | (back-to-indentation))))
|
107 | 98 |
|
| 99 | +(defun rust-align-to-method-chain () |
| 100 | + (save-excursion |
| 101 | + ;; for method-chain alignment to apply, we must be looking at |
| 102 | + ;; another method call or field access or something like |
| 103 | + ;; that. This avoids rather "eager" jumps in situations like: |
| 104 | + ;; |
| 105 | + ;; { |
| 106 | + ;; something.foo() |
| 107 | + ;; <indent> |
| 108 | + ;; |
| 109 | + ;; Without this check, we would wind up with the cursor under the |
| 110 | + ;; `.`. In an older version, I had the inverse of the current |
| 111 | + ;; check, where we checked for situations that should NOT indent, |
| 112 | + ;; vs checking for the one situation where we SHOULD. It should be |
| 113 | + ;; clear that this is more robust, but also I find it mildly less |
| 114 | + ;; annoying to have to press tab again to align to a method chain |
| 115 | + ;; than to have an over-eager indent in all other cases which must |
| 116 | + ;; be undone via tab. |
| 117 | + |
| 118 | + (when (looking-at (concat "\s*\." rust-re-ident)) |
| 119 | + (previous-line) |
| 120 | + (end-of-line) |
| 121 | + |
| 122 | + (let |
| 123 | + ;; skip-dot-identifier is used to position the point at the |
| 124 | + ;; `.` when looking at something like |
| 125 | + ;; |
| 126 | + ;; foo.bar |
| 127 | + ;; ^ ^ |
| 128 | + ;; | | |
| 129 | + ;; | position of point |
| 130 | + ;; returned offset |
| 131 | + ;; |
| 132 | + ((skip-dot-identifier |
| 133 | + (lambda () |
| 134 | + (when (looking-back (concat "\." rust-re-ident)) |
| 135 | + (backward-word 1) |
| 136 | + (backward-char) |
| 137 | + (- (current-column) rust-indent-offset))))) |
| 138 | + (cond |
| 139 | + ;; foo.bar(...) |
| 140 | + ((looking-back ")") |
| 141 | + (backward-list 1) |
| 142 | + (funcall skip-dot-identifier)) |
| 143 | + |
| 144 | + ;; foo.bar |
| 145 | + (t (funcall skip-dot-identifier))))))) |
| 146 | + |
108 | 147 | (defun rust-mode-indent-line ()
|
109 | 148 | (interactive)
|
110 | 149 | (let ((indent
|
|
123 | 162 | (or
|
124 | 163 | (when rust-indent-method-chain
|
125 | 164 | (rust-align-to-method-chain))
|
126 |
| - (save-excursion |
127 |
| - (backward-up-list) |
128 |
| - (rust-rewind-to-beginning-of-current-level-expr) |
129 |
| - (+ (current-column) rust-indent-offset)))))) |
| 165 | + (save-excursion |
| 166 | + (backward-up-list) |
| 167 | + (rust-rewind-to-beginning-of-current-level-expr) |
| 168 | + (+ (current-column) rust-indent-offset)))))) |
130 | 169 | (cond
|
131 | 170 | ;; A function return type is indented to the corresponding function arguments
|
132 | 171 | ((looking-at "->")
|
|
137 | 176 |
|
138 | 177 | ;; A closing brace is 1 level unindended
|
139 | 178 | ((looking-at "}") (- baseline rust-indent-offset))
|
140 |
| - |
141 |
| - ;;Line up method chains by their .'s |
142 |
| - ((when (and rust-indent-method-chain |
143 |
| - (looking-at "\..+\(.*\);?\n")) |
144 |
| - (or |
145 |
| - (let ((method-indent (rust-align-to-method-chain))) |
146 |
| - (when method-indent |
147 |
| - (+ method-indent rust-indent-offset))) |
148 |
| - (+ baseline rust-indent-offset)))) |
149 |
| - |
150 | 179 |
|
151 | 180 | ;; Doc comments in /** style with leading * indent to line up the *s
|
152 | 181 | ((and (nth 4 (syntax-ppss)) (looking-at "*"))
|
@@ -452,11 +481,84 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
|
452 | 481 | ;; There is no opening brace, so consider the whole buffer to be one "defun"
|
453 | 482 | (goto-char (point-max))))
|
454 | 483 |
|
| 484 | +;; Angle-bracket matching. This is kind of a hack designed to deal |
| 485 | +;; with the fact that we can't add angle-brackets to the list of |
| 486 | +;; matching characters unconditionally. Basically we just have some |
| 487 | +;; special-case code such that whenever `>` is typed, we look |
| 488 | +;; backwards to find a matching `<` and highlight it, whether or not |
| 489 | +;; this is *actually* appropriate. This could be annoying so it is |
| 490 | +;; configurable (but on by default because it's awesome). |
| 491 | + |
| 492 | +(defcustom rust-blink-matching-angle-brackets t |
| 493 | + "Blink matching `<` (if any) when `>` is typed" |
| 494 | + :type 'boolean |
| 495 | + :group 'rust-mode) |
| 496 | + |
| 497 | +(defvar rust-point-before-matching-angle-bracket 0) |
| 498 | + |
| 499 | +(defvar rust-matching-angle-bracker-timer nil) |
| 500 | + |
| 501 | +(defun rust-find-matching-angle-bracket () |
| 502 | + (save-excursion |
| 503 | + (let ((angle-brackets 1) |
| 504 | + (start-point (point)) |
| 505 | + (invalid nil)) |
| 506 | + (while (and |
| 507 | + ;; didn't find a match |
| 508 | + (> angle-brackets 0) |
| 509 | + ;; we have no guarantee of a match, so give up eventually |
| 510 | + (< (- start-point (point)) blink-matching-paren-distance) |
| 511 | + ;; didn't hit the top of the buffer |
| 512 | + (> (point) (point-min)) |
| 513 | + ;; didn't hit something else weird like a `;` |
| 514 | + (not invalid)) |
| 515 | + (backward-char 1) |
| 516 | + (cond |
| 517 | + ((looking-at ">") |
| 518 | + (setq angle-brackets (+ angle-brackets 1))) |
| 519 | + ((looking-at "<") |
| 520 | + (setq angle-brackets (- angle-brackets 1))) |
| 521 | + ((looking-at "[;{]") |
| 522 | + (setq invalid t)))) |
| 523 | + (cond |
| 524 | + ((= angle-brackets 0) (point)) |
| 525 | + (t nil))))) |
| 526 | + |
| 527 | +(defun rust-restore-point-after-angle-bracket () |
| 528 | + (goto-char rust-point-before-matching-angle-bracket) |
| 529 | + (when rust-matching-angle-bracker-timer |
| 530 | + (cancel-timer rust-matching-angle-bracker-timer)) |
| 531 | + (setq rust-matching-angle-bracker-timer nil) |
| 532 | + (remove-hook 'pre-command-hook 'rust-restore-point-after-angle-bracket)) |
| 533 | + |
| 534 | +(defun rust-match-angle-bracket-hook () |
| 535 | + "If the most recently inserted character is a `>`, briefly moves point to matching `<` (if any)." |
| 536 | + (interactive) |
| 537 | + (when (and rust-blink-matching-angle-brackets |
| 538 | + (looking-back ">")) |
| 539 | + (let ((matching-angle-bracket-point (save-excursion |
| 540 | + (backward-char 1) |
| 541 | + (rust-find-matching-angle-bracket)))) |
| 542 | + (when matching-angle-bracket-point |
| 543 | + (progn |
| 544 | + (setq rust-point-before-matching-angle-bracket (point)) |
| 545 | + (goto-char matching-angle-bracket-point) |
| 546 | + (add-hook 'pre-command-hook 'rust-restore-point-after-angle-bracket) |
| 547 | + (setq rust-matching-angle-bracker-timer |
| 548 | + (run-at-time blink-matching-delay nil 'rust-restore-point-after-angle-bracket))))))) |
| 549 | + |
| 550 | +(defun rust-match-angle-bracket () |
| 551 | + "The point should be placed on a `>`. Finds the matching `<` and moves point there." |
| 552 | + (interactive) |
| 553 | + (let ((matching-angle-bracket-point (rust-find-matching-angle-bracket))) |
| 554 | + (if matching-angle-bracket-point |
| 555 | + (goto-char matching-angle-bracket-point) |
| 556 | + (message "no matching angle bracket found")))) |
| 557 | + |
455 | 558 | ;; For compatibility with Emacs < 24, derive conditionally
|
456 | 559 | (defalias 'rust-parent-mode
|
457 | 560 | (if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
|
458 | 561 |
|
459 |
| - |
460 | 562 | ;;;###autoload
|
461 | 563 | (define-derived-mode rust-mode rust-parent-mode "Rust"
|
462 | 564 | "Major mode for Rust code."
|
@@ -490,6 +592,7 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
|
490 | 592 | (setq-local end-of-defun-function 'rust-end-of-defun)
|
491 | 593 | (setq-local parse-sexp-lookup-properties t)
|
492 | 594 | (add-hook 'syntax-propertize-extend-region-functions 'rust-syntax-propertize-extend-region)
|
| 595 | + (add-hook 'post-self-insert-hook 'rust-match-angle-bracket-hook) |
493 | 596 | (setq-local syntax-propertize-function 'rust-syntax-propertize))
|
494 | 597 |
|
495 | 598 | (defun rust-syntax-propertize-extend-region (start end)
|
|
0 commit comments