[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/rust-mode ec81a95 114/486: Merge pull request #22 from nik
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/rust-mode ec81a95 114/486: Merge pull request #22 from nikomatsakis/align-method-chain |
Date: |
Sat, 7 Aug 2021 09:25:00 -0400 (EDT) |
branch: elpa/rust-mode
commit ec81a95287a69bb36d1535a972e5afb46948247d
Merge: 351cc91 55e7483
Author: Felix S Klock II <pnkfelix@pnkfx.org>
Commit: Felix S Klock II <pnkfelix@pnkfx.org>
Merge pull request #22 from nikomatsakis/align-method-chain
Fix aligning of method chains (more-or-less), add various unit tests, and
add matching angle brackets.
---
rust-mode-tests.el | 86 ++++++++++++++++++++++++++++++
rust-mode.el | 151 ++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 213 insertions(+), 24 deletions(-)
diff --git a/rust-mode-tests.el b/rust-mode-tests.el
index 3ef4cb6..a0e27b0 100644
--- a/rust-mode-tests.el
+++ b/rust-mode-tests.el
@@ -922,3 +922,89 @@ list of substrings of `STR' each followed by its face."
"main" font-lock-function-name-face
"let" font-lock-keyword-face
"'\\''" font-lock-string-face)))
+
+(ert-deftest indent-method-chains-no-align ()
+ (let ((rust-indent-method-chain nil)) (test-indent
+ "
+fn main() {
+ let x = thing.do_it()
+ .aligned()
+ .more_alignment();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-with-align ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ let x = thing.do_it()
+ .aligned()
+ .more_alignment();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-with-align-and-second-stmt ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ let x = thing.do_it()
+ .aligned()
+ .more_alignment();
+ foo.bar();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-field ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ let x = thing.do_it
+ .aligned
+ .more_alignment();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-double-field-on-first-line ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ let x = thing.a.do_it
+ .aligned
+ .more_alignment();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-no-let ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ thing.a.do_it
+ .aligned
+ .more_alignment();
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-comment ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ // thing.do_it()
+ // .aligned()
+}
+"
+ )))
+
+(ert-deftest indent-method-chains-close-block ()
+ (let ((rust-indent-method-chain t)) (test-indent
+ "
+fn main() {
+ foo.bar()
+}
+"
+ )))
diff --git a/rust-mode.el b/rust-mode.el
index 70b49fe..b2e0d5d 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -89,15 +89,6 @@
(backward-word 1))
(current-column))))
-(defun rust-align-to-method-chain ()
- (save-excursion
- (previous-line)
- (end-of-line)
- (backward-word 1)
- (backward-char)
- (when (looking-at "\\..+\(.*\)\n")
- (- (current-column) rust-indent-offset))))
-
(defun rust-rewind-to-beginning-of-current-level-expr ()
(let ((current-level (rust-paren-level)))
(back-to-indentation)
@@ -105,6 +96,54 @@
(backward-up-list)
(back-to-indentation))))
+(defun rust-align-to-method-chain ()
+ (save-excursion
+ ;; for method-chain alignment to apply, we must be looking at
+ ;; another method call or field access or something like
+ ;; that. This avoids rather "eager" jumps in situations like:
+ ;;
+ ;; {
+ ;; something.foo()
+ ;; <indent>
+ ;;
+ ;; Without this check, we would wind up with the cursor under the
+ ;; `.`. In an older version, I had the inverse of the current
+ ;; check, where we checked for situations that should NOT indent,
+ ;; vs checking for the one situation where we SHOULD. It should be
+ ;; clear that this is more robust, but also I find it mildly less
+ ;; annoying to have to press tab again to align to a method chain
+ ;; than to have an over-eager indent in all other cases which must
+ ;; be undone via tab.
+
+ (when (looking-at (concat "\s*\." rust-re-ident))
+ (previous-line)
+ (end-of-line)
+
+ (let
+ ;; skip-dot-identifier is used to position the point at the
+ ;; `.` when looking at something like
+ ;;
+ ;; foo.bar
+ ;; ^ ^
+ ;; | |
+ ;; | position of point
+ ;; returned offset
+ ;;
+ ((skip-dot-identifier
+ (lambda ()
+ (when (looking-back (concat "\." rust-re-ident))
+ (backward-word 1)
+ (backward-char)
+ (- (current-column) rust-indent-offset)))))
+ (cond
+ ;; foo.bar(...)
+ ((looking-back ")")
+ (backward-list 1)
+ (funcall skip-dot-identifier))
+
+ ;; foo.bar
+ (t (funcall skip-dot-identifier)))))))
+
(defun rust-mode-indent-line ()
(interactive)
(let ((indent
@@ -123,10 +162,10 @@
(or
(when rust-indent-method-chain
(rust-align-to-method-chain))
- (save-excursion
- (backward-up-list)
- (rust-rewind-to-beginning-of-current-level-expr)
- (+ (current-column) rust-indent-offset))))))
+ (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 "->")
@@ -137,16 +176,6 @@
;; A closing brace is 1 level unindended
((looking-at "}") (- baseline rust-indent-offset))
-
- ;;Line up method chains by their .'s
- ((when (and rust-indent-method-chain
- (looking-at "\..+\(.*\);?\n"))
- (or
- (let ((method-indent (rust-align-to-method-chain)))
- (when method-indent
- (+ method-indent rust-indent-offset)))
- (+ baseline rust-indent-offset))))
-
;; Doc comments in /** style with leading * indent to line up
the *s
((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."
;; There is no opening brace, so consider the whole buffer to be one
"defun"
(goto-char (point-max))))
+;; Angle-bracket matching. This is kind of a hack designed to deal
+;; with the fact that we can't add angle-brackets to the list of
+;; matching characters unconditionally. Basically we just have some
+;; special-case code such that whenever `>` is typed, we look
+;; backwards to find a matching `<` and highlight it, whether or not
+;; this is *actually* appropriate. This could be annoying so it is
+;; configurable (but on by default because it's awesome).
+
+(defcustom rust-blink-matching-angle-brackets t
+ "Blink matching `<` (if any) when `>` is typed"
+ :type 'boolean
+ :group 'rust-mode)
+
+(defvar rust-point-before-matching-angle-bracket 0)
+
+(defvar rust-matching-angle-bracker-timer nil)
+
+(defun rust-find-matching-angle-bracket ()
+ (save-excursion
+ (let ((angle-brackets 1)
+ (start-point (point))
+ (invalid nil))
+ (while (and
+ ;; didn't find a match
+ (> angle-brackets 0)
+ ;; we have no guarantee of a match, so give up eventually
+ (< (- start-point (point)) blink-matching-paren-distance)
+ ;; didn't hit the top of the buffer
+ (> (point) (point-min))
+ ;; didn't hit something else weird like a `;`
+ (not invalid))
+ (backward-char 1)
+ (cond
+ ((looking-at ">")
+ (setq angle-brackets (+ angle-brackets 1)))
+ ((looking-at "<")
+ (setq angle-brackets (- angle-brackets 1)))
+ ((looking-at "[;{]")
+ (setq invalid t))))
+ (cond
+ ((= angle-brackets 0) (point))
+ (t nil)))))
+
+(defun rust-restore-point-after-angle-bracket ()
+ (goto-char rust-point-before-matching-angle-bracket)
+ (when rust-matching-angle-bracker-timer
+ (cancel-timer rust-matching-angle-bracker-timer))
+ (setq rust-matching-angle-bracker-timer nil)
+ (remove-hook 'pre-command-hook 'rust-restore-point-after-angle-bracket))
+
+(defun rust-match-angle-bracket-hook ()
+ "If the most recently inserted character is a `>`, briefly moves point to
matching `<` (if any)."
+ (interactive)
+ (when (and rust-blink-matching-angle-brackets
+ (looking-back ">"))
+ (let ((matching-angle-bracket-point (save-excursion
+ (backward-char 1)
+ (rust-find-matching-angle-bracket))))
+ (when matching-angle-bracket-point
+ (progn
+ (setq rust-point-before-matching-angle-bracket (point))
+ (goto-char matching-angle-bracket-point)
+ (add-hook 'pre-command-hook 'rust-restore-point-after-angle-bracket)
+ (setq rust-matching-angle-bracker-timer
+ (run-at-time blink-matching-delay nil
'rust-restore-point-after-angle-bracket)))))))
+
+(defun rust-match-angle-bracket ()
+ "The point should be placed on a `>`. Finds the matching `<` and moves point
there."
+ (interactive)
+ (let ((matching-angle-bracket-point (rust-find-matching-angle-bracket)))
+ (if matching-angle-bracket-point
+ (goto-char matching-angle-bracket-point)
+ (message "no matching angle bracket found"))))
+
;; For compatibility with Emacs < 24, derive conditionally
(defalias 'rust-parent-mode
(if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
-
;;;###autoload
(define-derived-mode rust-mode rust-parent-mode "Rust"
"Major mode for Rust code."
@@ -490,6 +592,7 @@ This is written mainly to be used as
`end-of-defun-function' for Rust."
(setq-local end-of-defun-function 'rust-end-of-defun)
(setq-local parse-sexp-lookup-properties t)
(add-hook 'syntax-propertize-extend-region-functions
'rust-syntax-propertize-extend-region)
+ (add-hook 'post-self-insert-hook 'rust-match-angle-bracket-hook)
(setq-local syntax-propertize-function 'rust-syntax-propertize))
(defun rust-syntax-propertize-extend-region (start end)
- [nongnu] elpa/rust-mode 15d31a9 013/486: removed a comma from the keyword list to get, (continued)
- [nongnu] elpa/rust-mode 15d31a9 013/486: removed a comma from the keyword list to get, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode e39142b 033/486: Allow customization of indent offset, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 8dc92b2 073/486: Update emacs mode to support new `#![inner(attribute)]` syntax., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 0800660 068/486: Emacs: stay at the correct position when indenting, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode bc78d17 075/486: rust-mode cleanup., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 5e34201 061/486: Add defun motions for rust-mode., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 0e58eb3 076/486: emacs: Add 'box' to keywords, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 226102c 086/486: emacs: Add shebang to test script, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 186583d 096/486: Mark _ as a word constituent to avoid highlighting parts of identifiers as keywords, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 04e4b49 103/486: Add .travis.yml, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode ec81a95 114/486: Merge pull request #22 from nikomatsakis/align-method-chain,
ELPA Syncer <=
- [nongnu] elpa/rust-mode 351cc91 112/486: Merge pull request #16 from MicahChalmer/add-travis, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode b3f87b9 122/486: Make the test driver script a little more informative., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 19bc0e9 121/486: Merge pull request #30 from MicahChalmer/emacs23-fixup, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode bddc933 124/486: Fix typo in comment, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 97f6445 132/486: Merge pull request #38 from MicahChalmer/fix-issue-36, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 42730b1 144/486: Merge pull request #49 from huonw/playpen, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 249e3ce 134/486: Merge pull request #40 from MicahChalmer/fix-comment-typos, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 31ceb60 135/486: Indent inside strings after ending backslash, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 22c8cfa 138/486: Merge pull request #43 from MicahChalmer/indent-backslash-strings, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode ce976b9 145/486: Fix "-> Type" on a single line indentation, ELPA Syncer, 2021/08/07