diff options
| author | Trevor Spiteri <tspiteri@ieee.org> | 2016-12-25 05:43:25 +0100 |
|---|---|---|
| committer | Trevor Spiteri <tspiteri@ieee.org> | 2016-12-25 05:43:25 +0100 |
| commit | 664c7b037c2fe2e2b2d1c0629835715194b844bb (patch) | |
| tree | 6efb0f832a16f11cf91d5ba43d2ff28a4583caf4 /rust-mode.el | |
| parent | 936a1878b7b5c60ee5f3d501df262028821fa2f3 (diff) | |
| download | rust-mode-664c7b037c2fe2e2b2d1c0629835715194b844bb.tar.gz | |
improve position recovery in rust-format-buffer
Diffstat (limited to 'rust-mode.el')
| -rw-r--r-- | rust-mode.el | 145 |
1 files changed, 103 insertions, 42 deletions
diff --git a/rust-mode.el b/rust-mode.el index 55148f6..cced21c 100644 --- a/rust-mode.el +++ b/rust-mode.el @@ -1281,6 +1281,88 @@ This is written mainly to be used as `end-of-defun-function' for Rust." (kill-buffer)) (error "Rustfmt failed, see *rustfmt* buffer for details")))) +(defconst rust--format-word "\\b\\(else\\|enum\\|fn\\|for\\|if\\|let\\|loop\\|match\\|struct\\|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-buffer () "Format the current buffer using rustfmt." (interactive) @@ -1289,58 +1371,37 @@ This is written mainly to be used as `end-of-defun-function' for Rust." (let* ((current (current-buffer)) (base (or (buffer-base-buffer current) current)) - buffer-pos - window-pos) + buffer-loc + window-loc) (dolist (buffer (buffer-list)) (when (or (eq buffer base) (eq (buffer-base-buffer buffer) base)) - (with-current-buffer buffer - (push (list buffer - (line-number-at-pos) - (current-column)) - buffer-pos)))) + (push (list buffer + (rust--format-get-loc buffer nil)) + buffer-loc))) (dolist (window (window-list)) (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))) - (with-current-buffer buffer - (push (list window - (line-number-at-pos start) - (save-excursion (goto-char start) (current-column)) - (line-number-at-pos point) - (save-excursion (goto-char point) (current-column))) - window-pos)))))) - (rust--format-call current) - (dolist (pos buffer-pos) - (let ((buffer (pop pos)) - (line (pop pos)) - (column (pop pos))) + (push (list window + (rust--format-get-loc buffer start) + (rust--format-get-loc buffer point)) + window-loc))))) + (rust--format-call (current-buffer)) + (dolist (loc buffer-loc) + (let* ((buffer (pop loc)) + (pos (rust--format-get-pos buffer (pop loc)))) (with-current-buffer buffer - ;; Move to the same line and column as before. This is best - ;; effort: if rustfmt inserted lines before point, we end up in - ;; the wrong place. See issue #162. - (goto-char (point-min)) - (forward-line (1- line)) - (forward-char column)))) - (dolist (pos window-pos) - (let ((window (pop pos)) - (start-line (pop pos)) - (start-column (pop pos)) - (point-line (pop pos)) - (point-column (pop pos))) - (with-current-buffer (window-buffer window) - (let ((start (save-excursion (goto-char (point-min)) - (forward-line (1- start-line)) - (forward-char start-column) - (point))) - (point (save-excursion (goto-char (point-min)) - (forward-line (1- point-line)) - (forward-char point-column) - (point)))) - (set-window-start window start) - (set-window-point window point)))))) + (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)))) + (set-window-start window start) + (set-window-point window pos)))) ;; Issue #127: Running this on a buffer acts like a revert, and could cause ;; the fontification to get out of sync. Call the same hook to ensure it is |
