diff options
author | Lars Ingebrigtsen <larsi@gnus.org> | 2021-11-04 21:44:46 +0100 |
---|---|---|
committer | Lars Ingebrigtsen <larsi@gnus.org> | 2021-11-04 21:44:53 +0100 |
commit | 6cf86ed4c1c7b5a7b74630347de0dfb413d3cd18 (patch) | |
tree | eb86a0a4bd114db63d9e41880386f0a8d0e6e91d /lisp/emacs-lisp/pp.el | |
parent | 4c6afb527bddf9e9f481dd6f6627ffd5407b8803 (diff) | |
download | emacs-6cf86ed4c1c7b5a7b74630347de0dfb413d3cd18.tar.gz emacs-6cf86ed4c1c7b5a7b74630347de0dfb413d3cd18.tar.bz2 emacs-6cf86ed4c1c7b5a7b74630347de0dfb413d3cd18.zip |
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.
Diffstat (limited to 'lisp/emacs-lisp/pp.el')
-rw-r--r-- | lisp/emacs-lisp/pp.el | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el index 4ff2cd59eba..5a643d94e4b 100644 --- a/lisp/emacs-lisp/pp.el +++ b/lisp/emacs-lisp/pp.el @@ -82,6 +82,10 @@ to make output that `read' can handle, whenever this is possible." "Output the pretty-printed representation of OBJECT, any Lisp object. Quoting characters are printed as needed to make output that `read' can handle, whenever this is possible. + +This function does not apply special formatting rules for Emacs +Lisp code. See `pp-emacs-lisp-code' instead. + Output stream is STREAM, or value of `standard-output' (which see)." (princ (pp-to-string object) (or stream standard-output))) @@ -180,6 +184,124 @@ Ignores leading comment characters." (insert (pp-to-string (macroexpand-1 (pp-last-sexp)))) (pp-macroexpand-expression (pp-last-sexp)))) +;;;###autoload +(defun pp-emacs-lisp-code (sexp) + "Insert SEXP into the current buffer, formatted as Emacs Lisp code." + (require 'edebug) + (let ((standard-output (current-buffer))) + (save-restriction + (narrow-to-region (point) (point)) + (pp--insert-lisp sexp) + (insert "\n") + (goto-char (point-min)) + (indent-sexp)))) + +(defun pp--insert-lisp (sexp) + (cl-case (type-of sexp) + (vector (pp--format-vector sexp)) + (cons (cond + ((consp (cdr sexp)) + (if (and (length= sexp 2) + (eq (car sexp) 'quote)) + (let ((print-quoted t)) + (prin1 sexp)) + (pp--format-list sexp))) + (t + (princ sexp)))) + ;; Print some of the smaller integers as characters, perhaps? + (integer + (if (<= ?0 sexp ?z) + (let ((print-integers-as-characters t)) + (princ sexp)) + (princ sexp))) + (string + (let ((print-escape-newlines t)) + (prin1 sexp))) + (otherwise (princ sexp)))) + +(defun pp--format-vector (sexp) + (prin1 sexp)) + +(defun pp--format-list (sexp) + (if (and (symbolp (car sexp)) + (not (keywordp (car sexp)))) + (pp--format-function sexp) + (prin1 sexp))) + +(defun pp--format-function (sexp) + (let* ((sym (car sexp)) + (edebug (get sym 'edebug-form-spec)) + (indent (get sym 'lisp-indent-function))) + (when (eq indent 'defun) + (setq indent 2)) + (pp--insert "(" sym) + (pop sexp) + ;; Get the first entries on the first line. + (if indent + (pp--format-definition sexp indent edebug) + (while sexp + (pp--insert " " (pop sexp)))) + (insert ")"))) + +(defun pp--format-definition (sexp indent edebug) + (while (and (cl-plusp indent) + sexp) + (insert " ") + (if (and (consp (car edebug)) + (eq (caar edebug) '&rest)) + (pp--insert-binding (pop sexp)) + (if (null (car sexp)) + (insert "()") + (pp--insert-lisp (car sexp))) + (pop sexp)) + (pop edebug) + (cl-decf indent)) + (when (stringp (car sexp)) + (insert "\n") + (prin1 (pop sexp))) + ;; Then insert the rest with line breaks before each form. + (while sexp + (insert "\n") + (if (keywordp (car sexp)) + (progn + (pp--insert-lisp (pop sexp)) + (when sexp + (pp--insert " " (pop sexp)))) + (pp--insert-lisp (pop sexp))))) + +(defun pp--insert-binding (sexp) + (insert "(") + (while sexp + (if (consp (car sexp)) + ;; Newlines after each (...) binding. + (progn + (pp--insert-lisp (car sexp)) + (when (cdr sexp) + (insert "\n"))) + ;; Keep plain symbols on the same line. + (pp--insert " " (car sexp))) + (pop sexp)) + (insert ")")) + +(defun pp--insert (delim &rest things) + (let ((start (point))) + (when delim + (insert delim)) + (dolist (thing things) + (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)) + (save-excursion + (goto-char start) + (insert "\n"))))) + +(defun pp--indent-buffer () + (goto-char (point-min)) + (while (not (eobp)) + (lisp-indent-line) + (forward-line 1))) + (provide 'pp) ; so (require 'pp) works ;;; pp.el ends here |