Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.0 KiB

4 years ago
  1. ;;; cider-format.el --- Code and EDN formatting functionality -*- lexical-binding: t -*-
  2. ;; Copyright © 2013-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors
  3. ;;
  4. ;; Author: Bozhidar Batsov <bozhidar@batsov.com>
  5. ;; Artur Malabarba <bruce.connor.am@gmail.com>
  6. ;; This program is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; This program is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;; This file is not part of GNU Emacs.
  17. ;;; Commentary:
  18. ;; Middleware-powered code and EDN formatting functionality.
  19. ;;; Code:
  20. (require 'map)
  21. (require 'seq)
  22. (require 'subr-x)
  23. (require 'cider-client)
  24. (require 'cider-util)
  25. ;; Format
  26. (defun cider--format-reindent (formatted start)
  27. "Reindent FORMATTED to align with buffer position START."
  28. (let* ((start-column (save-excursion (goto-char start) (current-column)))
  29. (indent-line (concat "\n" (make-string start-column ? ))))
  30. (replace-regexp-in-string "\n" indent-line formatted)))
  31. ;;; Format region
  32. (defun cider--format-region (start end formatter)
  33. "Format the contents of the given region.
  34. START and END represent the region's boundaries.
  35. FORMATTER is a function of one argument which is used to convert
  36. the string contents of the region into a formatted string.
  37. Uses the following heuristic to try to maintain point position:
  38. - Take a snippet of text starting at current position, up to 64 chars.
  39. - Search for the snippet, with lax whitespace, in the formatted text.
  40. - If snippet is less than 64 chars (point was near end of buffer), search
  41. from end instead of beginning.
  42. - Place point at match beginning, or `point-min' if no match."
  43. (let* ((original (buffer-substring-no-properties start end))
  44. (formatted (funcall formatter original))
  45. (indented (cider--format-reindent formatted start)))
  46. (unless (equal original indented)
  47. (let* ((pos (point))
  48. (pos-max (1+ (buffer-size)))
  49. (l 64)
  50. (endp (> (+ pos l) pos-max))
  51. (snippet (thread-last (buffer-substring-no-properties
  52. pos (min (+ pos l) pos-max))
  53. (regexp-quote)
  54. (replace-regexp-in-string "[[:space:]\t\n\r]+" "[[:space:]\t\n\r]*"))))
  55. (delete-region start end)
  56. (insert indented)
  57. (goto-char (if endp (point-max) (point-min)))
  58. (funcall (if endp #'re-search-backward #'re-search-forward) snippet nil t)
  59. (goto-char (or (match-beginning 0) start))
  60. (when (looking-at-p "\n") (forward-char))))))
  61. ;;;###autoload
  62. (defun cider-format-region (start end)
  63. "Format the Clojure code in the current region.
  64. START and END represent the region's boundaries."
  65. (interactive "r")
  66. (cider-ensure-connected)
  67. (cider--format-region start end #'cider-sync-request:format-code))
  68. ;;; Format defun
  69. ;;;###autoload
  70. (defun cider-format-defun ()
  71. "Format the code in the current defun."
  72. (interactive)
  73. (cider-ensure-connected)
  74. (let ((defun-bounds (cider-defun-at-point 't)))
  75. (cider-format-region (car defun-bounds) (cadr defun-bounds))))
  76. ;;; Format buffer
  77. (defun cider--format-buffer (formatter)
  78. "Format the contents of the current buffer.
  79. Uses FORMATTER, a function of one argument, to convert the string contents
  80. of the buffer into a formatted string."
  81. (cider--format-region 1 (1+ (buffer-size)) formatter))
  82. ;;;###autoload
  83. (defun cider-format-buffer ()
  84. "Format the Clojure code in the current buffer."
  85. (interactive)
  86. (check-parens)
  87. (cider-ensure-connected)
  88. (cider--format-buffer #'cider-sync-request:format-code))
  89. ;;; Format EDN
  90. ;;;###autoload
  91. (defun cider-format-edn-buffer ()
  92. "Format the EDN data in the current buffer."
  93. (interactive)
  94. (check-parens)
  95. (cider-ensure-connected)
  96. (cider--format-buffer (lambda (edn)
  97. (cider-sync-request:format-edn edn fill-column))))
  98. ;;;###autoload
  99. (defun cider-format-edn-region (start end)
  100. "Format the EDN data in the current region.
  101. START and END represent the region's boundaries."
  102. (interactive "r")
  103. (cider-ensure-connected)
  104. (let* ((start-column (save-excursion (goto-char start) (current-column)))
  105. (right-margin (- fill-column start-column)))
  106. (cider--format-region start end
  107. (lambda (edn)
  108. (cider-sync-request:format-edn edn right-margin)))))
  109. ;;;###autoload
  110. (defun cider-format-edn-last-sexp ()
  111. "Format the EDN data of the last sexp."
  112. (interactive)
  113. (apply 'cider-format-edn-region (cider-sexp-at-point 'bounds)))
  114. (provide 'cider-format)
  115. ;;; cider-format.el ends here