diff options
author | Tianxiang Xiong <tianxiang.xiong@gmail.com> | 2017-12-11 00:03:23 -0800 |
---|---|---|
committer | Bozhidar Batsov <bozhidar.batsov@gmail.com> | 2017-12-13 19:06:48 +0000 |
commit | 8cd76482bbac1e1c850c74f0123b5d929fa444e2 (patch) | |
tree | 7b848bc4ca00f24373bac2d264927a87b872ec43 | |
parent | bd051f2f2abf15d6f02f53d3452a79644e30538e (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.md | 2 | ||||
-rw-r--r-- | cider-interaction.el | 108 |
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)) |