Subject: bug#76103: [PATCH] New function 'process-output'

From: Juri Linkov <[email-masked]>
Date: Fri, 07 Feb 2025 09:29:20 +0200

> I find process-lines super convenient for glueing command line utilities.
>
> Often wished I had a similar function that neither split into lines
> (process-lines) nor relied on shell (shell-command-to-string).
>
> Proposing process-output as a close cousin to process-lines.
>
> Happy to drop process-lines in favour of an existing function I may have
> missed.

Unfortunately, there is no such function for process output.
What is worse there is no similar function even for files.
So everyone have to reimplement the same idiom dozens of times:

  (defun read-file (file)
    "Return FILE content as string."
    (with-temp-buffer
      (insert-file-contents file)
      (buffer-string)))

  (defun read-lines (file)
    "Return a list of lines of FILE."
    (with-temp-buffer
      (insert-file-contents file)
      (split-string (buffer-string) "\n" t)))

For example, there is a complete implementation of read-file
in org-babel-eval-read-file, uudecode-tests-read-file,
eshell-test-file-string.

Also there is a complete implementation of read-lines
in vc--read-lines.

Also this idiom is widely used in comint-exec, eieio-persistent-read,
ert-write-junit-test-summary-report, faceup-test-font-lock-file,
package--get-description, epa-file-insert-file-contents,
erc-load-irc-script, gnus-splash-svg-color-symbols, eww-submit,
tramp-get-lock-file, org-babel-R-evaluate-external-process,
org-babel-R-evaluate-session, ob-session-async-R-value-callback,
org-babel-julia-evaluate-external-process,
org-babel-julia-evaluate-session, org-babel-execute:plantuml,
org-babel-execute:sass, org-babel-screen-test,
org-texinfo-supports-math-p, ps-prologue-file, shell,
vc-cvs-file-to-string, vc-hg--active-bookmark-internal,
erc-tests-common-snapshot-compare em-extpipe-tests--deftest,
em-hist-test/check-history-file, eshell-test-file-string,
files-tests-save-buffer-read-only-file, dbus--test-introspect, url-file,

> +(defun process-output (program &rest args)
> +  "Execute PROGRAM with ARGS, returning its output as a string.
> +Signal an error if the program returns with a non-zero exit status.
> +Also see `process-lines'."
> +  (declare (important-return-value t))
> +  (with-temp-buffer
> +    (let ((status (apply #'call-process program nil (current-buffer) nil args)))
> +      (unless (eq status 0)
> +	(error "%s exited with status %s" program status))
> +      (buffer-string))))

Although process-lines than can be implemented with this as

  (split-string (process-output program args ...) "\n" t)

probably better to not change the existing process-lines-handling-status
since it's not clear whether it's enough to use 'split-string', or to use
'string-lines' like in css-mode-test-selectors and scss-mode-test-selectors.