Skip to content

Commit 8f1297a

Browse files
authored
Merge pull request #187 from tspiteri/format-other-buffers
handle indirect buffers and multiple windows in rust-format-buffer
2 parents cd09a54 + 664c7b0 commit 8f1297a

File tree

1 file changed

+114
-10
lines changed

1 file changed

+114
-10
lines changed

rust-mode.el

Lines changed: 114 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,23 +1283,127 @@ This is written mainly to be used as `end-of-defun-function' for Rust."
12831283
(kill-buffer))
12841284
(error "Rustfmt failed, see *rustfmt* buffer for details"))))
12851285

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

1292-
(let ((cur-line (line-number-at-pos))
1293-
(cur-column (current-column))
1294-
(cur-win-start (window-start)))
1374+
(let* ((current (current-buffer))
1375+
(base (or (buffer-base-buffer current) current))
1376+
buffer-loc
1377+
window-loc)
1378+
(dolist (buffer (buffer-list))
1379+
(when (or (eq buffer base)
1380+
(eq (buffer-base-buffer buffer) base))
1381+
(push (list buffer
1382+
(rust--format-get-loc buffer nil))
1383+
buffer-loc)))
1384+
(dolist (window (window-list))
1385+
(let ((buffer (window-buffer window)))
1386+
(when (or (eq buffer base)
1387+
(eq (buffer-base-buffer buffer) base))
1388+
(let ((start (window-start window))
1389+
(point (window-point window)))
1390+
(push (list window
1391+
(rust--format-get-loc buffer start)
1392+
(rust--format-get-loc buffer point))
1393+
window-loc)))))
12951394
(rust--format-call (current-buffer))
1296-
;; Move to the same line and column as before. This is best
1297-
;; effort: if rustfmt inserted lines before point, we end up in
1298-
;; the wrong place. See issue #162.
1299-
(goto-char (point-min))
1300-
(forward-line (1- cur-line))
1301-
(forward-char cur-column)
1302-
(set-window-start (selected-window) cur-win-start))
1395+
(dolist (loc buffer-loc)
1396+
(let* ((buffer (pop loc))
1397+
(pos (rust--format-get-pos buffer (pop loc))))
1398+
(with-current-buffer buffer
1399+
(goto-char pos))))
1400+
(dolist (loc window-loc)
1401+
(let* ((window (pop loc))
1402+
(buffer (window-buffer window))
1403+
(start (rust--format-get-pos buffer (pop loc)))
1404+
(pos (rust--format-get-pos buffer (pop loc))))
1405+
(set-window-start window start)
1406+
(set-window-point window pos))))
13031407

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

0 commit comments

Comments
 (0)