[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/rust-mode 139a658 482/486: Create rust-rustfmt.el from exi
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/rust-mode 139a658 482/486: Create rust-rustfmt.el from existing code |
Date: |
Sat, 7 Aug 2021 09:26:19 -0400 (EDT) |
branch: elpa/rust-mode
commit 139a6580ed85d4ec1b29b23abeb474d33e78ea39
Author: Jonas Bernoulli <jonas@bernoul.li>
Commit: brotzeit <brotzeitmacher@gmail.com>
Create rust-rustfmt.el from existing code
---
Makefile | 1 +
rust-mode.el | 356 ------------------------------------------------------
rust-rustfmt.el | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 369 insertions(+), 356 deletions(-)
diff --git a/Makefile b/Makefile
index 396b722..7ef02af 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ EMACS_ARGS ?=
ELS = rust-mode.el
ELS += rust-compile.el
+ELS += rust-rustfmt.el
ELCS = $(ELS:.el=.elc)
DEPS =
diff --git a/rust-mode.el b/rust-mode.el
index f35a947..37b5cd3 100644
--- a/rust-mode.el
+++ b/rust-mode.el
@@ -70,34 +70,6 @@ When nil, `where' will be aligned with `fn' or `trait'."
:safe #'booleanp
:group 'rust-mode)
-(defcustom rust-format-on-save nil
- "Format future rust buffers before saving using rustfmt."
- :type 'boolean
- :safe #'booleanp
- :group 'rust-mode)
-
-(defcustom rust-format-show-buffer t
- "Show *rustfmt* buffer if formatting detected problems."
- :type 'boolean
- :safe #'booleanp
- :group 'rust-mode)
-
-(defcustom rust-format-goto-problem t
- "Jump to location of first detected problem when formatting buffer."
- :type 'boolean
- :safe #'booleanp
- :group 'rust-mode)
-
-(defcustom rust-rustfmt-bin "rustfmt"
- "Path to rustfmt executable."
- :type 'string
- :group 'rust-mode)
-
-(defcustom rust-rustfmt-switches '("--edition" "2018")
- "Arguments to pass when invoking the `rustfmt' executable."
- :type '(repeat string)
- :group 'rust-mode)
-
(defcustom rust-cargo-bin "cargo"
"Path to cargo executable."
:type 'string
@@ -1608,314 +1580,6 @@ 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))))
-;;; Formatting using rustfmt
-
-(defconst rust-rustfmt-buffername "*rustfmt*")
-
-(defun rust--format-call (buf)
- "Format BUF using rustfmt."
- (with-current-buffer (get-buffer-create rust-rustfmt-buffername)
- (view-mode +1)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (insert-buffer-substring buf)
- (let* ((tmpf (make-temp-file "rustfmt"))
- (ret (apply 'call-process-region
- (point-min)
- (point-max)
- rust-rustfmt-bin
- t
- `(t ,tmpf)
- nil
- rust-rustfmt-switches)))
- (unwind-protect
- (cond
- ((zerop ret)
- (if (not (string= (buffer-string)
- (with-current-buffer buf (buffer-string))))
- ;; replace-buffer-contents was in emacs 26.1, but it
- ;; was broken for non-ASCII strings, so we need 26.2.
- (if (and (fboundp 'replace-buffer-contents)
- (version<= "26.2" emacs-version))
- (with-current-buffer buf
- (replace-buffer-contents rust-rustfmt-buffername))
- (copy-to-buffer buf (point-min) (point-max))))
- (kill-buffer))
- ((= ret 3)
- (if (not (string= (buffer-string)
- (with-current-buffer buf (buffer-string))))
- (copy-to-buffer buf (point-min) (point-max)))
- (erase-buffer)
- (insert-file-contents tmpf)
- (rust--format-fix-rustfmt-buffer (buffer-name buf))
- (error "Rustfmt could not format some lines, see *rustfmt*
buffer for details"))
- (t
- (erase-buffer)
- (insert-file-contents tmpf)
- (rust--format-fix-rustfmt-buffer (buffer-name buf))
- (error "Rustfmt failed, see *rustfmt* buffer for details"))))
- (delete-file tmpf)))))
-
-;; Since we run rustfmt through stdin we get <stdin> markers in the
-;; output. This replaces them with the buffer name instead.
-(defun rust--format-fix-rustfmt-buffer (buffer-name)
- (with-current-buffer (get-buffer rust-rustfmt-buffername)
- (let ((inhibit-read-only t))
- (goto-char (point-min))
- (while (re-search-forward "--> <stdin>:" nil t)
- (replace-match (format "--> %s:" buffer-name)))
- (while (re-search-forward "--> stdin:" nil t)
- (replace-match (format "--> %s:" buffer-name))))))
-
-;; If rust-mode has been configured to navigate to source of the error
-;; or display it, do so -- and return true. Otherwise return nil to
-;; indicate nothing was done.
-(defun rust--format-error-handler ()
- (let ((ok nil))
- (when rust-format-show-buffer
- (display-buffer (get-buffer rust-rustfmt-buffername))
- (setq ok t))
- (when rust-format-goto-problem
- (rust-goto-format-problem)
- (setq ok t))
- ok))
-
-(defun rust-goto-format-problem ()
- "Jumps to problem reported by rustfmt, if any.
-
-In case of multiple problems cycles through them. Displays the
-rustfmt complain in the echo area."
- (interactive)
- ;; This uses position in *rustfmt* buffer to know which is the next
- ;; error to jump to, and source: line in the buffer to figure which
- ;; buffer it is from.
- (let ((rustfmt (get-buffer rust-rustfmt-buffername)))
- (if (not rustfmt)
- (message "No *rustfmt*, no problems.")
- (let ((target-buffer (with-current-buffer rustfmt
- (save-excursion
- (goto-char (point-min))
- (when (re-search-forward "--> \\([^:]+\\):" nil
t)
- (match-string 1)))))
- (target-point (with-current-buffer rustfmt
- ;; No save-excursion, this is how we cycle through!
- (let ((regex "-->
[^:]+:\\([0-9]+\\):\\([0-9]+\\)"))
- (when (or (re-search-forward regex nil t)
- (progn (goto-char (point-min))
- (re-search-forward regex nil
t)))
- (cons (string-to-number (match-string 1))
- (string-to-number (match-string 2)))))))
- (target-problem (with-current-buffer rustfmt
- (save-excursion
- (when (re-search-backward "^error:.+\n" nil t)
- (forward-char (length "error: "))
- (let ((p0 (point)))
- (if (re-search-forward "\nerror:.+\n" nil
t)
- (buffer-substring p0 (point))
- (buffer-substring p0 (point-max)))))))))
- (when (and target-buffer (get-buffer target-buffer) target-point)
- (switch-to-buffer target-buffer)
- (goto-char (point-min))
- (forward-line (1- (car target-point)))
- (forward-char (1- (cdr target-point))))
- (message target-problem)))))
-
-(defconst rust--format-word "\
-\\b\\(else\\|enum\\|fn\\|for\\|if\\|let\\|loop\\|\
-match\\|struct\\|union\\|unsafe\\|while\\)\\b")
-(defconst rust--format-line "\\([\n]\\)")
-
-;; Counts number of matches of regex beginning up to max-beginning,
-;; leaving the point at the beginning of the last match.
-(defun rust--format-count (regex max-beginning)
- (let ((count 0)
- save-point
- beginning)
- (while (and (< (point) max-beginning)
- (re-search-forward regex max-beginning t))
- (setq count (1+ count))
- (setq beginning (match-beginning 1)))
- ;; try one more in case max-beginning lies in the middle of a match
- (setq save-point (point))
- (when (re-search-forward regex nil t)
- (let ((try-beginning (match-beginning 1)))
- (if (> try-beginning max-beginning)
- (goto-char save-point)
- (setq count (1+ count))
- (setq beginning try-beginning))))
- (when beginning (goto-char beginning))
- count))
-
-;; Gets list describing pos or (point).
-;; The list contains:
-;; 1. the number of matches of rust--format-word,
-;; 2. the number of matches of rust--format-line after that,
-;; 3. the number of columns after that.
-(defun rust--format-get-loc (buffer &optional pos)
- (with-current-buffer buffer
- (save-excursion
- (let ((pos (or pos (point)))
- words lines columns)
- (goto-char (point-min))
- (setq words (rust--format-count rust--format-word pos))
- (setq lines (rust--format-count rust--format-line pos))
- (if (> lines 0)
- (if (= (point) pos)
- (setq columns -1)
- (forward-char 1)
- (goto-char pos)
- (setq columns (current-column)))
- (let ((initial-column (current-column)))
- (goto-char pos)
- (setq columns (- (current-column) initial-column))))
- (list words lines columns)))))
-
-;; Moves the point forward by count matches of regex up to max-pos,
-;; and returns new max-pos making sure final position does not include another
match.
-(defun rust--format-forward (regex count max-pos)
- (when (< (point) max-pos)
- (let ((beginning (point)))
- (while (> count 0)
- (setq count (1- count))
- (re-search-forward regex nil t)
- (setq beginning (match-beginning 1)))
- (when (re-search-forward regex nil t)
- (setq max-pos (min max-pos (match-beginning 1))))
- (goto-char beginning)))
- max-pos)
-
-;; Gets the position from a location list obtained using rust--format-get-loc.
-(defun rust--format-get-pos (buffer loc)
- (with-current-buffer buffer
- (save-excursion
- (goto-char (point-min))
- (let ((max-pos (point-max))
- (words (pop loc))
- (lines (pop loc))
- (columns (pop loc)))
- (setq max-pos (rust--format-forward rust--format-word words max-pos))
- (setq max-pos (rust--format-forward rust--format-line lines max-pos))
- (when (> lines 0) (forward-char))
- (let ((initial-column (current-column))
- (save-point (point)))
- (move-end-of-line nil)
- (when (> (current-column) (+ initial-column columns))
- (goto-char save-point)
- (forward-char columns)))
- (min (point) max-pos)))))
-
-(defun rust-format-diff-buffer ()
- "Show diff to current buffer from rustfmt.
-
-Return the created process."
- (interactive)
- (unless (executable-find rust-rustfmt-bin)
- (error "Could not locate executable \%s\"" rust-rustfmt-bin))
- (let* ((buffer
- (with-current-buffer
- (get-buffer-create "*rustfmt-diff*")
- (let ((inhibit-read-only t))
- (erase-buffer))
- (current-buffer)))
- (proc
- (apply 'start-process
- "rustfmt-diff"
- buffer
- rust-rustfmt-bin
- "--check"
- (cons (buffer-file-name)
- rust-rustfmt-switches))))
- (set-process-sentinel proc 'rust-format-diff-buffer-sentinel)
- proc))
-
-(defun rust-format-diff-buffer-sentinel (process _e)
- (when (eq 'exit (process-status process))
- (if (> (process-exit-status process) 0)
- (with-current-buffer "*rustfmt-diff*"
- (let ((inhibit-read-only t))
- (diff-mode))
- (pop-to-buffer (current-buffer)))
- (message "rustfmt check passed."))))
-
-(defun rust--format-buffer-using-replace-buffer-contents ()
- (condition-case err
- (progn
- (rust--format-call (current-buffer))
- (message "Formatted buffer with rustfmt."))
- (error
- (or (rust--format-error-handler)
- (signal (car err) (cdr err))))))
-
-(defun rust--format-buffer-saving-position-manually ()
- (let* ((current (current-buffer))
- (base (or (buffer-base-buffer current) current))
- buffer-loc
- window-loc)
- (dolist (buffer (buffer-list))
- (when (or (eq buffer base)
- (eq (buffer-base-buffer buffer) base))
- (push (list buffer
- (rust--format-get-loc buffer nil))
- buffer-loc)))
- (dolist (frame (frame-list))
- (dolist (window (window-list frame))
- (let ((buffer (window-buffer window)))
- (when (or (eq buffer base)
- (eq (buffer-base-buffer buffer) base))
- (let ((start (window-start window))
- (point (window-point window)))
- (push (list window
- (rust--format-get-loc buffer start)
- (rust--format-get-loc buffer point))
- window-loc))))))
- (condition-case err
- (unwind-protect
- ;; save and restore window start position
- ;; after reformatting
- ;; to avoid the disturbing scrolling
- (let ((w-start (window-start)))
- (rust--format-call (current-buffer))
- (set-window-start (selected-window) w-start)
- (message "Formatted buffer with rustfmt."))
- (dolist (loc buffer-loc)
- (let* ((buffer (pop loc))
- (pos (rust--format-get-pos buffer (pop loc))))
- (with-current-buffer buffer
- (goto-char pos))))
- (dolist (loc window-loc)
- (let* ((window (pop loc))
- (buffer (window-buffer window))
- (start (rust--format-get-pos buffer (pop loc)))
- (pos (rust--format-get-pos buffer (pop loc))))
- (unless (eq buffer current)
- (set-window-start window start))
- (set-window-point window pos))))
- (error
- (or (rust--format-error-handler)
- (signal (car err) (cdr err)))))))
-
-(defun rust-format-buffer ()
- "Format the current buffer using rustfmt."
- (interactive)
- (unless (executable-find rust-rustfmt-bin)
- (error "Could not locate executable \"%s\"" rust-rustfmt-bin))
- ;; If emacs version >= 26.2, we can use replace-buffer-contents to
- ;; preserve location and markers in buffer, otherwise we can try to
- ;; save locations as best we can, though we still lose markers.
- (if (version<= "26.2" emacs-version)
- (rust--format-buffer-using-replace-buffer-contents)
- (rust--format-buffer-saving-position-manually)))
-
-(defun rust-enable-format-on-save ()
- "Enable formatting using rustfmt when saving buffer."
- (interactive)
- (setq-local rust-format-on-save t))
-
-(defun rust-disable-format-on-save ()
- "Disable formatting using rustfmt when saving buffer."
- (interactive)
- (setq-local rust-format-on-save nil))
-
(defun rust--compile (format-string &rest args)
(when (null rust-buffer-project)
(rust-update-buffer-project))
@@ -1955,26 +1619,6 @@ Return the created process."
(interactive)
(rust--compile "%s test" rust-cargo-bin))
-;;; Hooks
-
-(defun rust-before-save-hook ()
- (when rust-format-on-save
- (condition-case e
- (rust-format-buffer)
- (error (format "rust-before-save-hook: %S %S"
- (car e)
- (cdr e))))))
-
-(defun rust-after-save-hook ()
- (when rust-format-on-save
- (if (not (executable-find rust-rustfmt-bin))
- (error "Could not locate executable \"%s\"" rust-rustfmt-bin)
- (when (get-buffer rust-rustfmt-buffername)
- ;; KLDUGE: re-run the error handlers -- otherwise message area
- ;; would show "Wrote ..." instead of the error description.
- (or (rust--format-error-handler)
- (message "rustfmt detected problems, see *rustfmt* for more."))))))
-
;;; Secondary Commands
(defun rust-playpen-region (begin end)
diff --git a/rust-rustfmt.el b/rust-rustfmt.el
new file mode 100644
index 0000000..d3b7509
--- /dev/null
+++ b/rust-rustfmt.el
@@ -0,0 +1,368 @@
+;;; rust-rustfmt.el --- Support for rustfmt -*- lexical-binding:t -*-
+;;; Commentary:
+
+;; This library implements support for "rustfmt", a tool for
+;; formatting Rust code according to style guidelines.
+
+;;; Code:
+;;; Options
+
+(defcustom rust-format-on-save nil
+ "Format future rust buffers before saving using rustfmt."
+ :type 'boolean
+ :safe #'booleanp
+ :group 'rust-mode)
+
+(defcustom rust-format-show-buffer t
+ "Show *rustfmt* buffer if formatting detected problems."
+ :type 'boolean
+ :safe #'booleanp
+ :group 'rust-mode)
+
+(defcustom rust-format-goto-problem t
+ "Jump to location of first detected problem when formatting buffer."
+ :type 'boolean
+ :safe #'booleanp
+ :group 'rust-mode)
+
+(defcustom rust-rustfmt-bin "rustfmt"
+ "Path to rustfmt executable."
+ :type 'string
+ :group 'rust-mode)
+
+(defcustom rust-rustfmt-switches '("--edition" "2018")
+ "Arguments to pass when invoking the `rustfmt' executable."
+ :type '(repeat string)
+ :group 'rust-mode)
+
+;;; _
+
+(defconst rust-rustfmt-buffername "*rustfmt*")
+
+(defun rust--format-call (buf)
+ "Format BUF using rustfmt."
+ (with-current-buffer (get-buffer-create rust-rustfmt-buffername)
+ (view-mode +1)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (insert-buffer-substring buf)
+ (let* ((tmpf (make-temp-file "rustfmt"))
+ (ret (apply 'call-process-region
+ (point-min)
+ (point-max)
+ rust-rustfmt-bin
+ t
+ `(t ,tmpf)
+ nil
+ rust-rustfmt-switches)))
+ (unwind-protect
+ (cond
+ ((zerop ret)
+ (if (not (string= (buffer-string)
+ (with-current-buffer buf (buffer-string))))
+ ;; replace-buffer-contents was in emacs 26.1, but it
+ ;; was broken for non-ASCII strings, so we need 26.2.
+ (if (and (fboundp 'replace-buffer-contents)
+ (version<= "26.2" emacs-version))
+ (with-current-buffer buf
+ (replace-buffer-contents rust-rustfmt-buffername))
+ (copy-to-buffer buf (point-min) (point-max))))
+ (kill-buffer))
+ ((= ret 3)
+ (if (not (string= (buffer-string)
+ (with-current-buffer buf (buffer-string))))
+ (copy-to-buffer buf (point-min) (point-max)))
+ (erase-buffer)
+ (insert-file-contents tmpf)
+ (rust--format-fix-rustfmt-buffer (buffer-name buf))
+ (error "Rustfmt could not format some lines, see *rustfmt*
buffer for details"))
+ (t
+ (erase-buffer)
+ (insert-file-contents tmpf)
+ (rust--format-fix-rustfmt-buffer (buffer-name buf))
+ (error "Rustfmt failed, see *rustfmt* buffer for details"))))
+ (delete-file tmpf)))))
+
+;; Since we run rustfmt through stdin we get <stdin> markers in the
+;; output. This replaces them with the buffer name instead.
+(defun rust--format-fix-rustfmt-buffer (buffer-name)
+ (with-current-buffer (get-buffer rust-rustfmt-buffername)
+ (let ((inhibit-read-only t))
+ (goto-char (point-min))
+ (while (re-search-forward "--> <stdin>:" nil t)
+ (replace-match (format "--> %s:" buffer-name)))
+ (while (re-search-forward "--> stdin:" nil t)
+ (replace-match (format "--> %s:" buffer-name))))))
+
+;; If rust-mode has been configured to navigate to source of the error
+;; or display it, do so -- and return true. Otherwise return nil to
+;; indicate nothing was done.
+(defun rust--format-error-handler ()
+ (let ((ok nil))
+ (when rust-format-show-buffer
+ (display-buffer (get-buffer rust-rustfmt-buffername))
+ (setq ok t))
+ (when rust-format-goto-problem
+ (rust-goto-format-problem)
+ (setq ok t))
+ ok))
+
+(defun rust-goto-format-problem ()
+ "Jumps to problem reported by rustfmt, if any.
+
+In case of multiple problems cycles through them. Displays the
+rustfmt complain in the echo area."
+ (interactive)
+ ;; This uses position in *rustfmt* buffer to know which is the next
+ ;; error to jump to, and source: line in the buffer to figure which
+ ;; buffer it is from.
+ (let ((rustfmt (get-buffer rust-rustfmt-buffername)))
+ (if (not rustfmt)
+ (message "No *rustfmt*, no problems.")
+ (let ((target-buffer (with-current-buffer rustfmt
+ (save-excursion
+ (goto-char (point-min))
+ (when (re-search-forward "--> \\([^:]+\\):" nil
t)
+ (match-string 1)))))
+ (target-point (with-current-buffer rustfmt
+ ;; No save-excursion, this is how we cycle through!
+ (let ((regex "-->
[^:]+:\\([0-9]+\\):\\([0-9]+\\)"))
+ (when (or (re-search-forward regex nil t)
+ (progn (goto-char (point-min))
+ (re-search-forward regex nil
t)))
+ (cons (string-to-number (match-string 1))
+ (string-to-number (match-string 2)))))))
+ (target-problem (with-current-buffer rustfmt
+ (save-excursion
+ (when (re-search-backward "^error:.+\n" nil t)
+ (forward-char (length "error: "))
+ (let ((p0 (point)))
+ (if (re-search-forward "\nerror:.+\n" nil
t)
+ (buffer-substring p0 (point))
+ (buffer-substring p0 (point-max)))))))))
+ (when (and target-buffer (get-buffer target-buffer) target-point)
+ (switch-to-buffer target-buffer)
+ (goto-char (point-min))
+ (forward-line (1- (car target-point)))
+ (forward-char (1- (cdr target-point))))
+ (message target-problem)))))
+
+(defconst rust--format-word "\
+\\b\\(else\\|enum\\|fn\\|for\\|if\\|let\\|loop\\|\
+match\\|struct\\|union\\|unsafe\\|while\\)\\b")
+(defconst rust--format-line "\\([\n]\\)")
+
+;; Counts number of matches of regex beginning up to max-beginning,
+;; leaving the point at the beginning of the last match.
+(defun rust--format-count (regex max-beginning)
+ (let ((count 0)
+ save-point
+ beginning)
+ (while (and (< (point) max-beginning)
+ (re-search-forward regex max-beginning t))
+ (setq count (1+ count))
+ (setq beginning (match-beginning 1)))
+ ;; try one more in case max-beginning lies in the middle of a match
+ (setq save-point (point))
+ (when (re-search-forward regex nil t)
+ (let ((try-beginning (match-beginning 1)))
+ (if (> try-beginning max-beginning)
+ (goto-char save-point)
+ (setq count (1+ count))
+ (setq beginning try-beginning))))
+ (when beginning (goto-char beginning))
+ count))
+
+;; Gets list describing pos or (point).
+;; The list contains:
+;; 1. the number of matches of rust--format-word,
+;; 2. the number of matches of rust--format-line after that,
+;; 3. the number of columns after that.
+(defun rust--format-get-loc (buffer &optional pos)
+ (with-current-buffer buffer
+ (save-excursion
+ (let ((pos (or pos (point)))
+ words lines columns)
+ (goto-char (point-min))
+ (setq words (rust--format-count rust--format-word pos))
+ (setq lines (rust--format-count rust--format-line pos))
+ (if (> lines 0)
+ (if (= (point) pos)
+ (setq columns -1)
+ (forward-char 1)
+ (goto-char pos)
+ (setq columns (current-column)))
+ (let ((initial-column (current-column)))
+ (goto-char pos)
+ (setq columns (- (current-column) initial-column))))
+ (list words lines columns)))))
+
+;; Moves the point forward by count matches of regex up to max-pos,
+;; and returns new max-pos making sure final position does not include another
match.
+(defun rust--format-forward (regex count max-pos)
+ (when (< (point) max-pos)
+ (let ((beginning (point)))
+ (while (> count 0)
+ (setq count (1- count))
+ (re-search-forward regex nil t)
+ (setq beginning (match-beginning 1)))
+ (when (re-search-forward regex nil t)
+ (setq max-pos (min max-pos (match-beginning 1))))
+ (goto-char beginning)))
+ max-pos)
+
+;; Gets the position from a location list obtained using rust--format-get-loc.
+(defun rust--format-get-pos (buffer loc)
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-min))
+ (let ((max-pos (point-max))
+ (words (pop loc))
+ (lines (pop loc))
+ (columns (pop loc)))
+ (setq max-pos (rust--format-forward rust--format-word words max-pos))
+ (setq max-pos (rust--format-forward rust--format-line lines max-pos))
+ (when (> lines 0) (forward-char))
+ (let ((initial-column (current-column))
+ (save-point (point)))
+ (move-end-of-line nil)
+ (when (> (current-column) (+ initial-column columns))
+ (goto-char save-point)
+ (forward-char columns)))
+ (min (point) max-pos)))))
+
+(defun rust-format-diff-buffer ()
+ "Show diff to current buffer from rustfmt.
+
+Return the created process."
+ (interactive)
+ (unless (executable-find rust-rustfmt-bin)
+ (error "Could not locate executable \%s\"" rust-rustfmt-bin))
+ (let* ((buffer
+ (with-current-buffer
+ (get-buffer-create "*rustfmt-diff*")
+ (let ((inhibit-read-only t))
+ (erase-buffer))
+ (current-buffer)))
+ (proc
+ (apply 'start-process
+ "rustfmt-diff"
+ buffer
+ rust-rustfmt-bin
+ "--check"
+ (cons (buffer-file-name)
+ rust-rustfmt-switches))))
+ (set-process-sentinel proc 'rust-format-diff-buffer-sentinel)
+ proc))
+
+(defun rust-format-diff-buffer-sentinel (process _e)
+ (when (eq 'exit (process-status process))
+ (if (> (process-exit-status process) 0)
+ (with-current-buffer "*rustfmt-diff*"
+ (let ((inhibit-read-only t))
+ (diff-mode))
+ (pop-to-buffer (current-buffer)))
+ (message "rustfmt check passed."))))
+
+(defun rust--format-buffer-using-replace-buffer-contents ()
+ (condition-case err
+ (progn
+ (rust--format-call (current-buffer))
+ (message "Formatted buffer with rustfmt."))
+ (error
+ (or (rust--format-error-handler)
+ (signal (car err) (cdr err))))))
+
+(defun rust--format-buffer-saving-position-manually ()
+ (let* ((current (current-buffer))
+ (base (or (buffer-base-buffer current) current))
+ buffer-loc
+ window-loc)
+ (dolist (buffer (buffer-list))
+ (when (or (eq buffer base)
+ (eq (buffer-base-buffer buffer) base))
+ (push (list buffer
+ (rust--format-get-loc buffer nil))
+ buffer-loc)))
+ (dolist (frame (frame-list))
+ (dolist (window (window-list frame))
+ (let ((buffer (window-buffer window)))
+ (when (or (eq buffer base)
+ (eq (buffer-base-buffer buffer) base))
+ (let ((start (window-start window))
+ (point (window-point window)))
+ (push (list window
+ (rust--format-get-loc buffer start)
+ (rust--format-get-loc buffer point))
+ window-loc))))))
+ (condition-case err
+ (unwind-protect
+ ;; save and restore window start position
+ ;; after reformatting
+ ;; to avoid the disturbing scrolling
+ (let ((w-start (window-start)))
+ (rust--format-call (current-buffer))
+ (set-window-start (selected-window) w-start)
+ (message "Formatted buffer with rustfmt."))
+ (dolist (loc buffer-loc)
+ (let* ((buffer (pop loc))
+ (pos (rust--format-get-pos buffer (pop loc))))
+ (with-current-buffer buffer
+ (goto-char pos))))
+ (dolist (loc window-loc)
+ (let* ((window (pop loc))
+ (buffer (window-buffer window))
+ (start (rust--format-get-pos buffer (pop loc)))
+ (pos (rust--format-get-pos buffer (pop loc))))
+ (unless (eq buffer current)
+ (set-window-start window start))
+ (set-window-point window pos))))
+ (error
+ (or (rust--format-error-handler)
+ (signal (car err) (cdr err)))))))
+
+(defun rust-format-buffer ()
+ "Format the current buffer using rustfmt."
+ (interactive)
+ (unless (executable-find rust-rustfmt-bin)
+ (error "Could not locate executable \"%s\"" rust-rustfmt-bin))
+ ;; If emacs version >= 26.2, we can use replace-buffer-contents to
+ ;; preserve location and markers in buffer, otherwise we can try to
+ ;; save locations as best we can, though we still lose markers.
+ (if (version<= "26.2" emacs-version)
+ (rust--format-buffer-using-replace-buffer-contents)
+ (rust--format-buffer-saving-position-manually)))
+
+(defun rust-enable-format-on-save ()
+ "Enable formatting using rustfmt when saving buffer."
+ (interactive)
+ (setq-local rust-format-on-save t))
+
+(defun rust-disable-format-on-save ()
+ "Disable formatting using rustfmt when saving buffer."
+ (interactive)
+ (setq-local rust-format-on-save nil))
+
+;;; Hooks
+
+(defun rust-before-save-hook ()
+ (when rust-format-on-save
+ (condition-case e
+ (rust-format-buffer)
+ (error (format "rust-before-save-hook: %S %S"
+ (car e)
+ (cdr e))))))
+
+(defun rust-after-save-hook ()
+ (when rust-format-on-save
+ (if (not (executable-find rust-rustfmt-bin))
+ (error "Could not locate executable \"%s\"" rust-rustfmt-bin)
+ (when (get-buffer rust-rustfmt-buffername)
+ ;; KLDUGE: re-run the error handlers -- otherwise message area
+ ;; would show "Wrote ..." instead of the error description.
+ (or (rust--format-error-handler)
+ (message "rustfmt detected problems, see *rustfmt* for more."))))))
+
+;;; _
+(provide 'rust-rustfmt)
+;;; rust-rustfmt.el ends here
- [nongnu] elpa/rust-mode 1603a25 455/486: Change 'rust-build' to 'rust-compile' in README.md, (continued)
- [nongnu] elpa/rust-mode 1603a25 455/486: Change 'rust-build' to 'rust-compile' in README.md, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 6e4835c 456/486: Update README.md, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 5dc219f 465/486: rearrange III: Mode, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode beda16d 466/486: rearrange IV: Misc, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode f9e3618 468/486: Divide library into sections, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode e9e9e32 472/486: Add release build/run functions, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode e006788 474/486: Add .dir-locals.el, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 7fdb9c2 450/486: Use <kbd> to indicate keyboard input in README (#375), ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode d211e68 453/486: Fix various byte compilation warnings in rust-mode-tests.el., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode bded667 457/486: Add missing ‘require’ form., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 139a658 482/486: Create rust-rustfmt.el from existing code,
ELPA Syncer <=
- [nongnu] elpa/rust-mode 494d59f 486/486: Make most additional libraries optional, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 9f3d8cf 432/486: rust format buffer now saves position across multiple frames (#348), ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 6f1abc3 438/486: Expand README to include more information about features (#358), ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode e04e485 441/486: rustc-compilation-regexps: handle `note` case as compilation-info., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 39f32cc 447/486: In emacs >= 26.2, use replace-buffer-contents after formatting, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode eca55c0 451/486: Check for -> and => early in rust-ordinary-lt-gt-p, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode ca7d99c 469/486: Set default directory when compiling., ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode c5c7ed3 471/486: Update README.md, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 4e394ac 475/486: Add Makefile, ELPA Syncer, 2021/08/07
- [nongnu] elpa/rust-mode 09b4320 476/486: test: Suppress some noisy messages, ELPA Syncer, 2021/08/07