From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id COJTA62lzmP6IwEAbAwnHQ (envelope-from ) for ; Mon, 23 Jan 2023 16:20:13 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id gDeHAq2lzmMhegEAG6o9tA (envelope-from ) for ; Mon, 23 Jan 2023 16:20:13 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 79C6E30FA2 for ; Mon, 23 Jan 2023 16:20:12 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pJyba-0007Kv-5f; Mon, 23 Jan 2023 10:19:30 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pJybY-0007KM-6O for emacs-orgmode@gnu.org; Mon, 23 Jan 2023 10:19:28 -0500 Received: from mout02.posteo.de ([185.67.36.66]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pJybU-0000N2-Lu for emacs-orgmode@gnu.org; Mon, 23 Jan 2023 10:19:27 -0500 Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id 925782404D6 for ; Mon, 23 Jan 2023 16:19:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1674487162; bh=pjPT80xThcs800VNyVJoZohoF4L0pQ+EEvBR1UHisEI=; h=From:To:Subject:Date:From; b=qnr1EvX7U+YNwqb7Vr0WnQtedLjUs6uIG+Oy5xkqWXb3gFZ4GdWpG25jj0mu0f5Jl col3QYxPjcZdA2Y6zda67X3+44SZx2zrBq9+PZ5nzDUmZbaumHhiVew9Zq3boKokX0 TGXG1h9kfGlVNCP4l4GIFcY9uWLjpGG0LHmaXvXW90dHVFn0lpkt2SYKW203RSAzTI 0fZEWlwLBm1SPZjk/ATGHlT1Wles0Vtu09MFtqMKgf8iowHJIa5G7gfzLTo81ZOsDV cRO6skxZdXPmacDQSdRSm4Ao5s2QTCPvoNIqY7ro30S6q4Je4vlwKbGc8+OAm8TMag hOMa/i9xJ74zg== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4P0tzx73DDz9rxN for ; Mon, 23 Jan 2023 16:19:07 +0100 (CET) From: Ihor Radchenko To: emacs-orgmode@gnu.org Subject: [PATCH] Provide a uniform way to inform users about missing third-party packages Date: Mon, 23 Jan 2023 15:19:38 +0000 Message-ID: <87mt69e0s5.fsf@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=185.67.36.66; envelope-from=yantar92@posteo.net; helo=mout02.posteo.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1674487212; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=05OObWid4/kkNRmKE9R3iDanxTkHItRmh5/BQ/3qEoI=; b=Vtj+TUFlqyFs5AZ+mtXeo6ijd6J3INSSrY+DLP9ov2GsJgOAVOi+n6u8kU6o2Q8v67TYua m/YtgbrthcNpsG0JbmWvuXgYZoop8VkH3rSVT6TQDfPKFqD0Dg1638rSIghd1rFMFGSPKa TSv9yzzW2jlECxPOKOCefnZ07lk4OagrVRosiA1fSfVOHMB4YTXqI8SwEwPNZmKR/4tFJu tQUVzakK6sQvDSy7eMtyEJ8Im3OkQ+mBm2GbPuDjX29bEUeTMyuhg9lyl1Jc/bTES5eUoo 84zuagC3V+A/bwj09+hF42OCTN9MU8xI+HCfYaf+BQOo1BCqAAcJB6wOhKBXuw== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=qnr1EvX7; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Seal: i=1; s=key1; d=yhetil.org; t=1674487212; a=rsa-sha256; cv=none; b=EDxbuc2r0xl+X4/IqdEhuiHal07ETK1rORmZn8ez1CEXMeYIgue22NMMWJdxxITU1tIUdZ 80iqa9LdDag6i68K3IBSQ1wSQd1gTwxR7fbd1mYdf6TmofS0H9pJ75n48vstqBjNGvfiEt NFzstjkK/PYP1MYtQlzsMiC7yoXZpoRqDjSOlpKyFxVi+OX3yd2ebCzeTQRGA8k4sMbjbt VROf9/YIJnYdlfc07ulJo5+DZS647KjzwwnC6c1bAOD3VexTpvA7G7azsO19uDYDsrmW65 Xwdu/N+JMd6F6F85GriYzmLyoBfl6nT1/F4IawCnijmHymKodcmEThNdVcYQVA== Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=qnr1EvX7; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -6.05 X-Spam-Score: -6.05 X-Migadu-Queue-Id: 79C6E30FA2 X-Migadu-Scanner: scn1.migadu.com X-TUID: EAgf/fkI9u+K --=-=-= Content-Type: text/plain Hi, In Org code, we have various places where we depend (optionally) on third-party packages. The packages are typically loaded using `require' and report the usual error about missing library if the third-party package is not installed. Such situation is _almost_ OK, except some scenarios when the feature name we in `require' is not the same with the actual package name. Inexperienced users may easily be confused by such errors. In the attached patch, I am introducing a new macro that can be used instead of `require' as the following: (org-require-package 'skewer-repl "skewer-mode") The macro calls `require' and if it fails, displays error/warning saying "`this-command' failed to load required package \"package name\"" It will assist users about the actual third-party package name to be installed. WDYT? While writing a patch, I also noticed `org-cite-csl--barf-without-citeproc' doing similar job. Should we just use the new macro instead? Also, https://github.com/bard/mozrepl ob-js backend is no longer supported. I am wondering if we should remove it. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Provide-a-uniform-way-to-inform-users-about-missing-.patch >From 0140976d32f6fef3c2e2fa181f210dbd026008fe Mon Sep 17 00:00:00 2001 Message-Id: <0140976d32f6fef3c2e2fa181f210dbd026008fe.1674486794.git.yantar92@posteo.net> From: Ihor Radchenko Date: Mon, 23 Jan 2023 18:06:46 +0300 Subject: [PATCH] Provide a uniform way to inform users about missing third-party packages * lisp/org-macs.el (org-require-package): New macro trying to load a library and displaying custom error message or warning on failure. The actual package (not library) name can be provided as optional argument. * lisp/ob-R.el (org-babel-R-initiate-session): * lisp/ob-clojure.el (ob-clojure-eval-with-inf-clojure): (ob-clojure-eval-with-cider): (ob-clojure-eval-with-slime): * lisp/ob-forth.el (org-babel-forth-session-execute): * lisp/ob-gnuplot.el (org-babel-execute:gnuplot): (org-babel-gnuplot-initiate-session): * lisp/ob-haskell.el (org-babel-interpret-haskell): (org-babel-haskell-initiate-session): * lisp/ob-js.el (org-babel-execute:js): (org-babel-js-initiate-session): * lisp/ob-julia.el (org-babel-julia-initiate-session): * lisp/ob-lisp.el (org-babel-execute:lisp): * lisp/ob-ocaml.el (org-babel-prep-session:ocaml): * lisp/ob-octave.el (org-babel-octave-initiate-session): * lisp/ob-processing.el (org-babel-processing-view-sketch): * lisp/ob-ruby.el (org-babel-execute:ruby): (org-babel-ruby-initiate-session): * lisp/ol-bbdb.el (org-bbdb-open): (org-bbdb-complete-link): (org-bbdb-anniv-export-ical): * lisp/org-agenda.el: * lisp/org-plot.el (org-plot/gnuplot): * lisp/org.el: * lisp/ox-ascii.el (org-ascii-table): * lisp/ox-html.el (org-html-htmlize-generate-css): * lisp/ox-org.el: Use the new macro. * lisp/oc-csl.el: Add FIXME. oc-csl uses a custom function doing similar job. * lisp/ob-js.el (org-babel-js-initiate-session): Add FIXME noting that the third-party package is outdated. --- lisp/ob-R.el | 2 +- lisp/ob-clojure.el | 9 +++------ lisp/ob-forth.el | 2 +- lisp/ob-gnuplot.el | 4 ++-- lisp/ob-haskell.el | 4 ++-- lisp/ob-js.el | 10 ++++++---- lisp/ob-julia.el | 3 ++- lisp/ob-lisp.el | 6 +++--- lisp/ob-ocaml.el | 2 +- lisp/ob-octave.el | 6 ++++-- lisp/ob-processing.el | 2 +- lisp/ob-ruby.el | 4 ++-- lisp/oc-csl.el | 1 + lisp/ol-bbdb.el | 8 ++++---- lisp/org-agenda.el | 3 +-- lisp/org-macs.el | 9 +++++++++ lisp/org-plot.el | 2 +- lisp/org.el | 2 +- lisp/ox-ascii.el | 2 +- lisp/ox-html.el | 3 +-- lisp/ox-org.el | 3 +-- 21 files changed, 48 insertions(+), 39 deletions(-) diff --git a/lisp/ob-R.el b/lisp/ob-R.el index 4ee091118..2d22a4657 100644 --- a/lisp/ob-R.el +++ b/lisp/ob-R.el @@ -276,7 +276,7 @@ (defun org-babel-R-initiate-session (session params) (when (get-buffer session) ;; Session buffer exists, but with dead process (set-buffer session)) - (require 'ess) (R) + (org-require-package 'ess "ESS") (R) (let ((R-proc (get-process (or ess-local-process-name ess-current-process-name)))) (while (process-get R-proc 'callbacks) diff --git a/lisp/ob-clojure.el b/lisp/ob-clojure.el index d993e0cb7..5f589db00 100644 --- a/lisp/ob-clojure.el +++ b/lisp/ob-clojure.el @@ -186,8 +186,7 @@ (defvar comint-prompt-regexp) (defvar inf-clojure-comint-prompt-regexp) (defun ob-clojure-eval-with-inf-clojure (expanded params) "Evaluate EXPANDED code block with PARAMS using inf-clojure." - (condition-case nil (require 'inf-clojure) - (user-error "inf-clojure not available")) + (org-require-package 'inf-clojure) ;; Maybe initiate the inf-clojure session (unless (and inf-clojure-buffer (buffer-live-p (get-buffer inf-clojure-buffer))) @@ -228,8 +227,7 @@ (defun ob-clojure-eval-with-inf-clojure (expanded params) (defun ob-clojure-eval-with-cider (expanded params) "Evaluate EXPANDED code block with PARAMS using cider." - (condition-case nil (require 'cider) - (user-error "cider not available")) + (org-require-package 'cider "Cider") (let ((connection (cider-current-connection (cdr (assq :target params)))) (result-params (cdr (assq :result-params params))) result0) @@ -256,8 +254,7 @@ (defun ob-clojure-eval-with-cider (expanded params) (defun ob-clojure-eval-with-slime (expanded params) "Evaluate EXPANDED code block with PARAMS using slime." - (condition-case nil (require 'slime) - (user-error "slime not available")) + (org-require-package 'slime "SLIME") (with-temp-buffer (insert expanded) (slime-eval diff --git a/lisp/ob-forth.el b/lisp/ob-forth.el index e5dcad6d0..bd9ec04a4 100644 --- a/lisp/ob-forth.el +++ b/lisp/ob-forth.el @@ -55,7 +55,7 @@ (defun org-babel-execute:forth (body params) (car (last all-results)))))) (defun org-babel-forth-session-execute (body params) - (require 'forth-mode) + (org-require-package 'forth-mode) (let ((proc (forth-proc)) (rx " \\(\n:\\|compiled\n\\|ok\n\\)") (result-start)) diff --git a/lisp/ob-gnuplot.el b/lisp/ob-gnuplot.el index e3e42918c..79770c7fd 100644 --- a/lisp/ob-gnuplot.el +++ b/lisp/ob-gnuplot.el @@ -198,7 +198,7 @@ (defun org-babel-expand-body:gnuplot (body params) (defun org-babel-execute:gnuplot (body params) "Execute a block of Gnuplot code. This function is called by `org-babel-execute-src-block'." - (require 'gnuplot) + (org-require-package 'gnuplot) (let ((session (cdr (assq :session params))) (result-type (cdr (assq :results params))) (body (org-babel-expand-body:gnuplot body params)) @@ -262,7 +262,7 @@ (defun org-babel-gnuplot-initiate-session (&optional session _params) If there is not a current inferior-process-buffer in SESSION then create one. Return the initialized session. The current `gnuplot-mode' doesn't provide support for multiple sessions." - (require 'gnuplot) + (org-require-package 'gnuplot) (unless (string= session "none") (save-window-excursion (gnuplot-send-string-to-gnuplot "" "line") diff --git a/lisp/ob-haskell.el b/lisp/ob-haskell.el index 7185ed61f..2b1441c2a 100644 --- a/lisp/ob-haskell.el +++ b/lisp/ob-haskell.el @@ -122,7 +122,7 @@ (defun org-babel-haskell-execute (body params) (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))))) (defun org-babel-interpret-haskell (body params) - (require 'inf-haskell) + (org-require-package 'inf-haskell "haskell-mode") (add-hook 'inferior-haskell-hook (lambda () (setq-local comint-prompt-regexp @@ -167,7 +167,7 @@ (defun org-babel-haskell-initiate-session (&optional _session _params) "Initiate a haskell session. If there is not a current inferior-process-buffer in SESSION then create one. Return the initialized session." - (require 'inf-haskell) + (org-require-package 'inf-haskell "haskell-mode") (or (get-buffer "*haskell*") (save-window-excursion (run-haskell) (sleep-for 0.25) (current-buffer)))) diff --git a/lisp/ob-js.el b/lisp/ob-js.el index 910c11686..e19a6e543 100644 --- a/lisp/ob-js.el +++ b/lisp/ob-js.el @@ -96,7 +96,7 @@ (defun org-babel-execute:js (body params) ;; Indium Node REPL. Separate case because Indium ;; REPL is not inherited from Comint mode. ((string= session "*JS REPL*") - (require 'indium-repl) + (org-require-package 'indium-repl "indium") (unless (get-buffer session) (indium-run-node org-babel-js-cmd)) (indium-eval full-body)) @@ -168,7 +168,7 @@ (defun org-babel-js-initiate-session (&optional session _params) ((string= session "none") (warn "Session evaluation of ob-js is not supported")) ((string= "*skewer-repl*" session) - (require 'skewer-repl) + (org-require-package 'skewer-repl "skewer-mode") (let ((session-buffer (get-buffer "*skewer-repl*"))) (if (and session-buffer (org-babel-comint-buffer-livep (get-buffer session-buffer)) @@ -180,7 +180,7 @@ (defun org-babel-js-initiate-session (&optional session _params) (skewer-repl) session-buffer))) ((string= "*Javascript REPL*" session) - (require 'js-comint) + (org-require-package 'js-comint) (let ((session-buffer "*Javascript REPL*")) (if (and (org-babel-comint-buffer-livep (get-buffer session-buffer)) (comint-check-proc session-buffer)) @@ -189,7 +189,9 @@ (defun org-babel-js-initiate-session (&optional session _params) (sit-for .5) session-buffer))) ((string= "mozrepl" org-babel-js-cmd) - (require 'moz) + ;; FIXME: According to https://github.com/bard/mozrepl, this REPL + ;; is outdated and does not work for Firefox >54. + (org-require-package 'moz "mozrepl") (let ((session-buffer (save-window-excursion (run-mozilla nil) (rename-buffer session) diff --git a/lisp/ob-julia.el b/lisp/ob-julia.el index cb5c7fa3b..495169da1 100644 --- a/lisp/ob-julia.el +++ b/lisp/ob-julia.el @@ -196,7 +196,8 @@ (defun org-babel-julia-initiate-session (session params) (when (get-buffer session) ;; Session buffer exists, but with dead process (set-buffer session)) - (require 'ess) (set-buffer (julia)) + (org-require-package 'ess "ESS") + (set-buffer (julia)) (rename-buffer (if (bufferp session) (buffer-name session) diff --git a/lisp/ob-lisp.el b/lisp/ob-lisp.el index 048ef883c..03f23c82d 100644 --- a/lisp/ob-lisp.el +++ b/lisp/ob-lisp.el @@ -90,9 +90,9 @@ (defun org-babel-execute:lisp (body params) "Execute a block of Common Lisp code with Babel. BODY is the contents of the block, as a string. PARAMS is a property list containing the parameters of the block." - (require (pcase org-babel-lisp-eval-fn - (`slime-eval 'slime) - (`sly-eval 'sly))) + (pcase org-babel-lisp-eval-fn + (`slime-eval (org-require-package 'slime "SLIME")) + (`sly-eval (org-require-package 'sly "SLY"))) (org-babel-reassemble-table (let ((result (funcall (if (member "output" (cdr (assq :result-params params))) diff --git a/lisp/ob-ocaml.el b/lisp/ob-ocaml.el index 09224b98b..4ab58e150 100644 --- a/lisp/ob-ocaml.el +++ b/lisp/ob-ocaml.el @@ -109,7 +109,7 @@ (defun org-babel-execute:ocaml (body params) (defvar tuareg-interactive-buffer-name) (defun org-babel-prep-session:ocaml (session _params) "Prepare SESSION according to the header arguments in PARAMS." - (require 'tuareg) + (org-require-package 'tuareg) (let ((tuareg-interactive-buffer-name (if (and (not (string= session "none")) (not (string= session "default")) (stringp session)) diff --git a/lisp/ob-octave.el b/lisp/ob-octave.el index 9bf16b984..64eb2a32a 100644 --- a/lisp/ob-octave.el +++ b/lisp/ob-octave.el @@ -154,8 +154,10 @@ (defun org-babel-octave-initiate-session (&optional session _params matlabp) "Create an octave inferior process buffer. If there is not a current inferior-process-buffer in SESSION then create. Return the initialized session." - (if matlabp (require 'matlab) (or (require 'octave-inf nil 'noerror) - (require 'octave))) + (if matlabp + (org-require-package 'matlab "matlab-mode") + (or (require 'octave-inf nil 'noerror) + (require 'octave))) (unless (string= session "none") (let ((session (or session (if matlabp "*Inferior Matlab*" "*Inferior Octave*")))) diff --git a/lisp/ob-processing.el b/lisp/ob-processing.el index 4eeaf98e0..460e6e381 100644 --- a/lisp/ob-processing.el +++ b/lisp/ob-processing.el @@ -78,7 +78,7 @@ (defvar org-babel-processing-processing-js-filename "processing.js" (defun org-babel-processing-view-sketch () "Show the sketch of the Processing block under point in an external viewer." (interactive) - (require 'processing-mode) + (org-require-package 'processing-mode) (let ((info (org-babel-get-src-block-info))) (if (string= (nth 0 info) "processing") (let* ((body (nth 1 info)) diff --git a/lisp/ob-ruby.el b/lisp/ob-ruby.el index b94bc73dd..ba8697731 100644 --- a/lisp/ob-ruby.el +++ b/lisp/ob-ruby.el @@ -86,7 +86,7 @@ (defun org-babel-execute:ruby (body params) body params (org-babel-variable-assignments:ruby params))) (result (if (member "xmp" result-params) (with-temp-buffer - (require 'rcodetools) + (org-require-package 'rcodetools "rcodetools (gem package)") (insert full-body) (xmp (cdr (assq :xmp-option params))) (buffer-string)) @@ -161,7 +161,7 @@ (defun org-babel-ruby-initiate-session (&optional session params) If there is not a current inferior-process-buffer in SESSION then create one. Return the initialized session." (unless (string= session "none") - (require 'inf-ruby) + (org-require-package 'inf-ruby) (let* ((command (cdr (or (assq :ruby params) (assoc inf-ruby-default-implementation inf-ruby-implementations)))) diff --git a/lisp/oc-csl.el b/lisp/oc-csl.el index 432738a97..94c2ed94c 100644 --- a/lisp/oc-csl.el +++ b/lisp/oc-csl.el @@ -417,6 +417,7 @@ (defconst org-cite-csl--label-regexp ;;; Internal functions +;; FIXME: We use `org-require-package' in other places. (defun org-cite-csl--barf-without-citeproc () "Raise an error if Citeproc library is not loaded." (unless (featurep 'citeproc) diff --git a/lisp/ol-bbdb.el b/lisp/ol-bbdb.el index 47bd9d98c..915d83df2 100644 --- a/lisp/ol-bbdb.el +++ b/lisp/ol-bbdb.el @@ -255,7 +255,7 @@ (defun org-bbdb-export (path desc format _) (defun org-bbdb-open (name _) "Follow a BBDB link to NAME." - (require 'bbdb-com) + (org-require-package 'bbdb-com "bbdb") (let ((inhibit-redisplay (not debug-on-error))) (if (fboundp 'bbdb-name) (org-bbdb-open-old name) @@ -369,7 +369,7 @@ (defun org-bbdb-anniversaries () "Extract anniversaries from BBDB for display in the agenda. When called programmatically, this function expects the `date' variable to be globally bound." - (require 'bbdb) + (org-require-package 'bbdb) (require 'diary-lib) (unless (hash-table-p org-bbdb-anniv-hash) (setq org-bbdb-anniv-hash @@ -500,7 +500,7 @@ (defun org-bbdb-anniversaries-future (&optional n) (defun org-bbdb-complete-link () "Read a bbdb link with name completion." - (require 'bbdb-com) + (org-require-package 'bbdb-com "bbdb") (let ((rec (bbdb-completing-read-record "Name: "))) (concat "bbdb:" (bbdb-record-name (if (listp rec) @@ -509,7 +509,7 @@ (defun org-bbdb-complete-link () (defun org-bbdb-anniv-export-ical () "Extract anniversaries from BBDB and convert them to icalendar format." - (require 'bbdb) + (org-require-package 'bbdb) (require 'diary-lib) (unless (hash-table-p org-bbdb-anniv-hash) (setq org-bbdb-anniv-hash diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el index d2aa8f3f2..3f2b5dcc8 100644 --- a/lisp/org-agenda.el +++ b/lisp/org-agenda.el @@ -3627,8 +3627,7 @@ (defun org-agenda-write (file &optional open nosettings agenda-bufname) (kill-buffer (current-buffer)) (message "Org file written to %s" file))) ((member extension '("html" "htm")) - (or (require 'htmlize nil t) - (error "Please install htmlize from https://github.com/hniksic/emacs-htmlize")) + (org-require-package 'htmlize) (declare-function htmlize-buffer "htmlize" (&optional buffer)) (set-buffer (htmlize-buffer (current-buffer))) (when org-agenda-export-html-style diff --git a/lisp/org-macs.el b/lisp/org-macs.el index cda9c5e03..9083b82f8 100644 --- a/lisp/org-macs.el +++ b/lisp/org-macs.el @@ -107,6 +107,15 @@ (defvar org-fold-core-style) ;;; Macros +(defmacro org-require-package (symbol &optional name noerror) + "Try to load library SYMBOL and display error otherwise. +With optional parameter NAME, use NAME as package name instead of +SYMBOL. Show warning instead of error when NOERROR is non-nil." + `(unless (require ,symbol nil t) + (,(if noerror 'warn 'user-error) + "`%s' failed to load required package \"%s\"" + this-command ,(or name symbol)))) + (defmacro org-with-gensyms (symbols &rest body) (declare (debug (sexp body)) (indent 1)) `(let ,(mapcar (lambda (s) diff --git a/lisp/org-plot.el b/lisp/org-plot.el index fe61e9ace..d39ffc4b4 100644 --- a/lisp/org-plot.el +++ b/lisp/org-plot.el @@ -641,7 +641,7 @@ (defun org-plot/gnuplot (&optional params) If not given options will be taken from the +PLOT line directly before or after the table." (interactive) - (require 'gnuplot) + (org-require-package 'gnuplot) (save-window-excursion (delete-other-windows) (when (get-buffer "*gnuplot*") ; reset *gnuplot* if it already running diff --git a/lisp/org.el b/lisp/org.el index 00674d1fc..958305382 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -15436,7 +15436,7 @@ (define-minor-mode org-cdlatex-mode \\{org-cdlatex-mode-map}" :lighter " OCDL" (when org-cdlatex-mode - (require 'cdlatex) + (org-require-package 'cdlatex) (run-hooks 'cdlatex-mode-hook) (cdlatex-compute-tables)) (unless org-cdlatex-texmathp-advice-is-done diff --git a/lisp/ox-ascii.el b/lisp/ox-ascii.el index 9c4424b14..e5bdf92cb 100644 --- a/lisp/ox-ascii.el +++ b/lisp/ox-ascii.el @@ -1856,7 +1856,7 @@ (defun org-ascii-table (table contents info) (cond ((eq (org-element-property :type table) 'org) contents) ((and (plist-get info :ascii-table-use-ascii-art) (eq (plist-get info :ascii-charset) 'utf-8) - (require 'ascii-art-to-unicode nil t)) + (org-require-package 'ascii-art-to-unicode nil 'noerror)) (with-temp-buffer (insert (org-remove-indentation (org-element-property :value table))) diff --git a/lisp/ox-html.el b/lisp/ox-html.el index 5e58ccba3..37c474409 100644 --- a/lisp/ox-html.el +++ b/lisp/ox-html.el @@ -1823,8 +1823,7 @@ (defun org-html-htmlize-generate-css () to the function `org-html-htmlize-region-for-paste' will produce code that uses these same face definitions." (interactive) - (unless (require 'htmlize nil t) - (error "htmlize library missing. Aborting")) + (org-require-package 'htmlize) (and (get-buffer "*html*") (kill-buffer "*html*")) (with-temp-buffer (let ((fl (face-list)) diff --git a/lisp/ox-org.el b/lisp/ox-org.el index ed72cf4f2..9329eb159 100644 --- a/lisp/ox-org.el +++ b/lisp/ox-org.el @@ -320,8 +320,7 @@ (defun org-org-publish-to-org (plist filename pub-dir) Return output file name." (org-publish-org-to 'org filename ".org" plist pub-dir) (when (plist-get plist :htmlized-source) - (or (require 'htmlize nil t) - (error "Please install htmlize from https://github.com/hniksic/emacs-htmlize")) + (org-require-package 'htmlize) (require 'ox-html) (let* ((org-inhibit-startup t) (htmlize-output-type 'css) -- 2.39.1 --=-=-= Content-Type: text/plain -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at . Support Org development at , or support my work at --=-=-=--