Skip to content

Commit 8cd7648

Browse files
xiongtxbbatsov
authored andcommitted
Improve point restoration of cider--format-buffer
Fix #2126 Also make `cider--format-region` the base format function and reduce duplication in others, like `cider--format-buffer`.
1 parent bd051f2 commit 8cd7648

File tree

2 files changed

+68
-42
lines changed

2 files changed

+68
-42
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* [cider-nrepl#438](https://github.com/clojure-emacs/cider-nrepl/pull/438): Improve startup time by deferring loading CIDER's middleware until the first usage.
1414
* [#2078](https://github.com/clojure-emacs/cider/pull/2078): Improve startup time by bundling together sync requests during startup.
1515
* `cider-rotate-default-connection` will warn if you use it with only a single active connection.
16-
* `cider-format-buffer` preserves the point position.
16+
* `cider-format-buffer` tries to preserve the point position.
1717

1818
### Bugs Fixed
1919

cider-interaction.el

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,55 +1763,50 @@ The heavy lifting is done by `cider-load-buffer'."
17631763
(defalias 'cider-eval-buffer 'cider-load-buffer
17641764
"A convenience alias as some people are confused by the load-* names.")
17651765

1766-
(defun cider--format-buffer (formatter)
1767-
"Format the contents of the current buffer.
1768-
1769-
Uses FORMATTER, a function of one argument, to convert the string contents
1770-
of the buffer into a formatted string."
1771-
(let* ((original (substring-no-properties (buffer-string)))
1772-
(formatted (funcall formatter original)))
1773-
(unless (equal original formatted)
1774-
(let ((current-line (line-number-at-pos))
1775-
(current-column (current-column)))
1776-
(erase-buffer)
1777-
(insert formatted)
1778-
;; we have to preserve our point location in the buffer,
1779-
;; but save-excursion doesn't work, because of erase-buffer
1780-
(goto-char (point-min))
1781-
(forward-line (1- current-line))
1782-
(forward-char current-column)))))
1783-
1784-
(defun cider-format-buffer ()
1785-
"Format the Clojure code in the current buffer."
1786-
(interactive)
1787-
(cider-ensure-connected)
1788-
(cider--format-buffer #'cider-sync-request:format-code))
1789-
1790-
(defun cider-format-edn-buffer ()
1791-
"Format the EDN data in the current buffer."
1792-
(interactive)
1793-
(cider-ensure-connected)
1794-
(cider--format-buffer (lambda (edn)
1795-
(cider-sync-request:format-edn edn (cider--pretty-print-width)))))
1766+
1767+
;; Format
17961768

17971769
(defun cider--format-reindent (formatted start)
17981770
"Reindent FORMATTED to align with buffer position START."
17991771
(let* ((start-column (save-excursion (goto-char start) (current-column)))
18001772
(indent-line (concat "\n" (make-string start-column ? ))))
18011773
(replace-regexp-in-string "\n" indent-line formatted)))
18021774

1775+
1776+
;;; Format region
1777+
18031778
(defun cider--format-region (start end formatter)
18041779
"Format the contents of the given region.
18051780
18061781
START and END represent the region's boundaries.
1782+
18071783
FORMATTER is a function of one argument which is used to convert
1808-
the string contents of the region into a formatted string."
1784+
the string contents of the region into a formatted string.
1785+
1786+
Uses the following heuristic to try to maintain point position:
1787+
1788+
- Take a snippet of text starting at current position, up to 64 chars.
1789+
- Search for the snippet, with lax whitespace, in the formatted text.
1790+
- If snippet is less than 64 chars (point was near end of buffer), search
1791+
from end instead of beginning.
1792+
- Place point at match beginning, or `point-min' if no match."
18091793
(let* ((original (buffer-substring-no-properties start end))
18101794
(formatted (funcall formatter original))
18111795
(indented (cider--format-reindent formatted start)))
18121796
(unless (equal original indented)
1813-
(delete-region start end)
1814-
(insert indented))))
1797+
(let* ((pos (point))
1798+
(pos-max (1+ (buffer-size)))
1799+
(l 64)
1800+
(endp (> (+ pos l) pos-max))
1801+
(snippet (thread-last (buffer-substring-no-properties
1802+
pos (min (+ pos l) pos-max))
1803+
(replace-regexp-in-string "[[:space:]\t\n\r]+" "[[:space:]\t\n\r]*"))))
1804+
(delete-region start end)
1805+
(insert indented)
1806+
(goto-char (if endp (point-max) (point-min)))
1807+
(funcall (if endp #'re-search-backward #'re-search-forward) snippet nil t)
1808+
(goto-char (or (match-beginning 0) start))
1809+
(when (looking-at-p "\n") (forward-char))))))
18151810

18161811
(defun cider-format-region (start end)
18171812
"Format the Clojure code in the current region.
@@ -1820,6 +1815,43 @@ START and END represent the region's boundaries."
18201815
(cider-ensure-connected)
18211816
(cider--format-region start end #'cider-sync-request:format-code))
18221817

1818+
1819+
;;; Format defun
1820+
1821+
(defun cider-format-defun ()
1822+
"Format the code in the current defun."
1823+
(interactive)
1824+
(cider-ensure-connected)
1825+
(save-excursion
1826+
(mark-defun)
1827+
(cider-format-region (region-beginning) (region-end))))
1828+
1829+
1830+
;;; Format buffer
1831+
1832+
(defun cider--format-buffer (formatter)
1833+
"Format the contents of the current buffer.
1834+
1835+
Uses FORMATTER, a function of one argument, to convert the string contents
1836+
of the buffer into a formatted string."
1837+
(cider--format-region 1 (1+ (buffer-size)) formatter))
1838+
1839+
(defun cider-format-buffer ()
1840+
"Format the Clojure code in the current buffer."
1841+
(interactive)
1842+
(cider-ensure-connected)
1843+
(cider--format-buffer #'cider-sync-request:format-code))
1844+
1845+
1846+
;;; Format EDN
1847+
1848+
(defun cider-format-edn-buffer ()
1849+
"Format the EDN data in the current buffer."
1850+
(interactive)
1851+
(cider-ensure-connected)
1852+
(cider--format-buffer (lambda (edn)
1853+
(cider-sync-request:format-edn edn (cider--pretty-print-width)))))
1854+
18231855
(defun cider-format-edn-region (start end)
18241856
"Format the EDN data in the current region.
18251857
START and END represent the region's boundaries."
@@ -1831,15 +1863,9 @@ START and END represent the region's boundaries."
18311863
(lambda (edn)
18321864
(cider-sync-request:format-edn edn right-margin)))))
18331865

1834-
(defun cider-format-defun ()
1835-
"Format the code in the current defun."
1836-
(interactive)
1837-
(cider-ensure-connected)
1838-
(save-excursion
1839-
(mark-defun)
1840-
(cider-format-region (region-beginning) (region-end))))
1866+
1867+
;;; Interrupt evaluation
18411868

1842-
;;; interrupt evaluation
18431869
(defun cider-interrupt-handler (buffer)
18441870
"Create an interrupt response handler for BUFFER."
18451871
(nrepl-make-response-handler buffer nil nil nil nil))

0 commit comments

Comments
 (0)