branch: elpa/clojure-ts-mode
commit ee8baed6437452c76e9ce778038e2a28219c76e5
Author: Roman Rudakov <rruda...@fastmail.com>
Commit: Bozhidar Batsov <bozhi...@batsov.dev>

    Add custom fill-paragraph function to respect docstrings
---
 CHANGELOG.md                                |  2 +
 README.md                                   | 11 +++++
 clojure-ts-mode.el                          | 37 +++++++++++++++++
 test/clojure-ts-mode-fill-paragraph-test.el | 62 +++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1679109b2..3f0f61a824 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,8 @@
 - [#42]: Fix font locking of definitions with metadata
 - [#42]: Fix indentation of definitions with metadata
 - Fix semantic indentation of quoted functions
+- Add custom `fill-paragraph-function` which respects docstrings similar to
+  `clojure-mode`.
 
 ## 0.2.2 (2024-02-16)
 
diff --git a/README.md b/README.md
index 62d8414ccf..a3d762ccb9 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,17 @@ To make forms inside of `(comment ...)` forms appear as 
top-level forms for eval
 (setq clojure-ts-toplevel-inside-comment-form t)
 ```
 
+### Fill paragraph
+
+To change the maximal line length used by `M-x prog-fill-reindent-defun` (also
+bound to `M-q` by default) to reformat docstrings and comments it's possible to
+customize `clojure-ts-fill-paragraph` variable (by default set to the value of
+Emacs' `fill-paragraph` value).
+
+Every new line in the docstrings is indented by
+`clojure-ts-docstring-fill-prefix-width` number of spaces (set to 2 by default
+which matches the `clojure-mode` settings).
+
 ## Rationale
 
 [clojure-mode](https://github.com/clojure-emacs/clojure-mode) has served us 
well
diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el
index 2c56c19fe4..1d6fa215e7 100644
--- a/clojure-ts-mode.el
+++ b/clojure-ts-mode.el
@@ -97,6 +97,21 @@ itself."
   :safe #'booleanp
   :package-version '(clojure-ts-mode . "0.2.1"))
 
+(defcustom clojure-ts-docstring-fill-column fill-column
+  "Value of `fill-column' to use when filling a docstring."
+  :type 'integer
+  :safe #'integerp
+  :package-version '(clojure-ts-mode . "0.2.3"))
+
+(defcustom clojure-ts-docstring-fill-prefix-width 2
+  "Width of `fill-prefix' when filling a docstring.
+The default value conforms with the de facto convention for
+Clojure docstrings, aligning the second line with the opening
+double quotes on the third column."
+  :type 'integer
+  :safe #'integerp
+  :package-version '(clojure-ts-mode . "0.2.3"))
+
 (defvar clojure-ts--debug nil
   "Enables debugging messages, shows current node in mode-line.
 Only intended for use at development time.")
@@ -863,6 +878,27 @@ forms like deftype, defrecord, reify, proxy, etc."
         '(semantic fixed)
         clojure-ts-indent-style)))))
 
+(defun clojure-ts--docstring-fill-prefix ()
+  "The prefix string used by `clojure-ts--fill-paragraph'.
+It is simply `clojure-ts-docstring-fill-prefix-width' number of spaces."
+  (make-string clojure-ts-docstring-fill-prefix-width ? ))
+
+(defun clojure-ts--fill-paragraph (&optional justify)
+  "Like `fill-paragraph', but can handler Clojure docstrings.
+If JUSTIFY is non-nil, justify as well as fill the paragraph."
+  (let ((current-node (treesit-node-at (point))))
+    (if (clojure-ts--match-docstring nil current-node nil)
+        (let ((fill-column (or clojure-ts-docstring-fill-column fill-column))
+              (fill-prefix (clojure-ts--docstring-fill-prefix))
+              (beg-doc (treesit-node-start current-node))
+              (end-doc (treesit-node-end current-node)))
+          (save-restriction
+            (narrow-to-region beg-doc end-doc)
+            (fill-paragraph justify)))
+      (or (fill-comment-paragraph justify)
+          (fill-paragraph justify)))
+    t))
+
 (defconst clojure-ts--sexp-nodes
   '("#_" ;; transpose-sexp near a discard macro moves it around.
     "num_lit" "sym_lit" "kwd_lit" "nil_lit" "bool_lit"
@@ -963,6 +999,7 @@ See `clojure-ts--font-lock-settings' for usage of 
MARKDOWN-AVAILABLE."
                 (keyword string char symbol builtin type)
                 (constant number quote metadata doc)
                 (bracket deref function regex tagged-literals)))
+  (setq-local fill-paragraph-function #'clojure-ts--fill-paragraph)
   (when (boundp 'treesit-thing-settings) ;; Emacs 30+
     (setq-local treesit-thing-settings clojure-ts--thing-settings)))
 
diff --git a/test/clojure-ts-mode-fill-paragraph-test.el 
b/test/clojure-ts-mode-fill-paragraph-test.el
new file mode 100644
index 0000000000..a7e2dde53c
--- /dev/null
+++ b/test/clojure-ts-mode-fill-paragraph-test.el
@@ -0,0 +1,62 @@
+;;; clojure-ts-mode-fill-paragraph-test.el ---       -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2025  Roman Rudakov
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The unit test suite of CLojure TS Mode
+
+;;; Code:
+
+(require 'clojure-ts-mode)
+(require 'buttercup)
+
+(describe "clojure-ts--fill-paragraph"
+  (it "should reformat only the docstring"
+    (with-clojure-ts-buffer "(ns foo)
+
+(defn hello-world
+  \"This is a very long docstring that should be reformatted using 
fill-paragraph function.\"
+  []
+  (pringln \"Hello world\"))"
+                            (goto-char 40)
+                            (prog-fill-reindent-defun)
+                            (expect (buffer-substring-no-properties 
(point-min) (point-max))
+                                    :to-equal
+                                    "(ns foo)
+
+(defn hello-world
+  \"This is a very long docstring that should be reformatted using
+  fill-paragraph function.\"
+  []
+  (pringln \"Hello world\"))")))
+
+  (it "should reformat normal comments properly"
+    (with-clojure-ts-buffer "(ns foo)
+
+;; This is a very long comment that should be reformatted using fill-paragraph 
function."
+                              (goto-char 20)
+                              (prog-fill-reindent-defun)
+                              (expect (buffer-substring-no-properties 
(point-min) (point-max))
+                                      :to-equal
+                                      "(ns foo)
+
+;; This is a very long comment that should be reformatted using
+;; fill-paragraph function."))))
+
+;;; clojure-ts-mode-fill-paragraph-test.el ends here

Reply via email to