From 6cf86ed4c1c7b5a7b74630347de0dfb413d3cd18 Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Thu, 4 Nov 2021 21:44:46 +0100
Subject: Add new basic Emacs Lisp code formatting function

* lisp/emacs-lisp/pp.el (pp-emacs-lisp-code): New interface function.
(pp): Mention it.
(pp--insert-lisp, pp--format-vector, pp--format-list)
(pp--format-function, pp--format-definition, pp--insert-binding)
(pp--insert, pp--indent-buffer): New helper functions.
---
 .../lisp/emacs-lisp/pp-resources/code-formats.erts | 97 ++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 test/lisp/emacs-lisp/pp-resources/code-formats.erts

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
new file mode 100644
index 00000000000..821e326867b
--- /dev/null
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -0,0 +1,97 @@
+Code:
+  (lambda ()
+    (emacs-lisp-mode)
+    (let ((code (read (current-buffer))))
+      (erase-buffer)
+      (pp-emacs-lisp-code code)
+      (untabify (point-min) (point-max))))
+
+Name: code-formats1
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2))
+    (zot 1 2 (funcall bar 2))))
+=-=-=
+
+
+Name: code-formats2
+
+=-=
+(defun pp-emacs-lisp-code (sexp)
+  "Insert SEXP into the current buffer, formatted as Emacs Lisp code."
+  (require 'edebug)
+  (let ((start (point))
+        (standard-output (current-buffer)))
+    (pp--insert-lisp sexp)
+    (insert "\n")
+    (goto-char start)
+    (indent-sexp)))
+=-=-=
+
+
+Name: code-formats3
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2))
+    (zot-zot-zot-zot-zot-zot 1 2 (funcall
+                                  bar-bar-bar-bar-bar-bar-bar-bar-bar-bar 2))))
+=-=-=
+
+
+Name: code-formats4
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2)
+        foo bar zotfoo bar zotfoo bar zotfoo bar zotfoo bar zotfoo bar zotfoo
+        bar zot)
+    (zot 1 2 (funcall bar 2))))
+=-=-=
+
+
+Name: code-formats5
+
+=-=
+(defgroup pp ()
+  "Pretty printer for Emacs Lisp."
+  :prefix "pp-"
+  :group 'lisp)
+=-=-=
+
+Name: code-formats6
+
+=-=
+(defcustom pp-escape-newlines t
+  "Value of `print-escape-newlines' used by pp-* functions."
+  :type 'boolean
+  :group 'pp)
+=-=-=
+
+Name: code-formats7
+
+=-=
+(defun pp (object &optional stream)
+  (princ (pp-to-string object) (or stream standard-output)))
+=-=-=
+
+
+Name: code-formats8
+
+=-=
+(defun pp-eval-expression (expression)
+  "Evaluate EXPRESSION and pretty-print its value.
+Also add the value to the front of the list in the variable `values'."
+  (interactive (list (read--expression "Eval: ")))
+  (message "Evaluating...")
+  (let ((result (eval expression lexical-binding)))
+    (values--store-value result)
+    (pp-display-expression result "*Pp Eval Output*")))
+=-=-=
-- 
cgit v1.2.3


From fb1267d90a5c25a29dbdae170ea065e017b05d29 Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Thu, 4 Nov 2021 22:07:48 +0100
Subject: Indent lambdas/closures better

* lisp/emacs-lisp/pp.el (pp--format-function): Indent lambdas and
closures better.
---
 lisp/emacs-lisp/pp.el                               | 13 ++++++++++++-
 test/lisp/emacs-lisp/pp-resources/code-formats.erts |  8 ++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index ca3f2a270e2..1d7b935b6d9 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -236,9 +236,20 @@ Ignores leading comment characters."
 (defun pp--format-function (sexp)
   (let* ((sym (car sexp))
          (edebug (get sym 'edebug-form-spec))
-         (indent (get sym 'lisp-indent-function)))
+         (indent (get sym 'lisp-indent-function))
+         (doc (get sym 'doc-string-elt)))
     (when (eq indent 'defun)
       (setq indent 2))
+    ;; We probably want to keep all the elements before the doc string
+    ;; on a single line.
+    (when doc
+      (setq indent (1- doc)))
+    ;; Special-case closures -- these shouldn't really exist in actual
+    ;; source code, so there's no indentation information.  But make
+    ;; them output slightly better.
+    (when (and (not indent)
+               (eq sym 'closure))
+      (setq indent 0))
     (pp--insert "(" sym)
     (pop sexp)
     ;; Get the first entries on the first line.
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
index 821e326867b..f48e262f69d 100644
--- a/test/lisp/emacs-lisp/pp-resources/code-formats.erts
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -95,3 +95,11 @@ Also add the value to the front of the list in the variable `values'."
     (values--store-value result)
     (pp-display-expression result "*Pp Eval Output*")))
 =-=-=
+
+Name: code-formats9
+
+=-=
+(lambda ()
+  (interactive)
+  1)
+=-=-=
-- 
cgit v1.2.3


From 4cf7af5a2a9aecb067d95b96a5965cc74627e86b Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Thu, 4 Nov 2021 23:16:47 +0100
Subject: Tweak multi-line expressions in pp--format-function

* lisp/emacs-lisp/pp.el (pp--format-function): Fix up multi-line
expressions.
---
 lisp/emacs-lisp/pp.el                               | 10 ++++++++--
 test/lisp/emacs-lisp/pp-resources/code-formats.erts | 13 ++++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index 67a21c53915..df837fa691e 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -267,8 +267,14 @@ Ignores leading comment characters."
     ;; Get the first entries on the first line.
     (if indent
         (pp--format-definition sexp indent edebug)
-      (while sexp
-        (pp--insert " " (pop sexp))))
+      (let ((prev 0))
+        (while sexp
+          (let ((start (point)))
+            ;; Don't put sexps on the same line as a multi-line sexp
+            ;; preceding it.
+            (pp--insert (if (> prev 1) "\n" " ")
+                        (pop sexp))
+            (setq prev (count-lines start (point)))))))
     (insert ")")))
 
 (defun pp--format-definition (sexp indent edebug)
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
index f48e262f69d..c2733d84dae 100644
--- a/test/lisp/emacs-lisp/pp-resources/code-formats.erts
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -40,7 +40,8 @@ Name: code-formats3
   (let ((a 1)
         (b 2))
     (zot-zot-zot-zot-zot-zot 1 2 (funcall
-                                  bar-bar-bar-bar-bar-bar-bar-bar-bar-bar 2))))
+                                  bar-bar-bar-bar-bar-bar-bar-bar-bar-bar
+                                  2))))
 =-=-=
 
 
@@ -103,3 +104,13 @@ Name: code-formats9
   (interactive)
   1)
 =-=-=
+
+
+Name: code-formats10
+
+=-=
+(funcall foo (concat "zot" (if (length> site 0) site
+                             "bar")
+                     "+"
+                     (string-replace " " "+" query)))
+=-=-=
-- 
cgit v1.2.3


From c1865384d736cf290971e049a9d2f7869c7396da Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Fri, 5 Nov 2021 15:27:03 +0100
Subject: Allow 'pp' to limit the line widths

* lisp/emacs-lisp/pp.el (pp-max-width, pp-use-max-width): New user
options (bug#11934).
(pp-to-string): Use it.
(pp--insert-lisp): Tweak whether to use standard-output or not.
(pp--max-width): New function.
---
 etc/NEWS                                           |  5 ++
 lisp/emacs-lisp/pp.el                              | 90 ++++++++++++++++------
 .../lisp/emacs-lisp/pp-resources/code-formats.erts |  8 ++
 3 files changed, 78 insertions(+), 25 deletions(-)

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/etc/NEWS b/etc/NEWS
index 08ff1f1e697..9b4112a8f2b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -422,6 +422,11 @@ Use 'exif-parse-file' and 'exif-field' instead.
 
 * Lisp Changes in Emacs 29.1
 
+---
+*** New user option 'pp-use-max-width'.
+If non-nil, 'pp' will attempt to limit the line length when formatting
+long lists and vectors.
+
 ---
 *** New function 'pp-emacs-lisp-code'.
 'pp' formats general Lisp sexps.  This function does much the same,
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index ffaa2aeb93a..8ef5979a270 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -33,22 +33,43 @@
 
 (defcustom pp-escape-newlines t
   "Value of `print-escape-newlines' used by pp-* functions."
+  :type 'boolean)
+
+(defcustom pp-max-width t
+  "Max width to use when formatting.
+If nil, there's no max width.  If t, use the window width.
+Otherwise this should be a number."
+  :type '(choice (const :tag "none" nil)
+                 (const :tag "window width" t)
+                 number)
+  :version "29.1")
+
+(defcustom pp-use-max-width nil
+  "If non-nil, `pp'-related functions will try to fold lines.
+The target width is given by the `pp-max-width' variable."
   :type 'boolean
-  :group 'pp)
+  :version "29.1")
+
+(defvar pp--inhibit-function-formatting nil)
 
 ;;;###autoload
 (defun pp-to-string (object)
   "Return a string containing the pretty-printed representation of OBJECT.
 OBJECT can be any Lisp object.  Quoting characters are used as needed
 to make output that `read' can handle, whenever this is possible."
-  (with-temp-buffer
-    (lisp-mode-variables nil)
-    (set-syntax-table emacs-lisp-mode-syntax-table)
-    (let ((print-escape-newlines pp-escape-newlines)
-          (print-quoted t))
-      (prin1 object (current-buffer)))
-    (pp-buffer)
-    (buffer-string)))
+  (if pp-use-max-width
+      (let ((pp--inhibit-function-formatting t))
+        (with-temp-buffer
+          (pp-emacs-lisp-code object)
+          (buffer-string)))
+    (with-temp-buffer
+      (lisp-mode-variables nil)
+      (set-syntax-table emacs-lisp-mode-syntax-table)
+      (let ((print-escape-newlines pp-escape-newlines)
+            (print-quoted t))
+        (prin1 object (current-buffer)))
+      (pp-buffer)
+      (buffer-string))))
 
 ;;;###autoload
 (defun pp-buffer ()
@@ -56,7 +77,6 @@ to make output that `read' can handle, whenever this is possible."
   (interactive)
   (goto-char (point-min))
   (while (not (eobp))
-    ;; (message "%06d" (- (point-max) (point)))
     (cond
      ((ignore-errors (down-list 1) t)
       (save-excursion
@@ -86,6 +106,9 @@ can handle, whenever this is possible.
 This function does not apply special formatting rules for Emacs
 Lisp code.  See `pp-emacs-lisp-code' instead.
 
+By default, this function won't limit the line length of lists
+and vectors.  Bind `pp-use-max-width' to a non-nil value to do so.
+
 Output stream is STREAM, or value of `standard-output' (which see)."
   (princ (pp-to-string object) (or stream standard-output)))
 
@@ -191,17 +214,19 @@ Ignores leading comment characters."
 
 ;;;###autoload
 (defun pp-emacs-lisp-code (sexp)
-  "Insert SEXP into the current buffer, formatted as Emacs Lisp code."
+  "Insert SEXP into the current buffer, formatted as Emacs Lisp code.
+Use the `pp-max-width' variable to control the desired line length."
   (require 'edebug)
-  (let ((standard-output (current-buffer)))
-    (save-restriction
-      (narrow-to-region (point) (point))
+  (let ((obuf (current-buffer)))
+    (with-temp-buffer
+      (emacs-lisp-mode)
       (pp--insert-lisp sexp)
       (insert "\n")
       (goto-char (point-min))
       (indent-sexp)
       (while (re-search-forward " +$" nil t)
-        (replace-match "")))))
+        (replace-match ""))
+      (insert-into-buffer obuf))))
 
 (defun pp--insert-lisp (sexp)
   (cl-case (type-of sexp)
@@ -213,30 +238,35 @@ Ignores leading comment characters."
                 (cond
                  ((symbolp (cadr sexp))
                   (let ((print-quoted t))
-                    (prin1 sexp)))
+                    (prin1 sexp (current-buffer))))
                  ((consp (cadr sexp))
                   (insert "'")
                   (pp--format-list (cadr sexp)
                                    (set-marker (make-marker) (1- (point))))))
               (pp--format-list sexp)))
            (t
-            (princ sexp))))
+            (princ sexp (current-buffer)))))
     ;; Print some of the smaller integers as characters, perhaps?
     (integer
      (if (<= ?0 sexp ?z)
          (let ((print-integers-as-characters t))
-           (princ sexp))
-       (princ sexp)))
+           (princ sexp (current-buffer)))
+       (princ sexp (current-buffer))))
     (string
      (let ((print-escape-newlines t))
-       (prin1 sexp)))
-    (otherwise (princ sexp))))
+       (prin1 sexp (current-buffer))))
+    (otherwise (princ sexp (current-buffer)))))
 
 (defun pp--format-vector (sexp)
-  (prin1 sexp))
+  (insert "[")
+  (cl-loop for i from 0
+           for element across sexp
+           do (pp--insert (and (> i 0) " ") element))
+  (insert "]"))
 
 (defun pp--format-list (sexp &optional start)
   (if (and (symbolp (car sexp))
+           (not pp--inhibit-function-formatting)
            (not (keywordp (car sexp))))
       (pp--format-function sexp)
     (insert "(")
@@ -292,7 +322,7 @@ Ignores leading comment characters."
     (cl-decf indent))
   (when (stringp (car sexp))
     (insert "\n")
-    (prin1 (pop sexp)))
+    (prin1 (pop sexp) (current-buffer)))
   ;; Then insert the rest with line breaks before each form.
   (while sexp
     (insert "\n")
@@ -329,7 +359,7 @@ Ignores leading comment characters."
       (pp--insert-lisp thing))
     ;; We need to indent what we have so far to see if we have to fold.
     (pp--indent-buffer)
-    (when (> (current-column) (window-width))
+    (when (> (current-column) (pp--max-width))
       (save-excursion
         (goto-char start)
         (unless (looking-at "[ \t]+$")
@@ -338,13 +368,23 @@ Ignores leading comment characters."
         (goto-char (point-max))
         ;; If we're still too wide, then go up one step and try to
         ;; insert a newline there.
-        (when (> (current-column) (window-width))
+        (when (> (current-column) (pp--max-width))
           (condition-case ()
               (backward-up-list 1)
             (:success (when (looking-back " " 2)
                         (insert "\n")))
             (error nil)))))))
 
+(defun pp--max-width ()
+  (cond ((numberp pp-max-width)
+         pp-max-width)
+        ((null pp-max-width)
+         most-positive-fixnum)
+        ((eq pp-max-width t)
+         (window-width))
+        (t
+         (error "Invalid pp-max-width value: %s" pp-max-width))))
+
 (defun pp--indent-buffer ()
   (goto-char (point-min))
   (while (not (eobp))
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
index c2733d84dae..2b2001d0964 100644
--- a/test/lisp/emacs-lisp/pp-resources/code-formats.erts
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -114,3 +114,11 @@ Name: code-formats10
                      "+"
                      (string-replace " " "+" query)))
 =-=-=
+
+
+Name: code-formats11
+
+=-=
+(lambda ()
+  [(foo bar) (foo bar)])
+=-=-=
-- 
cgit v1.2.3


From 0d315102fed8cecccbac15232304000df5b66406 Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Tue, 4 Jan 2022 15:50:56 +0100
Subject: Improve pp-emacs-lisp-code for #'

* lisp/emacs-lisp/pp.el (pp--insert-lisp): Format (function ...)
as #'.
---
 lisp/emacs-lisp/pp.el                               | 6 ++++--
 test/lisp/emacs-lisp/pp-resources/code-formats.erts | 6 ++++++
 2 files changed, 10 insertions(+), 2 deletions(-)

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index a4dbd637553..d199716b2c5 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -24,6 +24,7 @@
 
 ;;; Code:
 
+(require 'cl-lib)
 (defvar font-lock-verbose)
 
 (defgroup pp nil
@@ -233,13 +234,14 @@ Use the `pp-max-width' variable to control the desired line length."
     (cons (cond
            ((consp (cdr sexp))
             (if (and (length= sexp 2)
-                     (eq (car sexp) 'quote))
+                     (memq (car sexp) '(quote function)))
                 (cond
                  ((symbolp (cadr sexp))
                   (let ((print-quoted t))
                     (prin1 sexp (current-buffer))))
                  ((consp (cadr sexp))
-                  (insert "'")
+                  (insert (if (eq (car sexp) 'quote)
+                              "'" "#'"))
                   (pp--format-list (cadr sexp)
                                    (set-marker (make-marker) (1- (point))))))
               (pp--format-list sexp)))
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
index 2b2001d0964..002a5cf1650 100644
--- a/test/lisp/emacs-lisp/pp-resources/code-formats.erts
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -122,3 +122,9 @@ Name: code-formats11
 (lambda ()
   [(foo bar) (foo bar)])
 =-=-=
+
+Name: code-formats12
+
+=-=
+(global-set-key (kbd "s-x") #'kill-region)
+=-=-=
-- 
cgit v1.2.3


From 6e61f9ec8a2c14699499f597edc6fdc7f4b1f0bd Mon Sep 17 00:00:00 2001
From: Lars Ingebrigtsen <larsi@gnus.org>
Date: Tue, 17 May 2022 19:45:20 +0200
Subject: Fix pp-emacs-lisp-code printing of cons cells

* lisp/emacs-lisp/pp.el (pp--insert-lisp): Fix printing of cons
cells (bug#55478).
---
 lisp/emacs-lisp/pp.el                               |  2 +-
 test/lisp/emacs-lisp/pp-resources/code-formats.erts | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

(limited to 'test/lisp/emacs-lisp/pp-resources')

diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index ad693fa5a61..3c849c2d01b 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -250,7 +250,7 @@ Use the `pp-max-width' variable to control the desired line length."
                                    (set-marker (make-marker) (1- (point))))))
               (pp--format-list sexp)))
            (t
-            (princ sexp (current-buffer)))))
+            (prin1 sexp (current-buffer)))))
     ;; Print some of the smaller integers as characters, perhaps?
     (integer
      (if (<= ?0 sexp ?z)
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
index 002a5cf1650..c3e3023cb19 100644
--- a/test/lisp/emacs-lisp/pp-resources/code-formats.erts
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -128,3 +128,15 @@ Name: code-formats12
 =-=
 (global-set-key (kbd "s-x") #'kill-region)
 =-=-=
+
+Name: code-formats13
+
+=-=
+'("a")
+=-=-=
+
+Name: code-formats14
+
+=-=
+'("a" . "b")
+=-=-=
-- 
cgit v1.2.3