ob-eval.el (6865B)
1 ;;; ob-eval.el --- Babel Functions for External Code Evaluation -*- lexical-binding: t; -*- 2 3 ;; Copyright (C) 2009-2023 Free Software Foundation, Inc. 4 5 ;; Author: Eric Schulte 6 ;; Keywords: literate programming, reproducible research, comint 7 ;; URL: https://orgmode.org 8 9 ;; This file is part of GNU Emacs. 10 11 ;; GNU Emacs is free software: you can redistribute it and/or modify 12 ;; it under the terms of the GNU General Public License as published by 13 ;; the Free Software Foundation, either version 3 of the License, or 14 ;; (at your option) any later version. 15 16 ;; GNU Emacs is distributed in the hope that it will be useful, 17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 ;; GNU General Public License for more details. 20 21 ;; You should have received a copy of the GNU General Public License 22 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. 23 24 ;;; Commentary: 25 26 ;; These functions build existing Emacs support for executing external 27 ;; shell commands. 28 29 ;;; Code: 30 31 (require 'org-macs) 32 (org-assert-version) 33 34 (eval-when-compile (require 'subr-x)) ; For `string-empty-p', Emacs < 29 35 36 (defvar org-babel-error-buffer-name "*Org-Babel Error Output*") 37 (declare-function org-babel-temp-file "ob-core" (prefix &optional suffix)) 38 39 (defun org-babel-eval-error-notify (exit-code stderr) 40 "Open a buffer to display STDERR and a message with the value of EXIT-CODE." 41 (let ((buf (get-buffer-create org-babel-error-buffer-name))) 42 (with-current-buffer buf 43 (goto-char (point-max)) 44 (save-excursion 45 (unless (bolp) (insert "\n")) 46 (insert stderr) 47 (insert (format "[ Babel evaluation exited with code %S ]" exit-code)))) 48 (display-buffer buf)) 49 (message "Babel evaluation exited with code %S" exit-code)) 50 51 (defun org-babel-eval (command query) 52 "Run COMMAND on QUERY. 53 Return standard output produced by COMMAND. If COMMAND exits 54 with a non-zero code or produces error output, show it with 55 `org-babel-eval-error-notify'. 56 57 Writes QUERY into a temp-buffer that is processed with 58 `org-babel--shell-command-on-region'." 59 (let ((error-buffer (get-buffer-create " *Org-Babel Error*")) exit-code) 60 (with-current-buffer error-buffer (erase-buffer)) 61 (with-temp-buffer 62 (insert query) 63 (setq exit-code 64 (org-babel--shell-command-on-region 65 command error-buffer)) 66 (let ((stderr (with-current-buffer error-buffer (buffer-string)))) 67 (if (or (not (numberp exit-code)) 68 (> exit-code 0) 69 (not (string-empty-p stderr))) 70 (progn 71 (org-babel-eval-error-notify exit-code stderr) 72 (save-excursion 73 (when (get-buffer org-babel-error-buffer-name) 74 (with-current-buffer org-babel-error-buffer-name 75 (unless (derived-mode-p 'compilation-mode) 76 (compilation-mode)) 77 ;; Compilation-mode enforces read-only, but 78 ;; Babel expects the buffer modifiable. 79 (setq buffer-read-only nil)))) 80 ;; Return output, if any. 81 (buffer-string)) 82 (buffer-string)))))) 83 84 (defun org-babel-eval-read-file (file) 85 "Return the contents of FILE as a string." 86 (with-temp-buffer (insert-file-contents file) 87 (buffer-string))) 88 89 (defun org-babel--shell-command-on-region (command error-buffer) 90 "Execute COMMAND in an inferior shell with region as input. 91 Stripped down version of `shell-command-on-region' for internal use in 92 Babel only. This lets us work around errors in the original function 93 in various versions of Emacs. This expects the query to be run to be 94 in the current temp buffer. This is written into 95 input-file. ERROR-BUFFER is the name of the file which 96 `org-babel-eval' has created to use for any error messages that are 97 returned." 98 99 (let ((input-file (org-babel-temp-file "ob-input-")) 100 (error-file (if error-buffer (org-babel-temp-file "ob-error-") nil)) 101 (shell-file-name (org-babel--get-shell-file-name)) 102 exit-status) 103 ;; There is an error in `process-file' when `error-file' exists. 104 ;; This is fixed in Emacs trunk as of 2012-12-21; let's use this 105 ;; workaround for now. 106 (unless (file-remote-p default-directory) 107 (delete-file error-file)) 108 ;; we always call this with 'replace, remove conditional 109 ;; Replace specified region with output from command. 110 (org-babel--write-temp-buffer-input-file input-file) 111 (setq exit-status 112 (process-file shell-file-name input-file 113 (if error-file 114 (list t error-file) 115 t) 116 nil shell-command-switch command)) 117 118 (when (and input-file (file-exists-p input-file) 119 ;; bind org-babel--debug-input around the call to keep 120 ;; the temporary input files available for inspection 121 (not (when (boundp 'org-babel--debug-input) 122 org-babel--debug-input))) 123 (delete-file input-file)) 124 125 (when (and error-file (file-exists-p error-file)) 126 (when (< 0 (file-attribute-size (file-attributes error-file))) 127 (with-current-buffer (get-buffer-create error-buffer) 128 (let ((pos-from-end (- (point-max) (point)))) 129 (or (bobp) 130 (insert "\f\n")) 131 ;; Do no formatting while reading error file, 132 ;; because that can run a shell command, and we 133 ;; don't want that to cause an infinite recursion. 134 (format-insert-file error-file nil) 135 ;; Put point after the inserted errors. 136 (goto-char (- (point-max) pos-from-end))) 137 (current-buffer))) 138 (delete-file error-file)) 139 exit-status)) 140 141 (defun org-babel--write-temp-buffer-input-file (input-file) 142 "Write the contents of the current temp buffer into INPUT-FILE." 143 (let ((start (point-min)) 144 (end (point-max))) 145 (goto-char start) 146 (push-mark (point) 'nomsg) 147 (write-region start end input-file) 148 (delete-region start end) 149 (exchange-point-and-mark))) 150 151 (defun org-babel-eval-wipe-error-buffer () 152 "Delete the contents of the Org code block error buffer. 153 This buffer is named by `org-babel-error-buffer-name'." 154 (when (get-buffer org-babel-error-buffer-name) 155 (with-current-buffer org-babel-error-buffer-name 156 (delete-region (point-min) (point-max))))) 157 158 (defun org-babel--get-shell-file-name () 159 "Return system `shell-file-name', defaulting to /bin/sh. 160 Unfortunately, `executable-find' does not support file name 161 handlers. Therefore, we could use it in the local case only." 162 ;; FIXME: Since Emacs 27, `executable-find' accepts optional second 163 ;; argument supporting remote hosts. 164 (cond ((and (not (file-remote-p default-directory)) 165 (executable-find shell-file-name)) 166 shell-file-name) 167 ((file-executable-p 168 (concat (file-remote-p default-directory) shell-file-name)) 169 shell-file-name) 170 ("/bin/sh"))) 171 172 (provide 'ob-eval) 173 174 ;;; ob-eval.el ends here