summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTianxiang Xiong <tianxiang.xiong@gmail.com>2017-12-11 00:03:23 -0800
committerBozhidar Batsov <bozhidar.batsov@gmail.com>2017-12-13 19:06:48 +0000
commit8cd76482bbac1e1c850c74f0123b5d929fa444e2 (patch)
tree7b848bc4ca00f24373bac2d264927a87b872ec43
parentbd051f2f2abf15d6f02f53d3452a79644e30538e (diff)
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`.
-rw-r--r--CHANGELOG.md2
-rw-r--r--cider-interaction.el108
2 files changed, 68 insertions, 42 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5606bdb7..7e853e02 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@
* [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.
* [#2078](https://github.com/clojure-emacs/cider/pull/2078): Improve startup time by bundling together sync requests during startup.
* `cider-rotate-default-connection` will warn if you use it with only a single active connection.
-* `cider-format-buffer` preserves the point position.
+* `cider-format-buffer` tries to preserve the point position.
### Bugs Fixed
diff --git a/cider-interaction.el b/cider-interaction.el
index 3f24fe5a..58384e91 100644
--- a/cider-interaction.el
+++ b/cider-interaction.el
@@ -1763,36 +1763,8 @@ The heavy lifting is done by `cider-load-buffer'."
(defalias 'cider-eval-buffer 'cider-load-buffer
"A convenience alias as some people are confused by the load-* names.")
-(defun cider--format-buffer (formatter)
- "Format the contents of the current buffer.
-
-Uses FORMATTER, a function of one argument, to convert the string contents
-of the buffer into a formatted string."
- (let* ((original (substring-no-properties (buffer-string)))
- (formatted (funcall formatter original)))
- (unless (equal original formatted)
- (let ((current-line (line-number-at-pos))
- (current-column (current-column)))
- (erase-buffer)
- (insert formatted)
- ;; we have to preserve our point location in the buffer,
- ;; but save-excursion doesn't work, because of erase-buffer
- (goto-char (point-min))
- (forward-line (1- current-line))
- (forward-char current-column)))))
-
-(defun cider-format-buffer ()
- "Format the Clojure code in the current buffer."
- (interactive)
- (cider-ensure-connected)
- (cider--format-buffer #'cider-sync-request:format-code))
-
-(defun cider-format-edn-buffer ()
- "Format the EDN data in the current buffer."
- (interactive)
- (cider-ensure-connected)
- (cider--format-buffer (lambda (edn)
- (cider-sync-request:format-edn edn (cider--pretty-print-width)))))
+
+;; Format
(defun cider--format-reindent (formatted start)
"Reindent FORMATTED to align with buffer position START."
@@ -1800,18 +1772,41 @@ of the buffer into a formatted string."
(indent-line (concat "\n" (make-string start-column ? ))))
(replace-regexp-in-string "\n" indent-line formatted)))
+
+;;; Format region
+
(defun cider--format-region (start end formatter)
"Format the contents of the given region.
START and END represent the region's boundaries.
+
FORMATTER is a function of one argument which is used to convert
-the string contents of the region into a formatted string."
+the string contents of the region into a formatted string.
+
+Uses the following heuristic to try to maintain point position:
+
+- Take a snippet of text starting at current position, up to 64 chars.
+- Search for the snippet, with lax whitespace, in the formatted text.
+ - If snippet is less than 64 chars (point was near end of buffer), search
+ from end instead of beginning.
+- Place point at match beginning, or `point-min' if no match."
(let* ((original (buffer-substring-no-properties start end))
(formatted (funcall formatter original))
(indented (cider--format-reindent formatted start)))
(unless (equal original indented)
- (delete-region start end)
- (insert indented))))
+ (let* ((pos (point))
+ (pos-max (1+ (buffer-size)))
+ (l 64)
+ (endp (> (+ pos l) pos-max))
+ (snippet (thread-last (buffer-substring-no-properties
+ pos (min (+ pos l) pos-max))
+ (replace-regexp-in-string "[[:space:]\t\n\r]+" "[[:space:]\t\n\r]*"))))
+ (delete-region start end)
+ (insert indented)
+ (goto-char (if endp (point-max) (point-min)))
+ (funcall (if endp #'re-search-backward #'re-search-forward) snippet nil t)
+ (goto-char (or (match-beginning 0) start))
+ (when (looking-at-p "\n") (forward-char))))))
(defun cider-format-region (start end)
"Format the Clojure code in the current region.
@@ -1820,6 +1815,43 @@ START and END represent the region's boundaries."
(cider-ensure-connected)
(cider--format-region start end #'cider-sync-request:format-code))
+
+;;; Format defun
+
+(defun cider-format-defun ()
+ "Format the code in the current defun."
+ (interactive)
+ (cider-ensure-connected)
+ (save-excursion
+ (mark-defun)
+ (cider-format-region (region-beginning) (region-end))))
+
+
+;;; Format buffer
+
+(defun cider--format-buffer (formatter)
+ "Format the contents of the current buffer.
+
+Uses FORMATTER, a function of one argument, to convert the string contents
+of the buffer into a formatted string."
+ (cider--format-region 1 (1+ (buffer-size)) formatter))
+
+(defun cider-format-buffer ()
+ "Format the Clojure code in the current buffer."
+ (interactive)
+ (cider-ensure-connected)
+ (cider--format-buffer #'cider-sync-request:format-code))
+
+
+;;; Format EDN
+
+(defun cider-format-edn-buffer ()
+ "Format the EDN data in the current buffer."
+ (interactive)
+ (cider-ensure-connected)
+ (cider--format-buffer (lambda (edn)
+ (cider-sync-request:format-edn edn (cider--pretty-print-width)))))
+
(defun cider-format-edn-region (start end)
"Format the EDN data in the current region.
START and END represent the region's boundaries."
@@ -1831,15 +1863,9 @@ START and END represent the region's boundaries."
(lambda (edn)
(cider-sync-request:format-edn edn right-margin)))))
-(defun cider-format-defun ()
- "Format the code in the current defun."
- (interactive)
- (cider-ensure-connected)
- (save-excursion
- (mark-defun)
- (cider-format-region (region-beginning) (region-end))))
+
+;;; Interrupt evaluation
-;;; interrupt evaluation
(defun cider-interrupt-handler (buffer)
"Create an interrupt response handler for BUFFER."
(nrepl-make-response-handler buffer nil nil nil nil))