Skip to content

Commit 664c7b0

Browse files
committed
improve position recovery in rust-format-buffer
1 parent 936a187 commit 664c7b0

File tree

1 file changed

+103
-42
lines changed

1 file changed

+103
-42
lines changed

rust-mode.el

Lines changed: 103 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,88 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
12811281
(kill-buffer))
12821282
(error "Rustfmt failed, see *rustfmt* buffer for details"))))
12831283

1284+
(defconst rust--format-word "\\b\\(else\\|enum\\|fn\\|for\\|if\\|let\\|loop\\|match\\|struct\\|unsafe\\|while\\)\\b")
1285+
(defconst rust--format-line "\\([\n]\\)")
1286+
1287+
;; Counts number of matches of regex beginning up to max-beginning,
1288+
;; leaving the point at the beginning of the last match.
1289+
(defun rust--format-count (regex max-beginning)
1290+
(let ((count 0)
1291+
save-point
1292+
beginning)
1293+
(while (and (< (point) max-beginning)
1294+
(re-search-forward regex max-beginning t))
1295+
(setq count (1+ count))
1296+
(setq beginning (match-beginning 1)))
1297+
;; try one more in case max-beginning lies in the middle of a match
1298+
(setq save-point (point))
1299+
(when (re-search-forward regex nil t)
1300+
(let ((try-beginning (match-beginning 1)))
1301+
(if (> try-beginning max-beginning)
1302+
(goto-char save-point)
1303+
(setq count (1+ count))
1304+
(setq beginning try-beginning))))
1305+
(when beginning (goto-char beginning))
1306+
count))
1307+
1308+
;; Gets list describing pos or (point).
1309+
;; The list contains:
1310+
;; 1. the number of matches of rust--format-word,
1311+
;; 2. the number of matches of rust--format-line after that,
1312+
;; 3. the number of columns after that.
1313+
(defun rust--format-get-loc (buffer &optional pos)
1314+
(with-current-buffer buffer
1315+
(save-excursion
1316+
(let ((pos (or pos (point)))
1317+
words lines columns)
1318+
(goto-char (point-min))
1319+
(setq words (rust--format-count rust--format-word pos))
1320+
(setq lines (rust--format-count rust--format-line pos))
1321+
(if (> lines 0)
1322+
(if (= (point) pos)
1323+
(setq columns -1)
1324+
(forward-char 1)
1325+
(goto-char pos)
1326+
(setq columns (current-column)))
1327+
(let ((initial-column (current-column)))
1328+
(goto-char pos)
1329+
(setq columns (- (current-column) initial-column))))
1330+
(list words lines columns)))))
1331+
1332+
;; Moves the point forward by count matches of regex up to max-pos,
1333+
;; and returns new max-pos making sure final position does not include another match.
1334+
(defun rust--format-forward (regex count max-pos)
1335+
(when (< (point) max-pos)
1336+
(let ((beginning (point)))
1337+
(while (> count 0)
1338+
(setq count (1- count))
1339+
(re-search-forward regex nil t)
1340+
(setq beginning (match-beginning 1)))
1341+
(when (re-search-forward regex nil t)
1342+
(setq max-pos (min max-pos (match-beginning 1))))
1343+
(goto-char beginning)))
1344+
max-pos)
1345+
1346+
;; Gets the position from a location list obtained using rust--format-get-loc.
1347+
(defun rust--format-get-pos (buffer loc)
1348+
(with-current-buffer buffer
1349+
(save-excursion
1350+
(goto-char (point-min))
1351+
(let ((max-pos (point-max))
1352+
(words (pop loc))
1353+
(lines (pop loc))
1354+
(columns (pop loc)))
1355+
(setq max-pos (rust--format-forward rust--format-word words max-pos))
1356+
(setq max-pos (rust--format-forward rust--format-line lines max-pos))
1357+
(when (> lines 0) (forward-char))
1358+
(let ((initial-column (current-column))
1359+
(save-point (point)))
1360+
(move-end-of-line nil)
1361+
(when (> (current-column) (+ initial-column columns))
1362+
(goto-char save-point)
1363+
(forward-char columns)))
1364+
(min (point) max-pos)))))
1365+
12841366
(defun rust-format-buffer ()
12851367
"Format the current buffer using rustfmt."
12861368
(interactive)
@@ -1289,58 +1371,37 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
12891371

12901372
(let* ((current (current-buffer))
12911373
(base (or (buffer-base-buffer current) current))
1292-
buffer-pos
1293-
window-pos)
1374+
buffer-loc
1375+
window-loc)
12941376
(dolist (buffer (buffer-list))
12951377
(when (or (eq buffer base)
12961378
(eq (buffer-base-buffer buffer) base))
1297-
(with-current-buffer buffer
1298-
(push (list buffer
1299-
(line-number-at-pos)
1300-
(current-column))
1301-
buffer-pos))))
1379+
(push (list buffer
1380+
(rust--format-get-loc buffer nil))
1381+
buffer-loc)))
13021382
(dolist (window (window-list))
13031383
(let ((buffer (window-buffer window)))
13041384
(when (or (eq buffer base)
13051385
(eq (buffer-base-buffer buffer) base))
13061386
(let ((start (window-start window))
13071387
(point (window-point window)))
1308-
(with-current-buffer buffer
1309-
(push (list window
1310-
(line-number-at-pos start)
1311-
(save-excursion (goto-char start) (current-column))
1312-
(line-number-at-pos point)
1313-
(save-excursion (goto-char point) (current-column)))
1314-
window-pos))))))
1315-
(rust--format-call current)
1316-
(dolist (pos buffer-pos)
1317-
(let ((buffer (pop pos))
1318-
(line (pop pos))
1319-
(column (pop pos)))
1388+
(push (list window
1389+
(rust--format-get-loc buffer start)
1390+
(rust--format-get-loc buffer point))
1391+
window-loc)))))
1392+
(rust--format-call (current-buffer))
1393+
(dolist (loc buffer-loc)
1394+
(let* ((buffer (pop loc))
1395+
(pos (rust--format-get-pos buffer (pop loc))))
13201396
(with-current-buffer buffer
1321-
;; Move to the same line and column as before. This is best
1322-
;; effort: if rustfmt inserted lines before point, we end up in
1323-
;; the wrong place. See issue #162.
1324-
(goto-char (point-min))
1325-
(forward-line (1- line))
1326-
(forward-char column))))
1327-
(dolist (pos window-pos)
1328-
(let ((window (pop pos))
1329-
(start-line (pop pos))
1330-
(start-column (pop pos))
1331-
(point-line (pop pos))
1332-
(point-column (pop pos)))
1333-
(with-current-buffer (window-buffer window)
1334-
(let ((start (save-excursion (goto-char (point-min))
1335-
(forward-line (1- start-line))
1336-
(forward-char start-column)
1337-
(point)))
1338-
(point (save-excursion (goto-char (point-min))
1339-
(forward-line (1- point-line))
1340-
(forward-char point-column)
1341-
(point))))
1342-
(set-window-start window start)
1343-
(set-window-point window point))))))
1397+
(goto-char pos))))
1398+
(dolist (loc window-loc)
1399+
(let* ((window (pop loc))
1400+
(buffer (window-buffer window))
1401+
(start (rust--format-get-pos buffer (pop loc)))
1402+
(pos (rust--format-get-pos buffer (pop loc))))
1403+
(set-window-start window start)
1404+
(set-window-point window pos))))
13441405

13451406
;; Issue #127: Running this on a buffer acts like a revert, and could cause
13461407
;; the fontification to get out of sync. Call the same hook to ensure it is

0 commit comments

Comments
 (0)