]> git.eshelyaron.com Git - emacs.git/commitdiff
(json-pretty-print): Rework a bit
authorStefan Monnier <monnier@iro.umontreal.ca>
Wed, 19 Feb 2025 03:27:08 +0000 (22:27 -0500)
committerEshel Yaron <me@eshelyaron.com>
Thu, 20 Feb 2025 21:42:59 +0000 (22:42 +0100)
* lisp/json.el (json-pretty-print): Call 'replace-buffer-contents'
separately for each json object rather than once at the end, so
its work is easier.  Use 'json--print' rather than 'json-encode' so as
to avoid creating yet more temp buffers.

(cherry picked from commit 9143c18ae4752cef8465579dcd713db2032ab045)

lisp/json.el

index a797423a2f831cb5d8bfbd3244eeb94ad8930bfa..6e62e5949105bd713b88f2128f4ced201b910eeb 100644 (file)
@@ -800,58 +800,44 @@ With prefix argument MINIMIZE, minimize it instead."
         (json-object-type 'alist)
         ;; Ensure that keys survive roundtrip (bug#24252, bug#42545).
         (json-key-type 'string)
-        (orig-buf (current-buffer))
-        error)
+        (orig-buf (current-buffer)))
     ;; Strategy: Repeatedly `json-read' from the original buffer and
-    ;; write the pretty-printed snippet to a temporary buffer.  As
-    ;; soon as we get an error from `json-read', simply append the
-    ;; remainder which we couldn't pretty-print to the temporary
-    ;; buffer as well (probably the region ends _inside_ a JSON
-    ;; object).
-    ;;
-    ;; Finally, use `replace-region-contents' to swap the original
+    ;; write the pretty-printed snippet to a temporary buffer.
+    ;; Use `replace-buffer-contents' to swap the original
     ;; region with the contents of the temporary buffer so that point,
     ;; marks, etc. are kept.
+    ;; Stop as soon as we get an error from `json-read'.
     (with-temp-buffer
       (let ((tmp-buf (current-buffer)))
+        ;; This apparently affords decent performance gains in `json--print'.
+        (setq-local inhibit-modification-hooks t)
         (set-buffer orig-buf)
-        (replace-region-contents
-         begin end
-         (lambda ()
-           (let ((pos (point))
-                 (keep-going t))
-             (while keep-going
-               (condition-case err
-                   ;; We want to format only the JSON snippets in the
-                   ;; region without modifying the whitespace between
-                   ;; them.
-                   (let ((space (buffer-substring
-                                 (point)
-                                 (+ (point) (skip-chars-forward " \t\n"))))
-                         (json (json-read)))
-                     (setq pos (point)) ; End of last good json-read.
-                     (set-buffer tmp-buf)
-                     (insert space (json-encode json))
-                     (set-buffer orig-buf))
-                 (t
-                  (setq keep-going nil)
-                  (set-buffer orig-buf)
-                  ;; Rescue the remainder we couldn't pretty-print.
-                  (append-to-buffer tmp-buf pos (point-max))
-                  ;; EOF is expected because we json-read until we hit
-                  ;; the end of the narrow region.
-                  (unless (eq (car err) 'json-end-of-file)
-                    (setq error err)))))
-             tmp-buf))
-         json-pretty-print-max-secs
-         ;; FIXME: What's a good value here?  Can we use something better,
-         ;; e.g., by deriving a value from the size of the region?
-         64)))
-    ;; If we got an error during JSON processing (possibly the region
-    ;; starts or ends inside a JSON object), signal it to the user.
-    ;; We did our best.
-    (when error
-      (signal (car error) (cdr error)))))
+        (save-excursion
+          (save-restriction
+            (narrow-to-region begin end)
+            (goto-char begin)
+            (while
+                (progn
+                  (skip-chars-forward " \t\n")
+                  (condition-case nil
+                      (let ((beg (point))
+                            (json (json-read))
+                            (standard-output tmp-buf))
+                        (with-current-buffer tmp-buf
+                          (erase-buffer) (json--print json))
+                        (save-restriction
+                          (narrow-to-region beg (point))
+                          (replace-buffer-contents
+                           tmp-buf
+                           json-pretty-print-max-secs
+                           ;; FIXME: What's a good value here?  Can we use
+                           ;; something better, e.g., by deriving a value
+                           ;; from the size of the region?
+                           64)
+                        'keep-going))
+                    ;; EOF is expected because we json-read until we hit
+                    ;; the end of the narrow region.
+                    (json-end-of-file nil))))))))))
 
 (defun json-pretty-print-buffer-ordered (&optional minimize)
   "Pretty-print current buffer with object keys ordered.