* Useful package? Compat.el @ 2021-10-11 10:36 Timothy 2021-10-11 14:28 ` Russell Adams 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko 0 siblings, 2 replies; 36+ messages in thread From: Timothy @ 2021-10-11 10:36 UTC (permalink / raw) To: Org-mode [-- Attachment #1.1: Type: text/plain, Size: 408 bytes --] Hi, I’ve recently come across an interesting looking library available on ELPA, <https://git.sr.ht/~pkal/compat>. I’m thinking in future this could allow us to both use newer features and also support older versions of Emacs, e.g. Org 10.X is developed for Emacs 28.1 and newer, but supports Emacs 24.3 and newer with compat.el. Just tossing this out as an idea :) All the best, Timothy [-- Attachment #1.2: Type: text/html, Size: 2920 bytes --] ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Useful package? Compat.el 2021-10-11 10:36 Useful package? Compat.el Timothy @ 2021-10-11 14:28 ` Russell Adams 2021-10-11 14:40 ` Timothy 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko 1 sibling, 1 reply; 36+ messages in thread From: Russell Adams @ 2021-10-11 14:28 UTC (permalink / raw) To: emacs-orgmode On Mon, Oct 11, 2021 at 06:36:50PM +0800, Timothy wrote: > I’ve recently come across an interesting looking library available on ELPA, > <https://git.sr.ht/~pkal/compat>. I’m thinking in future this could allow us to > both use newer features and also support older versions of Emacs, e.g. > > Org 10.X is developed for Emacs 28.1 and newer, but supports Emacs 24.3 and > newer with compat.el. That's interesting, using a library to wrap new Emacs functionality and implement a common replacement instead of custom work-arounds in local code. Do you have any examples of where this could shorten code in Org? I believe it's a tall order to add a dependency, but if it eliminates large chunks of backward compatibility code then maybe that's something to consider. Thanks. ------------------------------------------------------------------ Russell Adams RLAdams@AdamsInfoServ.com PGP Key ID: 0x1160DCB3 http://www.adamsinfoserv.com/ Fingerprint: 1723 D8CA 4280 1EC9 557F 66E8 1154 E018 1160 DCB3 ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Useful package? Compat.el 2021-10-11 14:28 ` Russell Adams @ 2021-10-11 14:40 ` Timothy 2021-10-11 18:04 ` Joost Kremers 0 siblings, 1 reply; 36+ messages in thread From: Timothy @ 2021-10-11 14:40 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 1072 bytes --] Hi Russel, > Do you have any examples of where this could shorten code in Org? I don’t have any examples on hand, but Org is already rolling some compat code for old Emacs versions, and we’ve had issues where people have accidentally used functions which are “too new” (but a few years old, and so nobody picked it up till someone raised an issue). I can also personally recall times when I’ve had to refactor code to make it uglier and more verbose to avoid using newer functions. All of this is why I’m thinking this could be an interesting idea. > I believe it’s a tall order to add a dependency, but if it eliminates > large chunks of backward compatibility code then maybe that’s > something to consider. I think the way to do this would be as a “soft” dependency, i.e. not needed for anyone running a recent version of Emacs, but needed if you want to use Org with an old version of Emacs. Not sure how this would best be done, but if this were to be useful, this is how I’d imagine it working. All the best, Timothy ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Useful package? Compat.el 2021-10-11 14:40 ` Timothy @ 2021-10-11 18:04 ` Joost Kremers 0 siblings, 0 replies; 36+ messages in thread From: Joost Kremers @ 2021-10-11 18:04 UTC (permalink / raw) To: Timothy; +Cc: emacs-orgmode On Mon, Oct 11 2021, Timothy wrote: > I think the way to do this would be as a “soft” dependency, i.e. not needed for > anyone running a recent version of Emacs, but needed if you want to use Org with > an old version of Emacs. Not sure how this would best be done, but if this were > to be useful, this is how I’d imagine it working. IIUC you can simply specify a dependency on `compat` and the package itself will make sure only the necessary compatibility functions are loaded given the Emacs version it's running in. So if you're running Emacs 28, nothing is loaded; if you're running Emacs 27, `compat-28.1` is loaded to ensure packages written for Emacs 28 can still be used; if you're running Emacs 26, both `compat-27.1` and `compat-28.1` are loaded, etc. -- Joost Kremers Life has its moments ^ permalink raw reply [flat|nested] 36+ messages in thread
* [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2021-10-11 10:36 Useful package? Compat.el Timothy 2021-10-11 14:28 ` Russell Adams @ 2023-01-27 13:23 ` Ihor Radchenko 2023-01-27 13:34 ` [POLL] Use compat.el in Org? Bastien Guerry ` (3 more replies) 1 sibling, 4 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-01-27 13:23 UTC (permalink / raw) To: Timothy, Bastien, Kyle Meyer; +Cc: Org-mode, Daniel Mendler Timothy <tecosaur@gmail.com> writes: > I’ve recently come across an interesting looking library available on ELPA, > <https://git.sr.ht/~pkal/compat>. I’m thinking in future this could allow us to > both use newer features and also support older versions of Emacs, e.g. > > Org 10.X is developed for Emacs 28.1 and newer, but supports Emacs 24.3 and > newer with compat.el. > > Just tossing this out as an idea :) I have recently been contacted by the current compat.el maintainer asking if we are willing to adapt compat.el in Org. Pros: 1. We will have less headache maintaining org-compat.el. 2. We will get an ability to use functions and macros from newer Emacs versions almost for free. Cons: 1. If compat.el happens to lack support of some function, we will need to contribute to compat.el directly and synchronize Org releases with compat.el releases. WDYT? -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko @ 2023-01-27 13:34 ` Bastien Guerry 2023-01-27 20:38 ` Tim Cross 2023-01-28 16:04 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Kyle Meyer ` (2 subsequent siblings) 3 siblings, 1 reply; 36+ messages in thread From: Bastien Guerry @ 2023-01-27 13:34 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Timothy, Kyle Meyer, Org-mode, Daniel Mendler Hi Ihor, Ihor Radchenko <yantar92@posteo.net> writes: > I have recently been contacted by the current compat.el maintainer > asking if we are willing to adapt compat.el in Org. Very nice! > WDYT? As long as we keep our promise in terms of backward compatibility with older Emacs versions, I'm all for it. -- Bastien ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? 2023-01-27 13:34 ` [POLL] Use compat.el in Org? Bastien Guerry @ 2023-01-27 20:38 ` Tim Cross 2023-01-27 21:38 ` Daniel Mendler 0 siblings, 1 reply; 36+ messages in thread From: Tim Cross @ 2023-01-27 20:38 UTC (permalink / raw) To: Bastien Guerry Cc: Ihor Radchenko, Timothy, Kyle Meyer, Daniel Mendler, emacs-orgmode Bastien Guerry <bzg@gnu.org> writes: > Hi Ihor, > > Ihor Radchenko <yantar92@posteo.net> writes: > >> I have recently been contacted by the current compat.el maintainer >> asking if we are willing to adapt compat.el in Org. > > Very nice! > >> WDYT? > > As long as we keep our promise in terms of backward compatibility with > older Emacs versions, I'm all for it. I would agree. I would also add that even with the use of this package, I don't think we should use it to increase the number of versions we support as support is not as simple as dropping in a compatibility library. These libraries come with a cost. Often, compatibility code does not perform as well and/or is much more complicated and more likely to have bugs. The more a version of emacs needs to rely on this library to run org-mode, the higher the likelihood performance will be degraded or unexpected new bugs are found. So, use the library, but keep the existing policy of officially supporting only the previous two major releases. If org does work with even older versions, that is great, but not supported. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? 2023-01-27 20:38 ` Tim Cross @ 2023-01-27 21:38 ` Daniel Mendler 2023-01-27 22:29 ` Samuel Wales 0 siblings, 1 reply; 36+ messages in thread From: Daniel Mendler @ 2023-01-27 21:38 UTC (permalink / raw) To: Tim Cross, Bastien Guerry Cc: Ihor Radchenko, Timothy, Kyle Meyer, emacs-orgmode On 1/27/23 21:38, Tim Cross wrote: >> As long as we keep our promise in terms of backward compatibility with >> older Emacs versions, I'm all for it. > > I would agree. I would also add that even with the use of this package, > I don't think we should use it to increase the number of versions we > support as support is not as simple as dropping in a compatibility > library. True. The Compat package cannot fix bugs below the Elisp level or provide APIs which cannot be backported, e.g., big integer support. If Org relies on behavior of the Emacs display engine or the C core of a certain Emacs version, Compat cannot help. The advantage would be that the maintenance burden of org-compat would be reduced. Many packages can share the backported functions by depending on Compat, which will increase robustness and reduce the risk of unexpected bugs. The community only has to maintain a single set of backported functions in a single package, instead of scattering compatibility code across many packages. > These libraries come with a cost. Often, compatibility code > does not perform as well and/or is much more complicated and more likely > to have bugs. The more a version of emacs needs to rely on this library > to run org-mode, the higher the likelihood performance will be degraded > or unexpected new bugs are found. To give some context about the stability aspect - many backported compatibility functions are copied verbatim from newer Emacs versions. Every compatibility function provided by Compat is covered by tests, which are executed via CI on all supported Emacs versions (>= 24.4). I make sure that no functions are backported which perform much worse such that they would introduce performance bugs. Daniel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? 2023-01-27 21:38 ` Daniel Mendler @ 2023-01-27 22:29 ` Samuel Wales 0 siblings, 0 replies; 36+ messages in thread From: Samuel Wales @ 2023-01-27 22:29 UTC (permalink / raw) To: Daniel Mendler Cc: Tim Cross, Bastien Guerry, Ihor Radchenko, Timothy, Kyle Meyer, emacs-orgmode what daniel said sgtm On 1/27/23, Daniel Mendler <mail@daniel-mendler.de> wrote: > On 1/27/23 21:38, Tim Cross wrote: >>> As long as we keep our promise in terms of backward compatibility with >>> older Emacs versions, I'm all for it. >> >> I would agree. I would also add that even with the use of this package, >> I don't think we should use it to increase the number of versions we >> support as support is not as simple as dropping in a compatibility >> library. > > True. The Compat package cannot fix bugs below the Elisp level or > provide APIs which cannot be backported, e.g., big integer support. If > Org relies on behavior of the Emacs display engine or the C core of a > certain Emacs version, Compat cannot help. > > The advantage would be that the maintenance burden of org-compat would > be reduced. Many packages can share the backported functions by > depending on Compat, which will increase robustness and reduce the risk > of unexpected bugs. The community only has to maintain a single set of > backported functions in a single package, instead of scattering > compatibility code across many packages. > >> These libraries come with a cost. Often, compatibility code >> does not perform as well and/or is much more complicated and more likely >> to have bugs. The more a version of emacs needs to rely on this library >> to run org-mode, the higher the likelihood performance will be degraded >> or unexpected new bugs are found. > > To give some context about the stability aspect - many backported > compatibility functions are copied verbatim from newer Emacs versions. > Every compatibility function provided by Compat is covered by tests, > which are executed via CI on all supported Emacs versions (>= 24.4). I > make sure that no functions are backported which perform much worse such > that they would introduce performance bugs. > > Daniel > > -- The Kafka Pandemic A blog about science, health, human rights, and misopathy: https://thekafkapandemic.blogspot.com ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko 2023-01-27 13:34 ` [POLL] Use compat.el in Org? Bastien Guerry @ 2023-01-28 16:04 ` Kyle Meyer 2023-01-30 11:35 ` Greg Minshall 2023-04-01 10:31 ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko 3 siblings, 0 replies; 36+ messages in thread From: Kyle Meyer @ 2023-01-28 16:04 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Timothy, Bastien, Org-mode, Daniel Mendler Ihor Radchenko writes: > I have recently been contacted by the current compat.el maintainer > asking if we are willing to adapt compat.el in Org. I'm in favor of Org using Compat. And grepping around emacs.git, there are already two bundled packages (erc and python) with (require 'compat nil 'noerror) so I don't expect there would be objections/questions from the Emacs side. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko 2023-01-27 13:34 ` [POLL] Use compat.el in Org? Bastien Guerry 2023-01-28 16:04 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Kyle Meyer @ 2023-01-30 11:35 ` Greg Minshall 2023-01-30 19:33 ` Ihor Radchenko 2023-04-01 10:31 ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko 3 siblings, 1 reply; 36+ messages in thread From: Greg Minshall @ 2023-01-30 11:35 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Timothy, Bastien, Kyle Meyer, Org-mode, Daniel Mendler Ihor, > Cons: > > 1. If compat.el happens to lack support of some function, we will need > to contribute to compat.el directly and synchronize Org releases with > compat.el releases. would a separate "org-compat.el" (in addition to compat.el) somehow solve this? (i worry about the synch'ing.) cheers, Greg ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2023-01-30 11:35 ` Greg Minshall @ 2023-01-30 19:33 ` Ihor Radchenko 2023-01-30 19:40 ` Greg Minshall 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-01-30 19:33 UTC (permalink / raw) To: Greg Minshall; +Cc: Timothy, Bastien, Kyle Meyer, Org-mode, Daniel Mendler Greg Minshall <minshall@umich.edu> writes: >> 1. If compat.el happens to lack support of some function, we will need >> to contribute to compat.el directly and synchronize Org releases with >> compat.el releases. > > would a separate "org-compat.el" (in addition to compat.el) somehow > solve this? (i worry about the synch'ing.) That's what we already do. Using compat.el means that we can remove some of the functions from org-compat.el and instead rely on compat.el where the same functions are maintained more carefully. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2023-01-30 19:33 ` Ihor Radchenko @ 2023-01-30 19:40 ` Greg Minshall 2023-01-30 21:38 ` Daniel Mendler 0 siblings, 1 reply; 36+ messages in thread From: Greg Minshall @ 2023-01-30 19:40 UTC (permalink / raw) To: Ihor Radchenko; +Cc: Timothy, Bastien, Kyle Meyer, Org-mode, Daniel Mendler Ihor, > >> 1. If compat.el happens to lack support of some function, we will need > >> to contribute to compat.el directly and synchronize Org releases with > >> compat.el releases. > > > > would a separate "org-compat.el" (in addition to compat.el) somehow > > solve this? (i worry about the synch'ing.) > > That's what we already do. > Using compat.el means that we can remove some of the functions from > org-compat.el and instead rely on compat.el where the same functions are > maintained more carefully. i see, yes. i'm just thinking that, for a given release CUR (like i know anything about org-mode release procedures!) we would use whatever has been available in compat.el since release CUR-n (for whatever n we use -- 2?), and supplement that, in org-compat.el, with whatever other compatibility features *we* (org-mode) need to support releases [CUR-n .. CUR]. (and, presumably, contribute whatever might be appropriate from org-compat.el to compat.el, so we can prune it out from org-compat.el at some future point in time.) i'm *only* thinking of trying to de-couple org-mode development from that of compat.el, in the mindset that "less cross-dependencies" == "less complication". if that makes sense. cheers, Greg ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [POLL] Use compat.el in Org? (was: Useful package? Compat.el) 2023-01-30 19:40 ` Greg Minshall @ 2023-01-30 21:38 ` Daniel Mendler 0 siblings, 0 replies; 36+ messages in thread From: Daniel Mendler @ 2023-01-30 21:38 UTC (permalink / raw) To: Greg Minshall, Ihor Radchenko; +Cc: Timothy, Bastien, Kyle Meyer, Org-mode On 1/30/23 20:40, Greg Minshall wrote: > i see, yes. i'm just thinking that, for a given release CUR (like i > know anything about org-mode release procedures!) we would use whatever > has been available in compat.el since release CUR-n (for whatever n we > use -- 2?), and supplement that, in org-compat.el, with whatever other > compatibility features *we* (org-mode) need to support releases [CUR-n > .. CUR]. > > (and, presumably, contribute whatever might be appropriate from > org-compat.el to compat.el, so we can prune it out from org-compat.el at > some future point in time.) Sounds good. But note that Compat will at some point have sufficient coverage of the existing APIs, such that Org may not miss anything. From then on new additions will only be made at the time of a new Emacs release. The current Compat already supports many Emacs 29 APIs, which is in time for the upcoming pretest. Compat won't add any APIs which are still part of the unstable development master branch (before the branch cut and feature freeze), which reduces the need for coordination. If you are missing something right now, and want to introduce and use a new backported function, e.g., something new from Emacs 29, instead of going via the org-compat indirection, you could also make an addition directly to Compat, a Compat release can be prepared a short while after, and then you start using the new function in the Org development version. Daniel ^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko ` (2 preceding siblings ...) 2023-01-30 11:35 ` Greg Minshall @ 2023-04-01 10:31 ` Ihor Radchenko 2023-04-01 11:38 ` Daniel Mendler 2023-04-02 16:37 ` Max Nikulin 3 siblings, 2 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-04-01 10:31 UTC (permalink / raw) To: Timothy; +Cc: Bastien, Kyle Meyer, Org-mode, Daniel Mendler [-- Attachment #1: Type: text/plain, Size: 713 bytes --] Ihor Radchenko <yantar92@posteo.net> writes: > I have recently been contacted by the current compat.el maintainer > asking if we are willing to adapt compat.el in Org. See the attached patch set adding support of compat.el. I had to update Org's build system to handle third-party packages. Please, give it a close check (first patch). The second patch adds the actual Elisp part and replaces some compatibility functions with what is provided by compat.el. Note that not all the functions are available in compat.el for now. Daniel, you might want to take a look. The last patch adds the necessary explanation for users who install Org from git. Now, they must install compat.el manually to make Org work. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Upgrade-Org-build-system-to-handle-third-party-depen.patch --] [-- Type: text/x-patch, Size: 6315 bytes --] From f95433f53878e8371bb28a045fdb5d06cf0877b9 Mon Sep 17 00:00:00 2001 Message-Id: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH 1/3] Upgrade Org build system to handle third-party dependencies * mk/default.mk (pkgdir): New variable holding the location of third-party packages to be downloaded if necessary during compilation. (EFLAGS): New variable holding extra flags to be passed to Emacs executable when running make. (EPACKAGES): List of packages to be installed (unless already present in the `load-path') during compilation. (package-install): (INSTALL_PACKAGES): New command to download and install missing packages. (BATCH): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (check test): (compile compile-dirty): Use the new uppkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_BASE): (CONF_DEST): (CONF_CALL): Update according to the new variables and targets. * .gitignore: Ignore the downloaded packages. This commit paves the way towards third-party built-time dependencies for Org. In particular, towards including compat.el dependency. According to EPACKAGES, we can auto-download necessary packages, unless they are manually specified via -L switches in EFLAGS. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 1 + mk/default.mk | 24 +++++++++++++++++++++++- mk/targets.mk | 24 ++++++++++++++++-------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 4bb81c359..a58670c90 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ t auto tmp TODO +/pkg-deps # and collateral damage from Emacs diff --git a/mk/default.mk b/mk/default.mk index fa46661e8..997b22b66 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -31,6 +31,15 @@ GIT_BRANCH = TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest +# Where to store Org dependencies +pkgdir = $(shell pwd)/pkg-deps + +# Extra flags to be passed to Emacs +EFLAGS ?= + +# Third-party packages to install when running make +EPACKAGES ?= + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -72,12 +81,22 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' +package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ --eval '(add-to-list '"'"'load-path (concat default-directory "testing"))' BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST) +ifeq (,$(EPACKAGES)) +INSTALL_PACKAGES = +else +INSTALL_PACKAGES = \ + $(BATCH) \ + --eval '(package-refresh-contents)' \ + $(foreach package,$(EPACKAGES),$(package-install)) +endif + BTEST = $(BATCH) $(BTEST_INIT) \ -l org-batch-test-init \ --eval '(setq \ @@ -120,7 +139,10 @@ EMACSQ = $(EMACS) -Q # Using emacs in batch mode. BATCH = $(EMACSQ) -batch \ - --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' + $(EFLAGS) \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)' # Emacs must be started in toplevel directory BATCHO = $(BATCH) \ diff --git a/mk/targets.mk b/mk/targets.mk index 0bd293d68..ab8b830bb 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \ check test install $(INSTSUB) \ info html pdf card refcard doc docs \ autoloads cleanall clean $(CLEANDIRS:%=clean%) \ clean-install cleanelc cleandirs \ - cleanlisp cleandoc cleandocs cleantest \ + cleanlisp cleandoc cleandocs cleantest cleanpkg \ compile compile-dirty uncompiled \ config config-test config-exe config-all config-eol config-version \ vanilla repro -CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC -CONF_DEST = lispdir infodir datadir testdir +CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES +CONF_DEST = lispdir infodir datadir testdir pkgdir CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO -CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION +CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION config-eol:: EOL = \# config-eol:: config-all config config-all:: @@ -86,7 +86,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: uppkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -94,7 +94,7 @@ all clean-install:: vanilla: -@$(NOBATCH) & -check test:: compile +check test:: uppkg compile check test test-dirty:: -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) @@ -102,6 +102,11 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f $(MAKE) cleantest endif +uppkg:: + -$(MKDIR) -p $(pkgdir) + -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + + $(INSTALL_PACKAGES) + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -134,7 +139,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest +cleanall: cleandirs cleantest cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -159,3 +164,6 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: + -$(RMR) $(pkgdir) -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Use-compat.el-library-instead-of-ad-hoc-compatibilit.patch --] [-- Type: text/x-patch, Size: 34712 bytes --] From 6c4c71426c15b6307cecc1ebffc75dbd6d5135b4 Mon Sep 17 00:00:00 2001 Message-Id: <6c4c71426c15b6307cecc1ebffc75dbd6d5135b4.1680344979.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:10:13 +0200 Subject: [PATCH 2/3] Use compat.el library instead of ad-hoc compatibility function set * mk/default.mk (EPACKAGES): Demand compat library during compile time. * lisp/org.el: Add compat dependency. (org-fill-paragraph): * lisp/org-compat.el: Implement compat.el compatibility layer. Obsolete org-* compatibility functions that are already available in compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case', `org-file-name-concat', `org-directory-empty-p', `org-string-clean-whitespace', `org-format-prompt', `org-xor', `org-string-distance', `org-buffer-hash'. * lisp/ob-core.el (org-babel-results-keyword): Use functions provided by compat.el. (org-babel-insert-result): * lisp/oc-basic.el (org-cite-basic--parse-bibliography): * lisp/oc.el (org-cite-adjust-note): * lisp/ol-gnus.el (org-gnus-group-link): (org-gnus-article-link): (org-gnus-store-link): * lisp/ol.el: (org-store-link): * lisp/org-attach.el: * lisp/org-capture.el: (org-capture-fill-template): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el: * lisp/org-persist.el (org-persist-directory): (org-persist-read:file): (org-persist-read:url): (org-persist--load-index): (org-persist-write:file): (org-persist-write:index): (org-persist--merge-index-with-disk): (org-persist-read): (org-persist-write): (org-persist-write-all): (org-persist--gc-persist-file): (org-persist-gc): * lisp/org-refile.el (org-refile-get-location): * lisp/ox.el (org-export-resolve-radio-link): * testing/lisp/test-ol.el (test-org-link/toggle-link-display): * testing/lisp/test-org-capture.el (test-org-capture/abort): Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- lisp/ob-core.el | 8 +- lisp/oc-basic.el | 4 +- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +- lisp/ol.el | 4 +- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +- lisp/org-compat.el | 220 +++++++++---------------------- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-persist.el | 38 +++--- lisp/org-refile.el | 2 +- lisp/org.el | 6 +- lisp/ox.el | 6 +- mk/default.mk | 2 +- testing/lisp/test-ol.el | 10 +- testing/lisp/test-org-capture.el | 2 +- 17 files changed, 115 insertions(+), 211 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 471887a3a..65d9fdc72 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS" :type 'string :safe (lambda (v) (and (stringp v) - (org-string-equal-ignore-case "RESULTS" v)))) + (string-equal-ignore-case "RESULTS" v)))) (defcustom org-babel-noweb-wrap-start "<<" "String used to begin a noweb reference in a code block. @@ -2518,7 +2518,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex ;; Escape contents from "export" wrap. Wrap ;; inline results within an export snippet with ;; appropriate value. - ((org-string-equal-ignore-case type "export") + ((string-equal-ignore-case type "export") (let ((backend (pcase split (`(,_) "none") (`(,_ ,b . ,_) b)))) @@ -2529,14 +2529,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex backend) "@@)}}}"))) ;; Escape contents from "example" wrap. Mark ;; inline results as verbatim. - ((org-string-equal-ignore-case type "example") + ((string-equal-ignore-case type "example") (funcall wrap opening-line closing-line nil nil "{{{results(=" "=)}}}")) ;; Escape contents from "src" wrap. Mark ;; inline results as inline source code. - ((org-string-equal-ignore-case type "src") + ((string-equal-ignore-case type "src") (let ((inline-open (pcase split (`(,_) diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index 12b627e71..eee354f26 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info) (dolist (file (org-cite-list-bibliography-files)) (when (file-readable-p file) (with-temp-buffer - (when (or (org-file-has-changed-p file) + (when (or (file-has-changed-p file) (not (gethash file org-cite-basic--file-id-cache))) (insert-file-contents file) (set-visited-file-name file t) - (puthash file (org-buffer-hash) org-cite-basic--file-id-cache)) + (puthash file (buffer-hash) org-cite-basic--file-id-cache)) (condition-case nil (unwind-protect (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache))) diff --git a/lisp/oc.el b/lisp/oc.el index dde6f3a32..f39ae848b 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct) (match-string 3 previous))))) ;; Bail you when there is no quote and either no punctuation, or ;; punctuation on both sides. - (when (or quote (org-xor punct final-punct)) + (when (or quote (xor punct final-punct)) ;; Phase 1: handle punctuation rule. (pcase rule ((guard (not quote)) nil) diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el index 7c07ce045..e121cfba3 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -98,8 +98,8 @@ (defun org-gnus-group-link (group) `org-gnus-prefer-web-links' is reversed." (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group))) (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups - (org-xor current-prefix-arg - org-gnus-prefer-web-links)) + (xor current-prefix-arg + org-gnus-prefer-web-links)) (concat "https://groups.google.com/group/" unprefixed-group) (concat "gnus:" group)))) @@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive) If `org-store-link' was called with a prefix arg the meaning of `org-gnus-prefer-web-links' is reversed." - (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links) + (if (and (xor current-prefix-arg org-gnus-prefer-web-links) newsgroups ;make web links only for nntp groups (not x-no-archive)) ;and if X-No-Archive isn't set (format "https://groups.google.com/groups/search?as_umsgid=%s" @@ -169,7 +169,7 @@ (defun org-gnus-store-link () newsgroups x-no-archive) ;; Fetching an article is an expensive operation; newsgroup and ;; x-no-archive are only needed for web links. - (when (org-xor current-prefix-arg org-gnus-prefer-web-links) + (when (xor current-prefix-arg org-gnus-prefer-web-links) ;; Make sure the original article buffer is up-to-date. (save-window-excursion (gnus-summary-select-article)) (setq to (or to (gnus-fetch-original-field "To"))) diff --git a/lisp/ol.el b/lisp/ol.el index 9e4781f6e..3d62a6fa0 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let* ((element (org-element-at-point)) (name (org-element-property :name element)) (context @@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let ((context (org-link--normalize-string (or (org-link--context-from-region) (org-current-line-string)) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 8d01eda71..5cc40873c 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -674,7 +674,7 @@ (defun org-attach-sync () (let ((files (org-attach-file-list attach-dir))) (org-attach-tag (not files))) (when org-attach-sync-delete-empty-dir - (when (and (org-directory-empty-p attach-dir) + (when (and (directory-empty-p attach-dir) (if (eq 'query org-attach-sync-delete-empty-dir) (yes-or-no-p "Attachment directory is empty. Delete?") t)) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index b96e9f336..c5b1c6d50 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1323,9 +1323,9 @@ (defun org-capture-place-item () ;; prioritize the existing list. (when prepend? (let ((ordered? (eq 'ordered (org-element-property :type item)))) - (when (org-xor ordered? - (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" - template)) + (when (xor ordered? + (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" + template)) (org-cycle-list-bullet (if ordered? "1." "-"))))) ;; Eventually repair the list for proper indentation and ;; bullets. @@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation) (setq org-capture--prompt-history (gethash prompt org-capture--prompt-history-table)) (push (org-completing-read - (org-format-prompt (or prompt "Enter string") default) + (format-prompt (or prompt "Enter string") default) completions nil nil nil 'org-capture--prompt-history default) strings) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index c47a4e8c2..046a3db97 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec)) (declare-function org-fold-show-all "org-fold" (&optional types)) (declare-function org-fold-show-children "org-fold" (&optional level)) (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers)) -;; `org-string-equal-ignore-case' is in _this_ file but isn't at the -;; top-level. -(declare-function org-string-equal-ignore-case "org-compat" (string1 string2)) (defvar calendar-mode-map) (defvar org-complex-heading-regexp) @@ -95,104 +92,67 @@ (defvar org-table1-hline-regexp) (defvar org-fold-core-style) \f -;;; Emacs < 29 compatibility - -(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal) - "Internal variable used by `org-file-has-changed-p'.") - -(if (fboundp 'file-has-changed-p) - (defalias 'org-file-has-changed-p #'file-has-changed-p) - (defun org-file-has-changed-p (file &optional tag) - "Return non-nil if FILE has changed. -The size and modification time of FILE are compared to the size -and modification time of the same FILE during a previous -invocation of `org-file-has-changed-p'. Thus, the first invocation -of `org-file-has-changed-p' always returns non-nil when FILE exists. -The optional argument TAG, which must be a symbol, can be used to -limit the comparison to invocations with identical tags; it can be -the symbol of the calling function, for example." - (let* ((file (directory-file-name (expand-file-name file))) - (remote-file-name-inhibit-cache t) - (fileattr (file-attributes file 'integer)) - (attr (and fileattr - (cons (file-attribute-size fileattr) - (file-attribute-modification-time fileattr)))) - (sym (concat (symbol-name tag) "@" file)) - (cachedattr (gethash sym org-file-has-changed-p--hash-table))) - (when (not (equal attr cachedattr)) - (puthash sym attr org-file-has-changed-p--hash-table))))) - -(if (fboundp 'string-equal-ignore-case) - (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case) - ;; From Emacs subr.el. - (defun org-string-equal-ignore-case (string1 string2) - "Like `string-equal', but case-insensitive. -Upper-case and lower-case letters are treated as equal. -Unibyte strings are converted to multibyte for comparison." - (eq t (compare-strings string1 0 nil string2 0 nil t)))) - -\f -;;; Emacs < 28.1 compatibility - -(if (fboundp 'file-name-concat) - (defalias 'org-file-name-concat #'file-name-concat) - (defun org-file-name-concat (directory &rest components) - "Append COMPONENTS to DIRECTORY and return the resulting string. - -Elements in COMPONENTS must be a string or nil. -DIRECTORY or the non-final elements in COMPONENTS may or may not end -with a slash -- if they don't end with a slash, a slash will be -inserted before contatenating." - (save-match-data - (mapconcat - #'identity - (delq nil - (mapcar - (lambda (str) - (when (and str (not (seq-empty-p str)) - (string-match "\\(.+\\)/?" str)) - (match-string 1 str))) - (cons directory components))) - "/")))) - -(if (fboundp 'directory-empty-p) - (defalias 'org-directory-empty-p #'directory-empty-p) - (defun org-directory-empty-p (dir) - "Return t if DIR names an existing directory containing no other files." - (and (file-directory-p dir) - (null (directory-files dir nil directory-files-no-dot-files-regexp t))))) - -(if (fboundp 'string-clean-whitespace) - (defalias 'org-string-clean-whitespace #'string-clean-whitespace) - ;; From Emacs subr-x.el. - (defun org-string-clean-whitespace (string) - "Clean up whitespace in STRING. -All sequences of whitespaces in STRING are collapsed into a -single space character, and leading/trailing whitespace is -removed." - (let ((blank "[[:blank:]\r\n]+")) - (string-trim (replace-regexp-in-string blank " " string t t) - blank blank)))) - -(if (fboundp 'format-prompt) - (defalias 'org-format-prompt #'format-prompt) - ;; From Emacs minibuffer.el, inlining - ;; `minibuffer-default-prompt-format' value and replacing `length<' - ;; (both new in Emacs 28.1). - (defun org-format-prompt (prompt default &rest format-args) - "Compatibility substitute for `format-prompt'." - (concat - (if (null format-args) - prompt - (apply #'format prompt format-args)) - (and default - (or (not (stringp default)) - (> (length default) 0)) - (format " (default %s)" - (if (consp default) - (car default) - default))) - ": "))) +;;; compat.el + +;; Do not throw an error when not available - assume latest Emacs +;; version (built-in Org). +(require 'compat nil 'noerror) + +;; Provide compatibility macros when we are a part of Emacs. +;; See https://elpa.gnu.org/packages/doc/compat.html#Usage + +(defmacro org-compat-function (fun) + "Return compatibility function symbol for FUN. + +If the Emacs version provides a sufficiently recent version of +FUN, the symbol FUN is returned itself. Otherwise the macro +returns the symbol of a compatibility function which supports the +behavior and calling convention of the current stable Emacs +version. For example Compat 29.1 will provide compatibility +functions which implement the behavior and calling convention of +Emacs 29.1. + +See also `org-compat-call' to directly call compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `#',(if (fboundp compat) compat fun))) + +(defmacro org-compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. + +A good example function is `plist-get' which was extended with an +additional predicate argument in Emacs 29.1. The compatibility +function, which supports this additional argument, can be +obtained via (compat-function plist-get) and called +via (compat-call plist-get plist prop predicate). It is not +possible to directly call (plist-get plist prop predicate) on +Emacs older than 29.1, since the original `plist-get' function +does not yet support the predicate argument. Note that the +Compat library never overrides existing functions. + +See also `org-compat-function' to lookup compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `(,(if (fboundp compat) compat fun) ,@args))) + +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "9.7") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "9.7") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "9.7") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "9.7") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "9.7") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "9.7") +(define-obsolete-function-alias 'org-xor + 'xor "9.7") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "9.7") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "9.7") \f ;;; Emacs < 27.1 compatibility @@ -210,22 +170,6 @@ (if (version< emacs-version "27.1") (replace-buffer-contents source)) (defalias 'org-replace-buffer-contents #'replace-buffer-contents)) -(unless (fboundp 'proper-list-p) - ;; `proper-list-p' was added in Emacs 27.1. The function below is - ;; taken from Emacs subr.el 200195e824b^. - (defun proper-list-p (object) - "Return OBJECT's length if it is a proper list, nil otherwise. -A proper list is neither circular nor dotted (i.e., its last cdr -is nil)." - (and (listp object) (ignore-errors (length object))))) - -(if (fboundp 'xor) - ;; `xor' was added in Emacs 27.1. - (defalias 'org-xor #'xor) - (defsubst org-xor (a b) - "Exclusive `or'." - (if a (not b) b))) - (unless (fboundp 'pcomplete-uniquify-list) ;; The misspelled variant was made obsolete in Emacs 27.1 (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list)) @@ -255,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p) (when (fboundp 'set-face-extend) (mapc (lambda (f) (set-face-extend f extend-p)) faces))) -(if (fboundp 'string-distance) - (defalias 'org-string-distance 'string-distance) - (defun org-string-distance (s1 s2) - "Return the edit (levenshtein) distance between strings S1 S2." - (let* ((l1 (length s1)) - (l2 (length s2)) - (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) - (number-sequence 1 (1+ l1))))) - (in (lambda (i j) (aref (aref dist i) j)))) - (setf (aref (aref dist 0) 0) 0) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist 0) j) j)) - (dolist (i (number-sequence 1 l1)) - (setf (aref (aref dist i) 0) i) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist i) j) - (min - (1+ (funcall in (1- i) j)) - (1+ (funcall in i (1- j))) - (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) - (funcall in (1- i) (1- j))))))) - (funcall in l1 l2)))) - (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance "9.5") @@ -298,23 +219,6 @@ (if (fboundp 'line-number-display-width) (defalias 'org-line-number-display-width 'line-number-display-width) (defun org-line-number-display-width (&rest _) 0)) -(if (fboundp 'buffer-hash) - (defalias 'org-buffer-hash 'buffer-hash) - (defun org-buffer-hash () (md5 (current-buffer)))) - -(unless (fboundp 'file-attribute-modification-time) - (defsubst file-attribute-modification-time (attributes) - "The modification time in ATTRIBUTES returned by `file-attributes'. -This is the time of the last change to the file's contents, and -is a Lisp timestamp in the same style as `current-time'." - (nth 5 attributes))) - -(unless (fboundp 'file-attribute-size) - (defsubst file-attribute-size (attributes) - "The size (in bytes) in ATTRIBUTES returned by `file-attributes'. -This is a floating point number if the size is too large for an integer." - (nth 7 attributes))) - \f ;;; Obsolete aliases (remove them after the next major release). @@ -1416,7 +1320,7 @@ (defun org-mode-flyspell-verify () (and log (let ((drawer (org-element-lineage element '(drawer)))) (and drawer - (org-string-equal-ignore-case + (string-equal-ignore-case log (org-element-property :drawer-name drawer)))))) nil) (t diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 43c6b2b74..c699c115b 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p (lambda (p) (next-single-char-property-change p 'invisible nil limit))))) (next pos)) (while (and (funcall cmp next limit) - (not (org-xor + (not (xor invisible-initially? (funcall invisible-p (if previous-p diff --git a/lisp/org-lint.el b/lisp/org-lint.el index 0e2967b6c..adc893aff 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast) ast 'node-property (lambda (property) - (and (org-string-equal-ignore-case + (and (string-equal-ignore-case "CUSTOM_ID" (org-element-property :key property)) (org-element-property :value property))) (lambda (property _) (org-element-property :begin property)) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index 8e73fbc4b..21c09567f 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -279,12 +279,12 @@ (defgroup org-persist nil (defcustom org-persist-directory (expand-file-name - (org-file-name-concat + (file-name-concat (let ((cache-dir (when (fboundp 'xdg-cache-home) (xdg-cache-home)))) (if (or (seq-empty-p cache-dir) (not (file-exists-p cache-dir)) - (file-exists-p (org-file-name-concat + (file-exists-p (file-name-concat user-emacs-directory "org-persist"))) user-emacs-directory @@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data) (defun org-persist-read:file (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:url (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:index (cont index-file _) "Read index container CONT from INDEX-FILE." @@ -750,7 +750,7 @@ (defun org-persist--load-index () "Load `org-persist--index'." (org-persist-load:index `(index ,org-persist--storage-version) - (org-file-name-concat org-persist-directory org-persist-index-file) + (file-name-concat org-persist-directory org-persist-index-file) nil)) ;;;; Writing container data @@ -804,7 +804,7 @@ (defun org-persist-write:file (c collection) (setq path (cadr c))) (let* ((persist-file (plist-get collection :persist-file)) (ext (file-name-extension path)) - (file-copy (org-file-name-concat + (file-copy (file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) (unless (file-exists-p file-copy) @@ -850,7 +850,7 @@ (defun org-persist-write:index (container _) org-persist-directory)))) (when (file-exists-p org-persist-directory) (let ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file))) + (file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) (org-persist--write-elisp-file index-file org-persist--index t t) (setq org-persist--index-age @@ -865,7 +865,7 @@ (defun org-persist--save-index () (defun org-persist--merge-index-with-disk () "Merge `org-persist--index' with the current index file on disk." (let* ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file)) + (file-name-concat org-persist-directory org-persist-index-file)) (disk-index (and (file-exists-p index-file) (org-file-newer-than-p index-file org-persist--index-age) @@ -887,8 +887,8 @@ (defun org-persist--merge-index (base other) (dolist (item (nreverse new)) (unless (or (memq 'index (mapcar #'car (plist-get item :container))) (not (file-exists-p - (org-file-name-concat org-persist-directory - (plist-get item :persist-file)))) + (file-name-concat org-persist-directory + (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) (nreverse combined)) @@ -989,7 +989,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) (persist-file (when collection - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (data nil)) @@ -1077,7 +1077,7 @@ (defun org-persist-write (container &optional associated ignore-return) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) (when (or (file-exists-p org-persist-directory) (org-persist--save-index)) - (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file))) + (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file))) (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection))) (plist-get collection :container)))) (puthash file data org-persist--write-cache) @@ -1097,11 +1097,11 @@ (defun org-persist-write-all (&optional associated) ;; The container is an `index' container. (eq 'index (caar (plist-get (car org-persist--index) :container))) (or (not (file-exists-p org-persist-directory)) - (org-directory-empty-p org-persist-directory))) + (directory-empty-p org-persist-directory))) ;; Do not write anything, and clear up `org-persist-directory' to reduce ;; clutter. (when (and (file-exists-p org-persist-directory) - (org-directory-empty-p org-persist-directory)) + (directory-empty-p org-persist-directory)) (delete-directory org-persist-directory)) ;; Write the data. (let (all-containers) @@ -1142,7 +1142,7 @@ (defun org-persist--gc-persist-file (persist-file) "Garbage collect PERSIST-FILE." (when (file-exists-p persist-file) (delete-file persist-file) - (when (org-directory-empty-p (file-name-directory persist-file)) + (when (directory-empty-p (file-name-directory persist-file)) (delete-directory (file-name-directory persist-file))))) (defmacro org-persist-associated-files:generic (container collection) @@ -1180,7 +1180,7 @@ (defun org-persist-gc () (let (new-index (remote-files-num 0) (orphan-files - (delete (org-file-name-concat org-persist-directory org-persist-index-file) + (delete (file-name-concat org-persist-directory org-persist-index-file) (when (file-exists-p org-persist-directory) (directory-files-recursively org-persist-directory ".+"))))) (dolist (collection org-persist--index) @@ -1188,7 +1188,7 @@ (defun org-persist-gc () (web-file (and file (string-match-p "\\`https?://" file))) (file-remote (when file (file-remote-p file))) (persist-file (when (plist-get collection :persist-file) - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (expired? (org-persist--gc-expired-p diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 03c351cf6..9797a0633 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes) (prompt (let ((default (or (car org-refile-history) (and (assoc cbnex tbl) (setq cdef cbnex) cbnex)))) - (org-format-prompt prompt default))) + (format-prompt prompt default))) pa answ parent-target child parent old-hist) (setq old-hist org-refile-history) (setq answ (funcall cfunc prompt tbl nil (not new-nodes) diff --git a/lisp/org.el b/lisp/org.el index 10ade32dd..e9fa9a241 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry <bzg@gnu.org> ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) ;; Version: 9.7-pre @@ -19445,7 +19445,7 @@ (defun org-fill-paragraph (&optional justify region) (barf-if-buffer-read-only) (list (when current-prefix-arg 'full) t))) (let ((hash (and (not (buffer-modified-p)) - (org-buffer-hash)))) + (buffer-hash)))) (cond ((and region transient-mark-mode mark-active (not (eq (region-beginning) (region-end)))) @@ -19470,7 +19470,7 @@ (defun org-fill-paragraph (&optional justify region) ;; If we didn't change anything in the buffer (and the buffer was ;; previously unmodified), then flip the modification status back ;; to "unchanged". - (when (and hash (equal hash (org-buffer-hash))) + (when (and hash (equal hash (buffer-hash))) (set-buffer-modified-p nil)) ;; Return non-nil. t)) diff --git a/lisp/ox.el b/lisp/ox.el index a6169ea63..203136994 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4626,11 +4626,11 @@ (defun org-export-resolve-radio-link (link info) Return value can be a radio-target object or nil. Assume LINK has type \"radio\"." - (let ((path (org-string-clean-whitespace (org-element-property :path link)))) + (let ((path (string-clean-whitespace (org-element-property :path link)))) (org-element-map (plist-get info :parse-tree) 'radio-target (lambda (radio) - (and (org-string-equal-ignore-case - (org-string-clean-whitespace (org-element-property :value radio)) + (and (string-equal-ignore-case + (string-clean-whitespace (org-element-property :value radio)) path) radio)) info 'first-match))) diff --git a/mk/default.mk b/mk/default.mk index 997b22b66..4ad1a4281 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -38,7 +38,7 @@ pkgdir = $(shell pwd)/pkg-deps EFLAGS ?= # Third-party packages to install when running make -EPACKAGES ?= +EPACKAGES ?= compat # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el index a38d9f979..565539571 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display () (dotimes (_ 2) (goto-char 1) (re-search-forward "\\[") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "example") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "com") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "\\[") (should-not (org-invisible-p)) (re-search-forward "link") (should-not (org-invisible-p)) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (org-toggle-link-display))))) \f diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 0ed44c6af..6a47b3384 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort () "Test aborting a capture process." ;; Newly create capture buffer should not be saved. (let ((capture-file (make-temp-name - (org-file-name-concat + (file-name-concat temporary-file-directory "org-test")))) (unwind-protect -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-org-manual.org-Document-compat-library-installation.patch --] [-- Type: text/x-patch, Size: 2242 bytes --] From cbc781d02021563b2f68b2179813e936ab379446 Mon Sep 17 00:00:00 2001 Message-Id: <cbc781d02021563b2f68b2179813e936ab379446.1680344979.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH 3/3] org-manual.org: Document compat library installation * doc/org-manual.org (Using Org's git repository): Document that users must also install compat library when using git version of Org. * etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to support older Emacs versions): Announce amendments to the Org installation from git sources. --- doc/org-manual.org | 4 ++++ etc/ORG-NEWS | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/doc/org-manual.org b/doc/org-manual.org index 50662669e..aa9886e5f 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -140,6 +140,10 @@ *** Using Org's git repository (add-to-list 'load-path "~/src/org-mode/lisp") #+end_src +You must also manually install =compat= library required by Org mode. +Using built-in =package.el=, you can run =M-x package-install <RET> +compat <RET>=. + You can also compile with =make=, generate the documentation with =make doc=, create a local configuration with =make config= and install Org with =make install=. Please run =make help= to get the diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ac233a986..0302b8cda 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Org mode now uses =compat.el= third-party package to support older Emacs versions + +This change is mostly technical and should not affect most users. +However, people who install Org from git source might be affected. +It is now necessary to manually install =compat.el= using Emacs' +package manager. + *** =python-mode.el (MELPA)= support in =ob-python.el= is removed =python-mode.el= support has been removed from =ob-python.el=. The -- 2.39.1 [-- Attachment #5: Type: text/plain, Size: 224 bytes --] -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-01 10:31 ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko @ 2023-04-01 11:38 ` Daniel Mendler 2023-04-01 14:20 ` Max Nikulin 2023-04-02 16:37 ` Max Nikulin 1 sibling, 1 reply; 36+ messages in thread From: Daniel Mendler @ 2023-04-01 11:38 UTC (permalink / raw) To: Ihor Radchenko, Timothy; +Cc: Bastien, Kyle Meyer, Org-mode On 4/1/23 12:31, Ihor Radchenko wrote: > Ihor Radchenko <yantar92@posteo.net> writes: > >> I have recently been contacted by the current compat.el maintainer >> asking if we are willing to adapt compat.el in Org. > > See the attached patch set adding support of compat.el. > > I had to update Org's build system to handle third-party packages. > Please, give it a close check (first patch). > > The second patch adds the actual Elisp part and replaces some > compatibility functions with what is provided by compat.el. > Note that not all the functions are available in compat.el for now. > Daniel, you might want to take a look. > > The last patch adds the necessary explanation for users who install Org > from git. Now, they must install compat.el manually to make Org work. From my side, the change looks good. The current Compat version 29.1.4.x is stable with no known issues. Daniel ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-01 11:38 ` Daniel Mendler @ 2023-04-01 14:20 ` Max Nikulin 2023-04-02 8:52 ` Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-01 14:20 UTC (permalink / raw) To: emacs-orgmode On 01/04/2023 18:38, Daniel Mendler wrote: > From my side, the change looks good. The current Compat version 29.1.4.x > is stable with no known issues. Debian Bookworm and Ubuntu 23.04 (currently frozen testing and beta accordingly) have elpa-compat-29.1.3.4 and 29.1.3.2. Are some issues expected if a bit earlier version is required? ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-01 14:20 ` Max Nikulin @ 2023-04-02 8:52 ` Ihor Radchenko 2023-04-02 15:31 ` Max Nikulin 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-04-02 8:52 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: > On 01/04/2023 18:38, Daniel Mendler wrote: >> From my side, the change looks good. The current Compat version 29.1.4.x >> is stable with no known issues. > > Debian Bookworm and Ubuntu 23.04 (currently frozen testing and beta > accordingly) have elpa-compat-29.1.3.4 and 29.1.3.2. Are some issues > expected if a bit earlier version is required? I don't think so. At least, we do not appear to be using anything listed in NEWS for later Compat versions (https://elpa.gnu.org/packages/compat.html). And it should not matter anyway. We only need compat when Org mode is not built-in, but installed by other means. Normally, users will simply install Org from ELPA where we do not need to worry about older versions of Compat. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-02 8:52 ` Ihor Radchenko @ 2023-04-02 15:31 ` Max Nikulin 2023-04-02 16:04 ` Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-02 15:31 UTC (permalink / raw) To: emacs-orgmode On 02/04/2023 15:52, Ihor Radchenko wrote: > And it should not matter anyway. We only need compat when Org mode is > not built-in, but installed by other means. Normally, users will simply > install Org from ELPA where we do not need to worry about older versions > of Compat. If dependencies may be satisfied by installing system packages then it is easier to run Org from repository clone or to build new version of elpa-org package. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-02 15:31 ` Max Nikulin @ 2023-04-02 16:04 ` Ihor Radchenko 0 siblings, 0 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-04-02 16:04 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: > If dependencies may be satisfied by installing system packages then it > is easier to run Org from repository clone or to build new version of > elpa-org package. The patch provides EFLAGS variable that will allow supplying flags to emacs executable. One can just use ~EFLAGS="-L /path/to/local/compat/" make~. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-01 10:31 ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko 2023-04-01 11:38 ` Daniel Mendler @ 2023-04-02 16:37 ` Max Nikulin 2023-04-02 17:00 ` [PATCH v2] " Ihor Radchenko 1 sibling, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-02 16:37 UTC (permalink / raw) To: emacs-orgmode On 01/04/2023 17:31, Ihor Radchenko wrote: > > See the attached patch set adding support of compat.el. Ihor, do added makefile rules follow best practices used by other Emacs packages in respect to dependencies? I do not like the idea of network queries on every make. In some cases I would prefer to specify a directory where compat.el is installed, so Makefile should not try to manage this directory. My impression is that package management code in Emacs is too oriented for interactive usage. E.g. python's pip caches downloaded packages or allows to specify a proxy or an alternative source. Moreover precise version may be specified while only last version is hosted on ELPA. In other package managers version lock is often preferred to avoid unexpected effects of spurious update. Fortunately ELPA packages are at least reviewed before publication. Originally I expected that either compat.el would be included into Org repository either as a copy of the file or as git submodule. In addition I am afraid of recursive removal of directories. It is too easy to remove too much. > +pkgdir = $(shell pwd)/pkg-deps Make has CURDIR variable, but I am unsure if it is safe to use it in this context. > + -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + find has -delete action. I see that "-exec $(RM)" is already used. > +cleanpkg: > + -$(RMR) $(pkgdir) Perhaps it is impossible to completely avoid recursive deleting of directories, but I still afraid of cases like https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123 https://news.ycombinator.com/item?id=9254876 > Subject: [PATCH 2/3] Use compat.el library instead of ad-hoc compatibility > function set It would be easier to review if this patch was split into 2 parts: - add compat.el dependency (unused) - replace functions to ones from compat.el ^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-02 16:37 ` Max Nikulin @ 2023-04-02 17:00 ` Ihor Radchenko 2023-04-03 8:46 ` [PATCH v3] " Ihor Radchenko 2023-04-08 11:15 ` [PATCH v2] " Max Nikulin 0 siblings, 2 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-04-02 17:00 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 2704 bytes --] I am attaching a slightly tweaked version of the patch that will make less use of internet connection (use only when really, really necessary), fixes variable expansion to be done once instead of in every make sub-process, and adds some extra info messages. Max Nikulin <manikulin@gmail.com> writes: > Ihor, do added makefile rules follow best practices used by other Emacs > packages in respect to dependencies? I know no other Emacs packages that manage dependencies using make. > I do not like the idea of network queries on every make. Any better suggestions? > In some cases I would prefer to specify a directory where compat.el is > installed, so Makefile should not try to manage this directory. Sure. See EFLAGS variable. Makefile will not try to manage -L /path/to/compat directory. > Originally I expected that either compat.el would be included into Org > repository either as a copy of the file or as git submodule. That will create maintenance nightmare. > In addition I am afraid of recursive removal of directories. It is too > easy to remove too much. > >> +pkgdir = $(shell pwd)/pkg-deps > > Make has CURDIR variable, but I am unsure if it is safe to use it in > this context. Actually, we need pkgdir := $(shell pwd)/pkg-deps. CURDIR is wrong because default.mk will trigger evaluation in every make sub-process as well. >> + -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + > > find has -delete action. I see that "-exec $(RM)" is already used. I just copied the existing code. I guess we can use -delete as well. I do not have a lot of experience with this usage of find. May you share the equivalent find call with -delete that works with this patch? >> +cleanpkg: >> + -$(RMR) $(pkgdir) > > Perhaps it is impossible to completely avoid recursive deleting of > directories, but I still afraid of cases like > https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123 > https://news.ycombinator.com/item?id=9254876 I do not think that we have any significant risk here. I would not mind alternative way to implement clean target though. If you know one. >> Subject: [PATCH 2/3] Use compat.el library instead of ad-hoc compatibility >> function set > > It would be easier to review if this patch was split into 2 parts: > - add compat.el dependency (unused) > - replace functions to ones from compat.el Sure, but after spending half an hour trying to decouple this part, I gave up and decided to leave it as is. And there is nothing fancy in adding compat dependency in 2/3 patch anyway. Just one (require 'compat nil t), two macro definitions adviced by compat manual (copy-paste from compat code), and adding compat to EPACKAGES in makefiles. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Upgrade-Org-build-system-to-handle-third-party-depen.patch --] [-- Type: text/x-patch, Size: 6315 bytes --] From f95433f53878e8371bb28a045fdb5d06cf0877b9 Mon Sep 17 00:00:00 2001 Message-Id: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH 1/6] Upgrade Org build system to handle third-party dependencies * mk/default.mk (pkgdir): New variable holding the location of third-party packages to be downloaded if necessary during compilation. (EFLAGS): New variable holding extra flags to be passed to Emacs executable when running make. (EPACKAGES): List of packages to be installed (unless already present in the `load-path') during compilation. (package-install): (INSTALL_PACKAGES): New command to download and install missing packages. (BATCH): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (check test): (compile compile-dirty): Use the new uppkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_BASE): (CONF_DEST): (CONF_CALL): Update according to the new variables and targets. * .gitignore: Ignore the downloaded packages. This commit paves the way towards third-party built-time dependencies for Org. In particular, towards including compat.el dependency. According to EPACKAGES, we can auto-download necessary packages, unless they are manually specified via -L switches in EFLAGS. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 1 + mk/default.mk | 24 +++++++++++++++++++++++- mk/targets.mk | 24 ++++++++++++++++-------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 4bb81c359..a58670c90 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ t auto tmp TODO +/pkg-deps # and collateral damage from Emacs diff --git a/mk/default.mk b/mk/default.mk index fa46661e8..997b22b66 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -31,6 +31,15 @@ GIT_BRANCH = TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest +# Where to store Org dependencies +pkgdir = $(shell pwd)/pkg-deps + +# Extra flags to be passed to Emacs +EFLAGS ?= + +# Third-party packages to install when running make +EPACKAGES ?= + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -72,12 +81,22 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' +package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ --eval '(add-to-list '"'"'load-path (concat default-directory "testing"))' BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST) +ifeq (,$(EPACKAGES)) +INSTALL_PACKAGES = +else +INSTALL_PACKAGES = \ + $(BATCH) \ + --eval '(package-refresh-contents)' \ + $(foreach package,$(EPACKAGES),$(package-install)) +endif + BTEST = $(BATCH) $(BTEST_INIT) \ -l org-batch-test-init \ --eval '(setq \ @@ -120,7 +139,10 @@ EMACSQ = $(EMACS) -Q # Using emacs in batch mode. BATCH = $(EMACSQ) -batch \ - --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' + $(EFLAGS) \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)' # Emacs must be started in toplevel directory BATCHO = $(BATCH) \ diff --git a/mk/targets.mk b/mk/targets.mk index 0bd293d68..ab8b830bb 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \ check test install $(INSTSUB) \ info html pdf card refcard doc docs \ autoloads cleanall clean $(CLEANDIRS:%=clean%) \ clean-install cleanelc cleandirs \ - cleanlisp cleandoc cleandocs cleantest \ + cleanlisp cleandoc cleandocs cleantest cleanpkg \ compile compile-dirty uncompiled \ config config-test config-exe config-all config-eol config-version \ vanilla repro -CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC -CONF_DEST = lispdir infodir datadir testdir +CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES +CONF_DEST = lispdir infodir datadir testdir pkgdir CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO -CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION +CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION config-eol:: EOL = \# config-eol:: config-all config config-all:: @@ -86,7 +86,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: uppkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -94,7 +94,7 @@ all clean-install:: vanilla: -@$(NOBATCH) & -check test:: compile +check test:: uppkg compile check test test-dirty:: -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) @@ -102,6 +102,11 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f $(MAKE) cleantest endif +uppkg:: + -$(MKDIR) -p $(pkgdir) + -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + + $(INSTALL_PACKAGES) + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -134,7 +139,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest +cleanall: cleandirs cleantest cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -159,3 +164,6 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: + -$(RMR) $(pkgdir) -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Use-compat.el-library-instead-of-ad-hoc-compatibilit.patch --] [-- Type: text/x-patch, Size: 35871 bytes --] From 6099628c54170b515d8812428fa050f81c0533ec Mon Sep 17 00:00:00 2001 Message-Id: <6099628c54170b515d8812428fa050f81c0533ec.1680454654.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:10:13 +0200 Subject: [PATCH 2/6] Use compat.el library instead of ad-hoc compatibility function set * mk/default.mk (EPACKAGES): Demand compat library during compile time. * lisp/org.el: Add compat dependency. (org-fill-paragraph): * lisp/org-compat.el: Implement compat.el compatibility layer. Obsolete org-* compatibility functions that are already available in compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case', `org-file-name-concat', `org-directory-empty-p', `org-string-clean-whitespace', `org-format-prompt', `org-xor', `org-string-distance', `org-buffer-hash'. * lisp/ob-core.el (org-babel-results-keyword): Use functions provided by compat.el. (org-babel-insert-result): * lisp/oc-basic.el (org-cite-basic--parse-bibliography): * lisp/oc.el (org-cite-adjust-note): * lisp/ol-gnus.el (org-gnus-group-link): (org-gnus-article-link): (org-gnus-store-link): * lisp/ol.el: (org-store-link): * lisp/org-attach.el: * lisp/org-capture.el: (org-capture-fill-template): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el: * lisp/org-persist.el (org-persist-directory): (org-persist-read:file): (org-persist-read:url): (org-persist--load-index): (org-persist-write:file): (org-persist-write:index): (org-persist--merge-index-with-disk): (org-persist-read): (org-persist-write): (org-persist-write-all): (org-persist--gc-persist-file): (org-persist-gc): * lisp/org-refile.el (org-refile-get-location): * lisp/ox.el (org-export-resolve-radio-link): * testing/lisp/test-ol.el (test-org-link/toggle-link-display): * testing/lisp/test-org-capture.el (test-org-capture/abort): Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 2 +- lisp/ob-core.el | 10 +- lisp/oc-basic.el | 6 +- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +- lisp/ol.el | 4 +- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +- lisp/org-compat.el | 220 +++++++++---------------------- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-persist.el | 38 +++--- lisp/org-refile.el | 2 +- lisp/org.el | 6 +- lisp/ox.el | 6 +- mk/default.mk | 2 +- testing/lisp/test-ol.el | 10 +- testing/lisp/test-org-capture.el | 2 +- 18 files changed, 118 insertions(+), 214 deletions(-) diff --git a/.gitignore b/.gitignore index a58670c90..0d9c5b297 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ local*.mk .gitattributes mk/x11idle ChangeLog +pkg-deps/ # Files generated during `make packages/org` in a clone of `elpa.git`. @@ -71,7 +72,6 @@ t auto tmp TODO -/pkg-deps # and collateral damage from Emacs diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 471887a3a..4ef1f2084 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS" :type 'string :safe (lambda (v) (and (stringp v) - (org-string-equal-ignore-case "RESULTS" v)))) + (string-equal-ignore-case "RESULTS" v)))) (defcustom org-babel-noweb-wrap-start "<<" "String used to begin a noweb reference in a code block. @@ -927,7 +927,7 @@ (defun org-babel-check-src-block () (match-string 4)))))) (dolist (name names) (when (and (not (string= header name)) - (<= (org-string-distance header name) too-close) + (<= (string-distance header name) too-close) (not (member header names))) (error "Supplied header \"%S\" is suspiciously close to \"%S\"" header name)))) @@ -2518,7 +2518,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex ;; Escape contents from "export" wrap. Wrap ;; inline results within an export snippet with ;; appropriate value. - ((org-string-equal-ignore-case type "export") + ((string-equal-ignore-case type "export") (let ((backend (pcase split (`(,_) "none") (`(,_ ,b . ,_) b)))) @@ -2529,14 +2529,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex backend) "@@)}}}"))) ;; Escape contents from "example" wrap. Mark ;; inline results as verbatim. - ((org-string-equal-ignore-case type "example") + ((string-equal-ignore-case type "example") (funcall wrap opening-line closing-line nil nil "{{{results(=" "=)}}}")) ;; Escape contents from "src" wrap. Mark ;; inline results as inline source code. - ((org-string-equal-ignore-case type "src") + ((string-equal-ignore-case type "src") (let ((inline-open (pcase split (`(,_) diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index 12b627e71..1c86f344a 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info) (dolist (file (org-cite-list-bibliography-files)) (when (file-readable-p file) (with-temp-buffer - (when (or (org-file-has-changed-p file) + (when (or (file-has-changed-p file) (not (gethash file org-cite-basic--file-id-cache))) (insert-file-contents file) (set-visited-file-name file t) - (puthash file (org-buffer-hash) org-cite-basic--file-id-cache)) + (puthash file (buffer-hash) org-cite-basic--file-id-cache)) (condition-case nil (unwind-protect (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache))) @@ -488,7 +488,7 @@ (defun org-cite-basic--close-keys (key keys) "List cite keys close to KEY in terms of string distance." (seq-filter (lambda (k) (>= org-cite-basic-max-key-distance - (org-string-distance k key))) + (string-distance k key))) keys)) (defun org-cite-basic--set-keymap (beg end suggestions) diff --git a/lisp/oc.el b/lisp/oc.el index dde6f3a32..f39ae848b 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct) (match-string 3 previous))))) ;; Bail you when there is no quote and either no punctuation, or ;; punctuation on both sides. - (when (or quote (org-xor punct final-punct)) + (when (or quote (xor punct final-punct)) ;; Phase 1: handle punctuation rule. (pcase rule ((guard (not quote)) nil) diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el index 7c07ce045..e121cfba3 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -98,8 +98,8 @@ (defun org-gnus-group-link (group) `org-gnus-prefer-web-links' is reversed." (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group))) (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups - (org-xor current-prefix-arg - org-gnus-prefer-web-links)) + (xor current-prefix-arg + org-gnus-prefer-web-links)) (concat "https://groups.google.com/group/" unprefixed-group) (concat "gnus:" group)))) @@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive) If `org-store-link' was called with a prefix arg the meaning of `org-gnus-prefer-web-links' is reversed." - (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links) + (if (and (xor current-prefix-arg org-gnus-prefer-web-links) newsgroups ;make web links only for nntp groups (not x-no-archive)) ;and if X-No-Archive isn't set (format "https://groups.google.com/groups/search?as_umsgid=%s" @@ -169,7 +169,7 @@ (defun org-gnus-store-link () newsgroups x-no-archive) ;; Fetching an article is an expensive operation; newsgroup and ;; x-no-archive are only needed for web links. - (when (org-xor current-prefix-arg org-gnus-prefer-web-links) + (when (xor current-prefix-arg org-gnus-prefer-web-links) ;; Make sure the original article buffer is up-to-date. (save-window-excursion (gnus-summary-select-article)) (setq to (or to (gnus-fetch-original-field "To"))) diff --git a/lisp/ol.el b/lisp/ol.el index 9e4781f6e..3d62a6fa0 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let* ((element (org-element-at-point)) (name (org-element-property :name element)) (context @@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let ((context (org-link--normalize-string (or (org-link--context-from-region) (org-current-line-string)) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 8d01eda71..5cc40873c 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -674,7 +674,7 @@ (defun org-attach-sync () (let ((files (org-attach-file-list attach-dir))) (org-attach-tag (not files))) (when org-attach-sync-delete-empty-dir - (when (and (org-directory-empty-p attach-dir) + (when (and (directory-empty-p attach-dir) (if (eq 'query org-attach-sync-delete-empty-dir) (yes-or-no-p "Attachment directory is empty. Delete?") t)) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index b96e9f336..c5b1c6d50 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1323,9 +1323,9 @@ (defun org-capture-place-item () ;; prioritize the existing list. (when prepend? (let ((ordered? (eq 'ordered (org-element-property :type item)))) - (when (org-xor ordered? - (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" - template)) + (when (xor ordered? + (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" + template)) (org-cycle-list-bullet (if ordered? "1." "-"))))) ;; Eventually repair the list for proper indentation and ;; bullets. @@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation) (setq org-capture--prompt-history (gethash prompt org-capture--prompt-history-table)) (push (org-completing-read - (org-format-prompt (or prompt "Enter string") default) + (format-prompt (or prompt "Enter string") default) completions nil nil nil 'org-capture--prompt-history default) strings) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index c47a4e8c2..046a3db97 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec)) (declare-function org-fold-show-all "org-fold" (&optional types)) (declare-function org-fold-show-children "org-fold" (&optional level)) (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers)) -;; `org-string-equal-ignore-case' is in _this_ file but isn't at the -;; top-level. -(declare-function org-string-equal-ignore-case "org-compat" (string1 string2)) (defvar calendar-mode-map) (defvar org-complex-heading-regexp) @@ -95,104 +92,67 @@ (defvar org-table1-hline-regexp) (defvar org-fold-core-style) \f -;;; Emacs < 29 compatibility - -(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal) - "Internal variable used by `org-file-has-changed-p'.") - -(if (fboundp 'file-has-changed-p) - (defalias 'org-file-has-changed-p #'file-has-changed-p) - (defun org-file-has-changed-p (file &optional tag) - "Return non-nil if FILE has changed. -The size and modification time of FILE are compared to the size -and modification time of the same FILE during a previous -invocation of `org-file-has-changed-p'. Thus, the first invocation -of `org-file-has-changed-p' always returns non-nil when FILE exists. -The optional argument TAG, which must be a symbol, can be used to -limit the comparison to invocations with identical tags; it can be -the symbol of the calling function, for example." - (let* ((file (directory-file-name (expand-file-name file))) - (remote-file-name-inhibit-cache t) - (fileattr (file-attributes file 'integer)) - (attr (and fileattr - (cons (file-attribute-size fileattr) - (file-attribute-modification-time fileattr)))) - (sym (concat (symbol-name tag) "@" file)) - (cachedattr (gethash sym org-file-has-changed-p--hash-table))) - (when (not (equal attr cachedattr)) - (puthash sym attr org-file-has-changed-p--hash-table))))) - -(if (fboundp 'string-equal-ignore-case) - (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case) - ;; From Emacs subr.el. - (defun org-string-equal-ignore-case (string1 string2) - "Like `string-equal', but case-insensitive. -Upper-case and lower-case letters are treated as equal. -Unibyte strings are converted to multibyte for comparison." - (eq t (compare-strings string1 0 nil string2 0 nil t)))) - -\f -;;; Emacs < 28.1 compatibility - -(if (fboundp 'file-name-concat) - (defalias 'org-file-name-concat #'file-name-concat) - (defun org-file-name-concat (directory &rest components) - "Append COMPONENTS to DIRECTORY and return the resulting string. - -Elements in COMPONENTS must be a string or nil. -DIRECTORY or the non-final elements in COMPONENTS may or may not end -with a slash -- if they don't end with a slash, a slash will be -inserted before contatenating." - (save-match-data - (mapconcat - #'identity - (delq nil - (mapcar - (lambda (str) - (when (and str (not (seq-empty-p str)) - (string-match "\\(.+\\)/?" str)) - (match-string 1 str))) - (cons directory components))) - "/")))) - -(if (fboundp 'directory-empty-p) - (defalias 'org-directory-empty-p #'directory-empty-p) - (defun org-directory-empty-p (dir) - "Return t if DIR names an existing directory containing no other files." - (and (file-directory-p dir) - (null (directory-files dir nil directory-files-no-dot-files-regexp t))))) - -(if (fboundp 'string-clean-whitespace) - (defalias 'org-string-clean-whitespace #'string-clean-whitespace) - ;; From Emacs subr-x.el. - (defun org-string-clean-whitespace (string) - "Clean up whitespace in STRING. -All sequences of whitespaces in STRING are collapsed into a -single space character, and leading/trailing whitespace is -removed." - (let ((blank "[[:blank:]\r\n]+")) - (string-trim (replace-regexp-in-string blank " " string t t) - blank blank)))) - -(if (fboundp 'format-prompt) - (defalias 'org-format-prompt #'format-prompt) - ;; From Emacs minibuffer.el, inlining - ;; `minibuffer-default-prompt-format' value and replacing `length<' - ;; (both new in Emacs 28.1). - (defun org-format-prompt (prompt default &rest format-args) - "Compatibility substitute for `format-prompt'." - (concat - (if (null format-args) - prompt - (apply #'format prompt format-args)) - (and default - (or (not (stringp default)) - (> (length default) 0)) - (format " (default %s)" - (if (consp default) - (car default) - default))) - ": "))) +;;; compat.el + +;; Do not throw an error when not available - assume latest Emacs +;; version (built-in Org). +(require 'compat nil 'noerror) + +;; Provide compatibility macros when we are a part of Emacs. +;; See https://elpa.gnu.org/packages/doc/compat.html#Usage + +(defmacro org-compat-function (fun) + "Return compatibility function symbol for FUN. + +If the Emacs version provides a sufficiently recent version of +FUN, the symbol FUN is returned itself. Otherwise the macro +returns the symbol of a compatibility function which supports the +behavior and calling convention of the current stable Emacs +version. For example Compat 29.1 will provide compatibility +functions which implement the behavior and calling convention of +Emacs 29.1. + +See also `org-compat-call' to directly call compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `#',(if (fboundp compat) compat fun))) + +(defmacro org-compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. + +A good example function is `plist-get' which was extended with an +additional predicate argument in Emacs 29.1. The compatibility +function, which supports this additional argument, can be +obtained via (compat-function plist-get) and called +via (compat-call plist-get plist prop predicate). It is not +possible to directly call (plist-get plist prop predicate) on +Emacs older than 29.1, since the original `plist-get' function +does not yet support the predicate argument. Note that the +Compat library never overrides existing functions. + +See also `org-compat-function' to lookup compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `(,(if (fboundp compat) compat fun) ,@args))) + +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "9.7") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "9.7") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "9.7") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "9.7") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "9.7") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "9.7") +(define-obsolete-function-alias 'org-xor + 'xor "9.7") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "9.7") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "9.7") \f ;;; Emacs < 27.1 compatibility @@ -210,22 +170,6 @@ (if (version< emacs-version "27.1") (replace-buffer-contents source)) (defalias 'org-replace-buffer-contents #'replace-buffer-contents)) -(unless (fboundp 'proper-list-p) - ;; `proper-list-p' was added in Emacs 27.1. The function below is - ;; taken from Emacs subr.el 200195e824b^. - (defun proper-list-p (object) - "Return OBJECT's length if it is a proper list, nil otherwise. -A proper list is neither circular nor dotted (i.e., its last cdr -is nil)." - (and (listp object) (ignore-errors (length object))))) - -(if (fboundp 'xor) - ;; `xor' was added in Emacs 27.1. - (defalias 'org-xor #'xor) - (defsubst org-xor (a b) - "Exclusive `or'." - (if a (not b) b))) - (unless (fboundp 'pcomplete-uniquify-list) ;; The misspelled variant was made obsolete in Emacs 27.1 (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list)) @@ -255,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p) (when (fboundp 'set-face-extend) (mapc (lambda (f) (set-face-extend f extend-p)) faces))) -(if (fboundp 'string-distance) - (defalias 'org-string-distance 'string-distance) - (defun org-string-distance (s1 s2) - "Return the edit (levenshtein) distance between strings S1 S2." - (let* ((l1 (length s1)) - (l2 (length s2)) - (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) - (number-sequence 1 (1+ l1))))) - (in (lambda (i j) (aref (aref dist i) j)))) - (setf (aref (aref dist 0) 0) 0) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist 0) j) j)) - (dolist (i (number-sequence 1 l1)) - (setf (aref (aref dist i) 0) i) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist i) j) - (min - (1+ (funcall in (1- i) j)) - (1+ (funcall in i (1- j))) - (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) - (funcall in (1- i) (1- j))))))) - (funcall in l1 l2)))) - (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance "9.5") @@ -298,23 +219,6 @@ (if (fboundp 'line-number-display-width) (defalias 'org-line-number-display-width 'line-number-display-width) (defun org-line-number-display-width (&rest _) 0)) -(if (fboundp 'buffer-hash) - (defalias 'org-buffer-hash 'buffer-hash) - (defun org-buffer-hash () (md5 (current-buffer)))) - -(unless (fboundp 'file-attribute-modification-time) - (defsubst file-attribute-modification-time (attributes) - "The modification time in ATTRIBUTES returned by `file-attributes'. -This is the time of the last change to the file's contents, and -is a Lisp timestamp in the same style as `current-time'." - (nth 5 attributes))) - -(unless (fboundp 'file-attribute-size) - (defsubst file-attribute-size (attributes) - "The size (in bytes) in ATTRIBUTES returned by `file-attributes'. -This is a floating point number if the size is too large for an integer." - (nth 7 attributes))) - \f ;;; Obsolete aliases (remove them after the next major release). @@ -1416,7 +1320,7 @@ (defun org-mode-flyspell-verify () (and log (let ((drawer (org-element-lineage element '(drawer)))) (and drawer - (org-string-equal-ignore-case + (string-equal-ignore-case log (org-element-property :drawer-name drawer)))))) nil) (t diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 43c6b2b74..c699c115b 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p (lambda (p) (next-single-char-property-change p 'invisible nil limit))))) (next pos)) (while (and (funcall cmp next limit) - (not (org-xor + (not (xor invisible-initially? (funcall invisible-p (if previous-p diff --git a/lisp/org-lint.el b/lisp/org-lint.el index 0e2967b6c..adc893aff 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast) ast 'node-property (lambda (property) - (and (org-string-equal-ignore-case + (and (string-equal-ignore-case "CUSTOM_ID" (org-element-property :key property)) (org-element-property :value property))) (lambda (property _) (org-element-property :begin property)) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index 8e73fbc4b..21c09567f 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -279,12 +279,12 @@ (defgroup org-persist nil (defcustom org-persist-directory (expand-file-name - (org-file-name-concat + (file-name-concat (let ((cache-dir (when (fboundp 'xdg-cache-home) (xdg-cache-home)))) (if (or (seq-empty-p cache-dir) (not (file-exists-p cache-dir)) - (file-exists-p (org-file-name-concat + (file-exists-p (file-name-concat user-emacs-directory "org-persist"))) user-emacs-directory @@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data) (defun org-persist-read:file (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:url (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:index (cont index-file _) "Read index container CONT from INDEX-FILE." @@ -750,7 +750,7 @@ (defun org-persist--load-index () "Load `org-persist--index'." (org-persist-load:index `(index ,org-persist--storage-version) - (org-file-name-concat org-persist-directory org-persist-index-file) + (file-name-concat org-persist-directory org-persist-index-file) nil)) ;;;; Writing container data @@ -804,7 +804,7 @@ (defun org-persist-write:file (c collection) (setq path (cadr c))) (let* ((persist-file (plist-get collection :persist-file)) (ext (file-name-extension path)) - (file-copy (org-file-name-concat + (file-copy (file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) (unless (file-exists-p file-copy) @@ -850,7 +850,7 @@ (defun org-persist-write:index (container _) org-persist-directory)))) (when (file-exists-p org-persist-directory) (let ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file))) + (file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) (org-persist--write-elisp-file index-file org-persist--index t t) (setq org-persist--index-age @@ -865,7 +865,7 @@ (defun org-persist--save-index () (defun org-persist--merge-index-with-disk () "Merge `org-persist--index' with the current index file on disk." (let* ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file)) + (file-name-concat org-persist-directory org-persist-index-file)) (disk-index (and (file-exists-p index-file) (org-file-newer-than-p index-file org-persist--index-age) @@ -887,8 +887,8 @@ (defun org-persist--merge-index (base other) (dolist (item (nreverse new)) (unless (or (memq 'index (mapcar #'car (plist-get item :container))) (not (file-exists-p - (org-file-name-concat org-persist-directory - (plist-get item :persist-file)))) + (file-name-concat org-persist-directory + (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) (nreverse combined)) @@ -989,7 +989,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) (persist-file (when collection - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (data nil)) @@ -1077,7 +1077,7 @@ (defun org-persist-write (container &optional associated ignore-return) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) (when (or (file-exists-p org-persist-directory) (org-persist--save-index)) - (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file))) + (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file))) (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection))) (plist-get collection :container)))) (puthash file data org-persist--write-cache) @@ -1097,11 +1097,11 @@ (defun org-persist-write-all (&optional associated) ;; The container is an `index' container. (eq 'index (caar (plist-get (car org-persist--index) :container))) (or (not (file-exists-p org-persist-directory)) - (org-directory-empty-p org-persist-directory))) + (directory-empty-p org-persist-directory))) ;; Do not write anything, and clear up `org-persist-directory' to reduce ;; clutter. (when (and (file-exists-p org-persist-directory) - (org-directory-empty-p org-persist-directory)) + (directory-empty-p org-persist-directory)) (delete-directory org-persist-directory)) ;; Write the data. (let (all-containers) @@ -1142,7 +1142,7 @@ (defun org-persist--gc-persist-file (persist-file) "Garbage collect PERSIST-FILE." (when (file-exists-p persist-file) (delete-file persist-file) - (when (org-directory-empty-p (file-name-directory persist-file)) + (when (directory-empty-p (file-name-directory persist-file)) (delete-directory (file-name-directory persist-file))))) (defmacro org-persist-associated-files:generic (container collection) @@ -1180,7 +1180,7 @@ (defun org-persist-gc () (let (new-index (remote-files-num 0) (orphan-files - (delete (org-file-name-concat org-persist-directory org-persist-index-file) + (delete (file-name-concat org-persist-directory org-persist-index-file) (when (file-exists-p org-persist-directory) (directory-files-recursively org-persist-directory ".+"))))) (dolist (collection org-persist--index) @@ -1188,7 +1188,7 @@ (defun org-persist-gc () (web-file (and file (string-match-p "\\`https?://" file))) (file-remote (when file (file-remote-p file))) (persist-file (when (plist-get collection :persist-file) - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (expired? (org-persist--gc-expired-p diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 03c351cf6..9797a0633 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes) (prompt (let ((default (or (car org-refile-history) (and (assoc cbnex tbl) (setq cdef cbnex) cbnex)))) - (org-format-prompt prompt default))) + (format-prompt prompt default))) pa answ parent-target child parent old-hist) (setq old-hist org-refile-history) (setq answ (funcall cfunc prompt tbl nil (not new-nodes) diff --git a/lisp/org.el b/lisp/org.el index 10ade32dd..e9fa9a241 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry <bzg@gnu.org> ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) ;; Version: 9.7-pre @@ -19445,7 +19445,7 @@ (defun org-fill-paragraph (&optional justify region) (barf-if-buffer-read-only) (list (when current-prefix-arg 'full) t))) (let ((hash (and (not (buffer-modified-p)) - (org-buffer-hash)))) + (buffer-hash)))) (cond ((and region transient-mark-mode mark-active (not (eq (region-beginning) (region-end)))) @@ -19470,7 +19470,7 @@ (defun org-fill-paragraph (&optional justify region) ;; If we didn't change anything in the buffer (and the buffer was ;; previously unmodified), then flip the modification status back ;; to "unchanged". - (when (and hash (equal hash (org-buffer-hash))) + (when (and hash (equal hash (buffer-hash))) (set-buffer-modified-p nil)) ;; Return non-nil. t)) diff --git a/lisp/ox.el b/lisp/ox.el index a6169ea63..203136994 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4626,11 +4626,11 @@ (defun org-export-resolve-radio-link (link info) Return value can be a radio-target object or nil. Assume LINK has type \"radio\"." - (let ((path (org-string-clean-whitespace (org-element-property :path link)))) + (let ((path (string-clean-whitespace (org-element-property :path link)))) (org-element-map (plist-get info :parse-tree) 'radio-target (lambda (radio) - (and (org-string-equal-ignore-case - (org-string-clean-whitespace (org-element-property :value radio)) + (and (string-equal-ignore-case + (string-clean-whitespace (org-element-property :value radio)) path) radio)) info 'first-match))) diff --git a/mk/default.mk b/mk/default.mk index 997b22b66..4ad1a4281 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -38,7 +38,7 @@ pkgdir = $(shell pwd)/pkg-deps EFLAGS ?= # Third-party packages to install when running make -EPACKAGES ?= +EPACKAGES ?= compat # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el index a38d9f979..565539571 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display () (dotimes (_ 2) (goto-char 1) (re-search-forward "\\[") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "example") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "com") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "\\[") (should-not (org-invisible-p)) (re-search-forward "link") (should-not (org-invisible-p)) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (org-toggle-link-display))))) \f diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 0ed44c6af..6a47b3384 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort () "Test aborting a capture process." ;; Newly create capture buffer should not be saved. (let ((capture-file (make-temp-name - (org-file-name-concat + (file-name-concat temporary-file-directory "org-test")))) (unwind-protect -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-org-manual.org-Document-compat-library-installation.patch --] [-- Type: text/x-patch, Size: 2242 bytes --] From 25047bc1d6c262aae7467723f12d0ed65c2f0e40 Mon Sep 17 00:00:00 2001 Message-Id: <25047bc1d6c262aae7467723f12d0ed65c2f0e40.1680454654.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH 3/6] org-manual.org: Document compat library installation * doc/org-manual.org (Using Org's git repository): Document that users must also install compat library when using git version of Org. * etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to support older Emacs versions): Announce amendments to the Org installation from git sources. --- doc/org-manual.org | 4 ++++ etc/ORG-NEWS | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/doc/org-manual.org b/doc/org-manual.org index 50662669e..aa9886e5f 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -140,6 +140,10 @@ *** Using Org's git repository (add-to-list 'load-path "~/src/org-mode/lisp") #+end_src +You must also manually install =compat= library required by Org mode. +Using built-in =package.el=, you can run =M-x package-install <RET> +compat <RET>=. + You can also compile with =make=, generate the documentation with =make doc=, create a local configuration with =make config= and install Org with =make install=. Please run =make help= to get the diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ac233a986..0302b8cda 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Org mode now uses =compat.el= third-party package to support older Emacs versions + +This change is mostly technical and should not affect most users. +However, people who install Org from git source might be affected. +It is now necessary to manually install =compat.el= using Emacs' +package manager. + *** =python-mode.el (MELPA)= support in =ob-python.el= is removed =python-mode.el= support has been removed from =ob-python.el=. The -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-mk-Expand-shell-commands-once-only.patch --] [-- Type: text/x-patch, Size: 2303 bytes --] From 1515712e093137fe9642c7f1e2ebc0fc71119740 Mon Sep 17 00:00:00 2001 Message-Id: <1515712e093137fe9642c7f1e2ebc0fc71119740.1680454654.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 13:53:47 +0200 Subject: [PATCH 4/6] mk: Expand shell commands once only * mk/default.mk (pkgdir): * mk/targets.mk (GITVERSION): (GITSTATUS): (DATE): (YEAR): Only expand the variables once, not in every make sub-process. Previous code ran pwd/date/git in every make sub-process, slowing things down significantly and unnecessarily. --- mk/default.mk | 2 +- mk/targets.mk | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mk/default.mk b/mk/default.mk index 4ad1a4281..b43a9b3ac 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -32,7 +32,7 @@ TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest # Where to store Org dependencies -pkgdir = $(shell pwd)/pkg-deps +pkgdir := $(shell pwd)/pkg-deps # Extra flags to be passed to Emacs EFLAGS ?= diff --git a/mk/targets.mk b/mk/targets.mk index ab8b830bb..18faa02f5 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -14,15 +14,15 @@ ifneq ($(wildcard .git),) # Use the org.el header. ORGVERSION := $(patsubst %-dev,%,$(shell $(BATCH) --eval "(require 'lisp-mnt)" \ --visit lisp/org.el --eval '(princ (lm-header "version"))')) - GITVERSION ?= $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)") - GITSTATUS ?= $(shell git status -uno --porcelain) + GITVERSION := $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)") + GITSTATUS := $(shell git status -uno --porcelain) else -include mk/version.mk GITVERSION ?= N/A ORGVERSION ?= N/A endif -DATE = $(shell date +%Y-%m-%d) -YEAR = $(shell date +%Y) +DATE := $(shell date +%Y-%m-%d) +YEAR := $(shell date +%Y) ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-mk-Echo-main-compilation-states-when-running-make.patch --] [-- Type: text/x-patch, Size: 2268 bytes --] From 14140c127e5b44dd6f8aa76b5f6c946d77610939 Mon Sep 17 00:00:00 2001 Message-Id: <14140c127e5b44dd6f8aa76b5f6c946d77610939.1680454654.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 14:05:22 +0200 Subject: [PATCH 5/6] mk: Echo main compilation states when running make * lisp/Makefile (all compile compile-dirty): ($(LISPV)): ($(LISPI)): Echo compile stage. * mk/targets.mk (uppkg): Echo compile stage and hide the installation command. --- lisp/Makefile | 7 +++++-- mk/targets.mk | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lisp/Makefile b/lisp/Makefile index f507f18a2..45d8109f0 100644 --- a/lisp/Makefile +++ b/lisp/Makefile @@ -20,6 +20,7 @@ _ORGCM_ := dirall single source slint1 slint2 # do not clean here, done in toplevel make all compile compile-dirty:: autoloads + @$(info ========= Compiling lisp files using '$(ORGCM)' target) ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),) $(MAKE) compile-$(ORGCM) else @@ -52,12 +53,14 @@ slint1: autoloads: cleanauto $(LISPI) $(LISPV) $(LISPV): $(LISPF) - @echo "org-version: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org version number) + @$(info org-version: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_VERSION) $(LISPI): $(LISPV) $(LISPF) - @echo "org-loaddefs: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org loaddefs) + @$(info org-loaddefs: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_INSTALL) diff --git a/mk/targets.mk b/mk/targets.mk index 18faa02f5..072106237 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -103,9 +103,10 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f endif uppkg:: - -$(MKDIR) -p $(pkgdir) - -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + - $(INSTALL_PACKAGES) + $(info ========= Installing required third-party packages) + @$(MKDIR) -p $(pkgdir) + @$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + + -@$(INSTALL_PACKAGES) up0 up1 up2:: git checkout $(GIT_BRANCH) -- 2.39.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-mk-Do-not-run-package-refresh-packages-unless-necess.patch --] [-- Type: text/x-patch, Size: 2322 bytes --] From dcb8bc6ba68834da94cef9006e6889c75e89f67a Mon Sep 17 00:00:00 2001 Message-Id: <dcb8bc6ba68834da94cef9006e6889c75e89f67a.1680454654.git.yantar92@posteo.net> In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680454654.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 15:11:06 +0200 Subject: [PATCH 6/6] mk: Do not run `package-refresh-packages' unless necessary * mk/default.mk (package-install): (package-define-refresh-mark): (package-need-refresh-mark): (package-refresh-maybe): (package-install-maybe): (INSTALL_PACKAGES): Update the command avoiding `package-refresh-packages' when all the required third-party packages are already present in the `load-path'. --- mk/default.mk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mk/default.mk b/mk/default.mk index b43a9b3ac..67bf96c2e 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -81,7 +81,10 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' -package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' +package-define-refresh-mark = --eval '(setq org--compile-packages-missing nil)' +package-need-refresh-mark = --eval '(unless (require '"'"'$(package) nil t) (setq org--compile-packages-missing t))' +package-refresh-maybe = --eval '(if org--compile-packages-missing (package-refresh-contents) (message "No third-party packages need to be installed"))' +package-install-maybe = --eval '(unless (require '"'"'$(package) nil t) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ @@ -93,8 +96,8 @@ INSTALL_PACKAGES = else INSTALL_PACKAGES = \ $(BATCH) \ - --eval '(package-refresh-contents)' \ - $(foreach package,$(EPACKAGES),$(package-install)) + $(package-define-refresh-mark) $(foreach package,$(EPACKAGES),$(package-need-refresh-mark)) $(package-refresh-maybe) \ + $(foreach package,$(EPACKAGES),$(package-install-maybe)) endif BTEST = $(BATCH) $(BTEST_INIT) \ -- 2.39.1 [-- Attachment #8: Type: text/plain, Size: 224 bytes --] -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-02 17:00 ` [PATCH v2] " Ihor Radchenko @ 2023-04-03 8:46 ` Ihor Radchenko 2023-04-08 11:15 ` [PATCH v2] " Max Nikulin 1 sibling, 0 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-04-03 8:46 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 692 bytes --] Ihor Radchenko <yantar92@posteo.net> writes: >> It would be easier to review if this patch was split into 2 parts: >> - add compat.el dependency (unused) >> - replace functions to ones from compat.el > > Sure, but after spending half an hour trying to decouple this part, I > gave up and decided to leave it as is. And there is nothing fancy in > adding compat dependency in 2/3 patch anyway. Just one (require 'compat > nil t), two macro definitions adviced by compat manual (copy-paste from > compat code), and adding compat to EPACKAGES in makefiles. After more fiddling with interactive rebase, I managed to split the patch further. See the attached. Hope it is easier to review now. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Upgrade-Org-build-system-to-handle-third-party-depen.patch --] [-- Type: text/x-patch, Size: 6381 bytes --] From 313f2b6acdf67f29f4f5f671e8278bb3e566cabf Mon Sep 17 00:00:00 2001 Message-Id: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH 1/7] Upgrade Org build system to handle third-party dependencies * mk/default.mk (pkgdir): New variable holding the location of third-party packages to be downloaded if necessary during compilation. (EFLAGS): New variable holding extra flags to be passed to Emacs executable when running make. (EPACKAGES): List of packages to be installed (unless already present in the `load-path') during compilation. (package-install): (INSTALL_PACKAGES): New command to download and install missing packages. (BATCH): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (check test): (compile compile-dirty): Use the new uppkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_BASE): (CONF_DEST): (CONF_CALL): Update according to the new variables and targets. * .gitignore: Ignore the downloaded packages. This commit paves the way towards third-party built-time dependencies for Org. In particular, towards including compat.el dependency. According to EPACKAGES, we can auto-download necessary packages, unless they are manually specified via -L switches in EFLAGS. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 1 + mk/default.mk | 24 +++++++++++++++++++++++- mk/targets.mk | 24 ++++++++++++++++-------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 4bb81c359..0d9c5b297 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ local*.mk .gitattributes mk/x11idle ChangeLog +pkg-deps/ # Files generated during `make packages/org` in a clone of `elpa.git`. diff --git a/mk/default.mk b/mk/default.mk index fa46661e8..997b22b66 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -31,6 +31,15 @@ GIT_BRANCH = TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest +# Where to store Org dependencies +pkgdir = $(shell pwd)/pkg-deps + +# Extra flags to be passed to Emacs +EFLAGS ?= + +# Third-party packages to install when running make +EPACKAGES ?= + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -72,12 +81,22 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' +package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ --eval '(add-to-list '"'"'load-path (concat default-directory "testing"))' BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST) +ifeq (,$(EPACKAGES)) +INSTALL_PACKAGES = +else +INSTALL_PACKAGES = \ + $(BATCH) \ + --eval '(package-refresh-contents)' \ + $(foreach package,$(EPACKAGES),$(package-install)) +endif + BTEST = $(BATCH) $(BTEST_INIT) \ -l org-batch-test-init \ --eval '(setq \ @@ -120,7 +139,10 @@ EMACSQ = $(EMACS) -Q # Using emacs in batch mode. BATCH = $(EMACSQ) -batch \ - --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' + $(EFLAGS) \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)' # Emacs must be started in toplevel directory BATCHO = $(BATCH) \ diff --git a/mk/targets.mk b/mk/targets.mk index 0bd293d68..ab8b830bb 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \ check test install $(INSTSUB) \ info html pdf card refcard doc docs \ autoloads cleanall clean $(CLEANDIRS:%=clean%) \ clean-install cleanelc cleandirs \ - cleanlisp cleandoc cleandocs cleantest \ + cleanlisp cleandoc cleandocs cleantest cleanpkg \ compile compile-dirty uncompiled \ config config-test config-exe config-all config-eol config-version \ vanilla repro -CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC -CONF_DEST = lispdir infodir datadir testdir +CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES +CONF_DEST = lispdir infodir datadir testdir pkgdir CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO -CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION +CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION config-eol:: EOL = \# config-eol:: config-all config config-all:: @@ -86,7 +86,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: uppkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -94,7 +94,7 @@ all clean-install:: vanilla: -@$(NOBATCH) & -check test:: compile +check test:: uppkg compile check test test-dirty:: -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) @@ -102,6 +102,11 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f $(MAKE) cleantest endif +uppkg:: + -$(MKDIR) -p $(pkgdir) + -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + + $(INSTALL_PACKAGES) + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -134,7 +139,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest +cleanall: cleandirs cleantest cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -159,3 +164,6 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: + -$(RMR) $(pkgdir) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-org-compat-Enable-compat.el.patch --] [-- Type: text/x-patch, Size: 3395 bytes --] From 68fb497e93d717df60d26c1e1fb5547e9f972cac Mon Sep 17 00:00:00 2001 Message-Id: <68fb497e93d717df60d26c1e1fb5547e9f972cac.1680511418.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Mon, 3 Apr 2023 10:40:00 +0200 Subject: [PATCH 2/7] org-compat: Enable compat.el * lisp/org-compat.el (compat): Load Compat library, when available. (org-compat-function): (org-compat-call): Add compatibility macros available even when Compat is not available (Org is a part of Emacs). * lisp/org.el: Add Compat to package-requires. --- lisp/org-compat.el | 42 ++++++++++++++++++++++++++++++++++++++++++ lisp/org.el | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index c47a4e8c2..e5b22d623 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -94,6 +94,48 @@ (defvar org-table-tab-recognizes-table.el) (defvar org-table1-hline-regexp) (defvar org-fold-core-style) +\f +;;; compat.el + +;; Do not throw an error when not available - assume latest Emacs +;; version (built-in Org). +(require 'compat nil 'noerror) + +;; Provide compatibility macros when we are a part of Emacs. +;; See https://elpa.gnu.org/packages/doc/compat.html#Usage + +(defmacro org-compat-function (fun) + "Return compatibility function symbol for FUN. + +If the Emacs version provides a sufficiently recent version of +FUN, the symbol FUN is returned itself. Otherwise the macro +returns the symbol of a compatibility function which supports the +behavior and calling convention of the current stable Emacs +version. For example Compat 29.1 will provide compatibility +functions which implement the behavior and calling convention of +Emacs 29.1. + +See also `org-compat-call' to directly call compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `#',(if (fboundp compat) compat fun))) + +(defmacro org-compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. + +A good example function is `plist-get' which was extended with an +additional predicate argument in Emacs 29.1. The compatibility +function, which supports this additional argument, can be +obtained via (compat-function plist-get) and called +via (compat-call plist-get plist prop predicate). It is not +possible to directly call (plist-get plist prop predicate) on +Emacs older than 29.1, since the original `plist-get' function +does not yet support the predicate argument. Note that the +Compat library never overrides existing functions. + +See also `org-compat-function' to lookup compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `(,(if (fboundp compat) compat fun) ,@args))) + \f ;;; Emacs < 29 compatibility diff --git a/lisp/org.el b/lisp/org.el index 10ade32dd..5e52608ca 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry <bzg@gnu.org> ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) ;; Version: 9.7-pre -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Use-compat.el-library-instead-of-ad-hoc-compatibilit.patch --] [-- Type: text/x-patch, Size: 33408 bytes --] From 88888d4bc18da596a68698082789bc9ba3eb9ff3 Mon Sep 17 00:00:00 2001 Message-Id: <88888d4bc18da596a68698082789bc9ba3eb9ff3.1680511419.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Mon, 3 Apr 2023 10:41:50 +0200 Subject: [PATCH 3/7] Use compat.el library instead of ad-hoc compatibility function set * mk/default.mk (EPACKAGES): Demand compat library during compile time. * lisp/org.el (org-fill-paragraph): * lisp/org-compat.el: Obsolete org-* compatibility functions that are already available in compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case', `org-file-name-concat', `org-directory-empty-p', `org-string-clean-whitespace', `org-format-prompt', `org-xor', `org-string-distance', `org-buffer-hash'. * lisp/ob-core.el (org-babel-results-keyword): Use functions provided by compat.el. (org-babel-insert-result): * lisp/oc-basic.el (org-cite-basic--parse-bibliography): * lisp/oc.el (org-cite-adjust-note): * lisp/ol-gnus.el (org-gnus-group-link): (org-gnus-article-link): (org-gnus-store-link): * lisp/ol.el: (org-store-link): * lisp/org-attach.el: * lisp/org-capture.el: (org-capture-fill-template): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el: * lisp/org-persist.el (org-persist-directory): (org-persist-read:file): (org-persist-read:url): (org-persist--load-index): (org-persist-write:file): (org-persist-write:index): (org-persist--merge-index-with-disk): (org-persist-read): (org-persist-write): (org-persist-write-all): (org-persist--gc-persist-file): (org-persist-gc): * lisp/org-refile.el (org-refile-get-location): * lisp/ox.el (org-export-resolve-radio-link): * testing/lisp/test-ol.el (test-org-link/toggle-link-display): * testing/lisp/test-org-capture.el (test-org-capture/abort): Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- lisp/ob-core.el | 10 +- lisp/oc-basic.el | 6 +- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +- lisp/ol.el | 4 +- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +- lisp/org-compat.el | 180 ++++--------------------------- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-persist.el | 38 +++---- lisp/org-refile.el | 2 +- lisp/org.el | 4 +- lisp/ox.el | 6 +- mk/default.mk | 2 +- testing/lisp/test-ol.el | 10 +- testing/lisp/test-org-capture.el | 2 +- 17 files changed, 75 insertions(+), 213 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 471887a3a..4ef1f2084 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS" :type 'string :safe (lambda (v) (and (stringp v) - (org-string-equal-ignore-case "RESULTS" v)))) + (string-equal-ignore-case "RESULTS" v)))) (defcustom org-babel-noweb-wrap-start "<<" "String used to begin a noweb reference in a code block. @@ -927,7 +927,7 @@ (defun org-babel-check-src-block () (match-string 4)))))) (dolist (name names) (when (and (not (string= header name)) - (<= (org-string-distance header name) too-close) + (<= (string-distance header name) too-close) (not (member header names))) (error "Supplied header \"%S\" is suspiciously close to \"%S\"" header name)))) @@ -2518,7 +2518,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex ;; Escape contents from "export" wrap. Wrap ;; inline results within an export snippet with ;; appropriate value. - ((org-string-equal-ignore-case type "export") + ((string-equal-ignore-case type "export") (let ((backend (pcase split (`(,_) "none") (`(,_ ,b . ,_) b)))) @@ -2529,14 +2529,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex backend) "@@)}}}"))) ;; Escape contents from "example" wrap. Mark ;; inline results as verbatim. - ((org-string-equal-ignore-case type "example") + ((string-equal-ignore-case type "example") (funcall wrap opening-line closing-line nil nil "{{{results(=" "=)}}}")) ;; Escape contents from "src" wrap. Mark ;; inline results as inline source code. - ((org-string-equal-ignore-case type "src") + ((string-equal-ignore-case type "src") (let ((inline-open (pcase split (`(,_) diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index 12b627e71..1c86f344a 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info) (dolist (file (org-cite-list-bibliography-files)) (when (file-readable-p file) (with-temp-buffer - (when (or (org-file-has-changed-p file) + (when (or (file-has-changed-p file) (not (gethash file org-cite-basic--file-id-cache))) (insert-file-contents file) (set-visited-file-name file t) - (puthash file (org-buffer-hash) org-cite-basic--file-id-cache)) + (puthash file (buffer-hash) org-cite-basic--file-id-cache)) (condition-case nil (unwind-protect (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache))) @@ -488,7 +488,7 @@ (defun org-cite-basic--close-keys (key keys) "List cite keys close to KEY in terms of string distance." (seq-filter (lambda (k) (>= org-cite-basic-max-key-distance - (org-string-distance k key))) + (string-distance k key))) keys)) (defun org-cite-basic--set-keymap (beg end suggestions) diff --git a/lisp/oc.el b/lisp/oc.el index dde6f3a32..f39ae848b 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct) (match-string 3 previous))))) ;; Bail you when there is no quote and either no punctuation, or ;; punctuation on both sides. - (when (or quote (org-xor punct final-punct)) + (when (or quote (xor punct final-punct)) ;; Phase 1: handle punctuation rule. (pcase rule ((guard (not quote)) nil) diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el index 7c07ce045..e121cfba3 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -98,8 +98,8 @@ (defun org-gnus-group-link (group) `org-gnus-prefer-web-links' is reversed." (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group))) (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups - (org-xor current-prefix-arg - org-gnus-prefer-web-links)) + (xor current-prefix-arg + org-gnus-prefer-web-links)) (concat "https://groups.google.com/group/" unprefixed-group) (concat "gnus:" group)))) @@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive) If `org-store-link' was called with a prefix arg the meaning of `org-gnus-prefer-web-links' is reversed." - (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links) + (if (and (xor current-prefix-arg org-gnus-prefer-web-links) newsgroups ;make web links only for nntp groups (not x-no-archive)) ;and if X-No-Archive isn't set (format "https://groups.google.com/groups/search?as_umsgid=%s" @@ -169,7 +169,7 @@ (defun org-gnus-store-link () newsgroups x-no-archive) ;; Fetching an article is an expensive operation; newsgroup and ;; x-no-archive are only needed for web links. - (when (org-xor current-prefix-arg org-gnus-prefer-web-links) + (when (xor current-prefix-arg org-gnus-prefer-web-links) ;; Make sure the original article buffer is up-to-date. (save-window-excursion (gnus-summary-select-article)) (setq to (or to (gnus-fetch-original-field "To"))) diff --git a/lisp/ol.el b/lisp/ol.el index 9e4781f6e..3d62a6fa0 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let* ((element (org-element-at-point)) (name (org-element-property :name element)) (context @@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let ((context (org-link--normalize-string (or (org-link--context-from-region) (org-current-line-string)) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 8d01eda71..5cc40873c 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -674,7 +674,7 @@ (defun org-attach-sync () (let ((files (org-attach-file-list attach-dir))) (org-attach-tag (not files))) (when org-attach-sync-delete-empty-dir - (when (and (org-directory-empty-p attach-dir) + (when (and (directory-empty-p attach-dir) (if (eq 'query org-attach-sync-delete-empty-dir) (yes-or-no-p "Attachment directory is empty. Delete?") t)) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index b96e9f336..c5b1c6d50 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1323,9 +1323,9 @@ (defun org-capture-place-item () ;; prioritize the existing list. (when prepend? (let ((ordered? (eq 'ordered (org-element-property :type item)))) - (when (org-xor ordered? - (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" - template)) + (when (xor ordered? + (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" + template)) (org-cycle-list-bullet (if ordered? "1." "-"))))) ;; Eventually repair the list for proper indentation and ;; bullets. @@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation) (setq org-capture--prompt-history (gethash prompt org-capture--prompt-history-table)) (push (org-completing-read - (org-format-prompt (or prompt "Enter string") default) + (format-prompt (or prompt "Enter string") default) completions nil nil nil 'org-capture--prompt-history default) strings) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index e5b22d623..046a3db97 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec)) (declare-function org-fold-show-all "org-fold" (&optional types)) (declare-function org-fold-show-children "org-fold" (&optional level)) (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers)) -;; `org-string-equal-ignore-case' is in _this_ file but isn't at the -;; top-level. -(declare-function org-string-equal-ignore-case "org-compat" (string1 string2)) (defvar calendar-mode-map) (defvar org-complex-heading-regexp) @@ -136,105 +133,26 @@ (defmacro org-compat-call (fun &rest args) (let ((compat (intern (format "compat--%s" fun)))) `(,(if (fboundp compat) compat fun) ,@args))) -\f -;;; Emacs < 29 compatibility - -(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal) - "Internal variable used by `org-file-has-changed-p'.") - -(if (fboundp 'file-has-changed-p) - (defalias 'org-file-has-changed-p #'file-has-changed-p) - (defun org-file-has-changed-p (file &optional tag) - "Return non-nil if FILE has changed. -The size and modification time of FILE are compared to the size -and modification time of the same FILE during a previous -invocation of `org-file-has-changed-p'. Thus, the first invocation -of `org-file-has-changed-p' always returns non-nil when FILE exists. -The optional argument TAG, which must be a symbol, can be used to -limit the comparison to invocations with identical tags; it can be -the symbol of the calling function, for example." - (let* ((file (directory-file-name (expand-file-name file))) - (remote-file-name-inhibit-cache t) - (fileattr (file-attributes file 'integer)) - (attr (and fileattr - (cons (file-attribute-size fileattr) - (file-attribute-modification-time fileattr)))) - (sym (concat (symbol-name tag) "@" file)) - (cachedattr (gethash sym org-file-has-changed-p--hash-table))) - (when (not (equal attr cachedattr)) - (puthash sym attr org-file-has-changed-p--hash-table))))) - -(if (fboundp 'string-equal-ignore-case) - (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case) - ;; From Emacs subr.el. - (defun org-string-equal-ignore-case (string1 string2) - "Like `string-equal', but case-insensitive. -Upper-case and lower-case letters are treated as equal. -Unibyte strings are converted to multibyte for comparison." - (eq t (compare-strings string1 0 nil string2 0 nil t)))) - -\f -;;; Emacs < 28.1 compatibility - -(if (fboundp 'file-name-concat) - (defalias 'org-file-name-concat #'file-name-concat) - (defun org-file-name-concat (directory &rest components) - "Append COMPONENTS to DIRECTORY and return the resulting string. - -Elements in COMPONENTS must be a string or nil. -DIRECTORY or the non-final elements in COMPONENTS may or may not end -with a slash -- if they don't end with a slash, a slash will be -inserted before contatenating." - (save-match-data - (mapconcat - #'identity - (delq nil - (mapcar - (lambda (str) - (when (and str (not (seq-empty-p str)) - (string-match "\\(.+\\)/?" str)) - (match-string 1 str))) - (cons directory components))) - "/")))) - -(if (fboundp 'directory-empty-p) - (defalias 'org-directory-empty-p #'directory-empty-p) - (defun org-directory-empty-p (dir) - "Return t if DIR names an existing directory containing no other files." - (and (file-directory-p dir) - (null (directory-files dir nil directory-files-no-dot-files-regexp t))))) - -(if (fboundp 'string-clean-whitespace) - (defalias 'org-string-clean-whitespace #'string-clean-whitespace) - ;; From Emacs subr-x.el. - (defun org-string-clean-whitespace (string) - "Clean up whitespace in STRING. -All sequences of whitespaces in STRING are collapsed into a -single space character, and leading/trailing whitespace is -removed." - (let ((blank "[[:blank:]\r\n]+")) - (string-trim (replace-regexp-in-string blank " " string t t) - blank blank)))) - -(if (fboundp 'format-prompt) - (defalias 'org-format-prompt #'format-prompt) - ;; From Emacs minibuffer.el, inlining - ;; `minibuffer-default-prompt-format' value and replacing `length<' - ;; (both new in Emacs 28.1). - (defun org-format-prompt (prompt default &rest format-args) - "Compatibility substitute for `format-prompt'." - (concat - (if (null format-args) - prompt - (apply #'format prompt format-args)) - (and default - (or (not (stringp default)) - (> (length default) 0)) - (format " (default %s)" - (if (consp default) - (car default) - default))) - ": "))) +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "9.7") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "9.7") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "9.7") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "9.7") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "9.7") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "9.7") +(define-obsolete-function-alias 'org-xor + 'xor "9.7") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "9.7") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "9.7") \f ;;; Emacs < 27.1 compatibility @@ -252,22 +170,6 @@ (if (version< emacs-version "27.1") (replace-buffer-contents source)) (defalias 'org-replace-buffer-contents #'replace-buffer-contents)) -(unless (fboundp 'proper-list-p) - ;; `proper-list-p' was added in Emacs 27.1. The function below is - ;; taken from Emacs subr.el 200195e824b^. - (defun proper-list-p (object) - "Return OBJECT's length if it is a proper list, nil otherwise. -A proper list is neither circular nor dotted (i.e., its last cdr -is nil)." - (and (listp object) (ignore-errors (length object))))) - -(if (fboundp 'xor) - ;; `xor' was added in Emacs 27.1. - (defalias 'org-xor #'xor) - (defsubst org-xor (a b) - "Exclusive `or'." - (if a (not b) b))) - (unless (fboundp 'pcomplete-uniquify-list) ;; The misspelled variant was made obsolete in Emacs 27.1 (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list)) @@ -297,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p) (when (fboundp 'set-face-extend) (mapc (lambda (f) (set-face-extend f extend-p)) faces))) -(if (fboundp 'string-distance) - (defalias 'org-string-distance 'string-distance) - (defun org-string-distance (s1 s2) - "Return the edit (levenshtein) distance between strings S1 S2." - (let* ((l1 (length s1)) - (l2 (length s2)) - (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) - (number-sequence 1 (1+ l1))))) - (in (lambda (i j) (aref (aref dist i) j)))) - (setf (aref (aref dist 0) 0) 0) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist 0) j) j)) - (dolist (i (number-sequence 1 l1)) - (setf (aref (aref dist i) 0) i) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist i) j) - (min - (1+ (funcall in (1- i) j)) - (1+ (funcall in i (1- j))) - (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) - (funcall in (1- i) (1- j))))))) - (funcall in l1 l2)))) - (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance "9.5") @@ -340,23 +219,6 @@ (if (fboundp 'line-number-display-width) (defalias 'org-line-number-display-width 'line-number-display-width) (defun org-line-number-display-width (&rest _) 0)) -(if (fboundp 'buffer-hash) - (defalias 'org-buffer-hash 'buffer-hash) - (defun org-buffer-hash () (md5 (current-buffer)))) - -(unless (fboundp 'file-attribute-modification-time) - (defsubst file-attribute-modification-time (attributes) - "The modification time in ATTRIBUTES returned by `file-attributes'. -This is the time of the last change to the file's contents, and -is a Lisp timestamp in the same style as `current-time'." - (nth 5 attributes))) - -(unless (fboundp 'file-attribute-size) - (defsubst file-attribute-size (attributes) - "The size (in bytes) in ATTRIBUTES returned by `file-attributes'. -This is a floating point number if the size is too large for an integer." - (nth 7 attributes))) - \f ;;; Obsolete aliases (remove them after the next major release). @@ -1458,7 +1320,7 @@ (defun org-mode-flyspell-verify () (and log (let ((drawer (org-element-lineage element '(drawer)))) (and drawer - (org-string-equal-ignore-case + (string-equal-ignore-case log (org-element-property :drawer-name drawer)))))) nil) (t diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 43c6b2b74..c699c115b 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p (lambda (p) (next-single-char-property-change p 'invisible nil limit))))) (next pos)) (while (and (funcall cmp next limit) - (not (org-xor + (not (xor invisible-initially? (funcall invisible-p (if previous-p diff --git a/lisp/org-lint.el b/lisp/org-lint.el index 0e2967b6c..adc893aff 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast) ast 'node-property (lambda (property) - (and (org-string-equal-ignore-case + (and (string-equal-ignore-case "CUSTOM_ID" (org-element-property :key property)) (org-element-property :value property))) (lambda (property _) (org-element-property :begin property)) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index 8e73fbc4b..21c09567f 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -279,12 +279,12 @@ (defgroup org-persist nil (defcustom org-persist-directory (expand-file-name - (org-file-name-concat + (file-name-concat (let ((cache-dir (when (fboundp 'xdg-cache-home) (xdg-cache-home)))) (if (or (seq-empty-p cache-dir) (not (file-exists-p cache-dir)) - (file-exists-p (org-file-name-concat + (file-exists-p (file-name-concat user-emacs-directory "org-persist"))) user-emacs-directory @@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data) (defun org-persist-read:file (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:url (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:index (cont index-file _) "Read index container CONT from INDEX-FILE." @@ -750,7 +750,7 @@ (defun org-persist--load-index () "Load `org-persist--index'." (org-persist-load:index `(index ,org-persist--storage-version) - (org-file-name-concat org-persist-directory org-persist-index-file) + (file-name-concat org-persist-directory org-persist-index-file) nil)) ;;;; Writing container data @@ -804,7 +804,7 @@ (defun org-persist-write:file (c collection) (setq path (cadr c))) (let* ((persist-file (plist-get collection :persist-file)) (ext (file-name-extension path)) - (file-copy (org-file-name-concat + (file-copy (file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) (unless (file-exists-p file-copy) @@ -850,7 +850,7 @@ (defun org-persist-write:index (container _) org-persist-directory)))) (when (file-exists-p org-persist-directory) (let ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file))) + (file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) (org-persist--write-elisp-file index-file org-persist--index t t) (setq org-persist--index-age @@ -865,7 +865,7 @@ (defun org-persist--save-index () (defun org-persist--merge-index-with-disk () "Merge `org-persist--index' with the current index file on disk." (let* ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file)) + (file-name-concat org-persist-directory org-persist-index-file)) (disk-index (and (file-exists-p index-file) (org-file-newer-than-p index-file org-persist--index-age) @@ -887,8 +887,8 @@ (defun org-persist--merge-index (base other) (dolist (item (nreverse new)) (unless (or (memq 'index (mapcar #'car (plist-get item :container))) (not (file-exists-p - (org-file-name-concat org-persist-directory - (plist-get item :persist-file)))) + (file-name-concat org-persist-directory + (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) (nreverse combined)) @@ -989,7 +989,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) (persist-file (when collection - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (data nil)) @@ -1077,7 +1077,7 @@ (defun org-persist-write (container &optional associated ignore-return) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) (when (or (file-exists-p org-persist-directory) (org-persist--save-index)) - (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file))) + (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file))) (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection))) (plist-get collection :container)))) (puthash file data org-persist--write-cache) @@ -1097,11 +1097,11 @@ (defun org-persist-write-all (&optional associated) ;; The container is an `index' container. (eq 'index (caar (plist-get (car org-persist--index) :container))) (or (not (file-exists-p org-persist-directory)) - (org-directory-empty-p org-persist-directory))) + (directory-empty-p org-persist-directory))) ;; Do not write anything, and clear up `org-persist-directory' to reduce ;; clutter. (when (and (file-exists-p org-persist-directory) - (org-directory-empty-p org-persist-directory)) + (directory-empty-p org-persist-directory)) (delete-directory org-persist-directory)) ;; Write the data. (let (all-containers) @@ -1142,7 +1142,7 @@ (defun org-persist--gc-persist-file (persist-file) "Garbage collect PERSIST-FILE." (when (file-exists-p persist-file) (delete-file persist-file) - (when (org-directory-empty-p (file-name-directory persist-file)) + (when (directory-empty-p (file-name-directory persist-file)) (delete-directory (file-name-directory persist-file))))) (defmacro org-persist-associated-files:generic (container collection) @@ -1180,7 +1180,7 @@ (defun org-persist-gc () (let (new-index (remote-files-num 0) (orphan-files - (delete (org-file-name-concat org-persist-directory org-persist-index-file) + (delete (file-name-concat org-persist-directory org-persist-index-file) (when (file-exists-p org-persist-directory) (directory-files-recursively org-persist-directory ".+"))))) (dolist (collection org-persist--index) @@ -1188,7 +1188,7 @@ (defun org-persist-gc () (web-file (and file (string-match-p "\\`https?://" file))) (file-remote (when file (file-remote-p file))) (persist-file (when (plist-get collection :persist-file) - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (expired? (org-persist--gc-expired-p diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 03c351cf6..9797a0633 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes) (prompt (let ((default (or (car org-refile-history) (and (assoc cbnex tbl) (setq cdef cbnex) cbnex)))) - (org-format-prompt prompt default))) + (format-prompt prompt default))) pa answ parent-target child parent old-hist) (setq old-hist org-refile-history) (setq answ (funcall cfunc prompt tbl nil (not new-nodes) diff --git a/lisp/org.el b/lisp/org.el index 5e52608ca..e9fa9a241 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -19445,7 +19445,7 @@ (defun org-fill-paragraph (&optional justify region) (barf-if-buffer-read-only) (list (when current-prefix-arg 'full) t))) (let ((hash (and (not (buffer-modified-p)) - (org-buffer-hash)))) + (buffer-hash)))) (cond ((and region transient-mark-mode mark-active (not (eq (region-beginning) (region-end)))) @@ -19470,7 +19470,7 @@ (defun org-fill-paragraph (&optional justify region) ;; If we didn't change anything in the buffer (and the buffer was ;; previously unmodified), then flip the modification status back ;; to "unchanged". - (when (and hash (equal hash (org-buffer-hash))) + (when (and hash (equal hash (buffer-hash))) (set-buffer-modified-p nil)) ;; Return non-nil. t)) diff --git a/lisp/ox.el b/lisp/ox.el index a6169ea63..203136994 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4626,11 +4626,11 @@ (defun org-export-resolve-radio-link (link info) Return value can be a radio-target object or nil. Assume LINK has type \"radio\"." - (let ((path (org-string-clean-whitespace (org-element-property :path link)))) + (let ((path (string-clean-whitespace (org-element-property :path link)))) (org-element-map (plist-get info :parse-tree) 'radio-target (lambda (radio) - (and (org-string-equal-ignore-case - (org-string-clean-whitespace (org-element-property :value radio)) + (and (string-equal-ignore-case + (string-clean-whitespace (org-element-property :value radio)) path) radio)) info 'first-match))) diff --git a/mk/default.mk b/mk/default.mk index 997b22b66..4ad1a4281 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -38,7 +38,7 @@ pkgdir = $(shell pwd)/pkg-deps EFLAGS ?= # Third-party packages to install when running make -EPACKAGES ?= +EPACKAGES ?= compat # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el index a38d9f979..565539571 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display () (dotimes (_ 2) (goto-char 1) (re-search-forward "\\[") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "example") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "com") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "\\[") (should-not (org-invisible-p)) (re-search-forward "link") (should-not (org-invisible-p)) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (org-toggle-link-display))))) \f diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 0ed44c6af..6a47b3384 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort () "Test aborting a capture process." ;; Newly create capture buffer should not be saved. (let ((capture-file (make-temp-name - (org-file-name-concat + (file-name-concat temporary-file-directory "org-test")))) (unwind-protect -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-org-manual.org-Document-compat-library-installation.patch --] [-- Type: text/x-patch, Size: 2242 bytes --] From a5a5f3b14ce81279c6ba8d9bad2a58c83ab88ac4 Mon Sep 17 00:00:00 2001 Message-Id: <a5a5f3b14ce81279c6ba8d9bad2a58c83ab88ac4.1680511419.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH 4/7] org-manual.org: Document compat library installation * doc/org-manual.org (Using Org's git repository): Document that users must also install compat library when using git version of Org. * etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to support older Emacs versions): Announce amendments to the Org installation from git sources. --- doc/org-manual.org | 4 ++++ etc/ORG-NEWS | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/doc/org-manual.org b/doc/org-manual.org index 50662669e..aa9886e5f 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -140,6 +140,10 @@ *** Using Org's git repository (add-to-list 'load-path "~/src/org-mode/lisp") #+end_src +You must also manually install =compat= library required by Org mode. +Using built-in =package.el=, you can run =M-x package-install <RET> +compat <RET>=. + You can also compile with =make=, generate the documentation with =make doc=, create a local configuration with =make config= and install Org with =make install=. Please run =make help= to get the diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ac233a986..0302b8cda 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Org mode now uses =compat.el= third-party package to support older Emacs versions + +This change is mostly technical and should not affect most users. +However, people who install Org from git source might be affected. +It is now necessary to manually install =compat.el= using Emacs' +package manager. + *** =python-mode.el (MELPA)= support in =ob-python.el= is removed =python-mode.el= support has been removed from =ob-python.el=. The -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-mk-Expand-shell-commands-once-only.patch --] [-- Type: text/x-patch, Size: 2303 bytes --] From 5bb17634a14bb1af4944f73465552cbfd7068a77 Mon Sep 17 00:00:00 2001 Message-Id: <5bb17634a14bb1af4944f73465552cbfd7068a77.1680511419.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 13:53:47 +0200 Subject: [PATCH 5/7] mk: Expand shell commands once only * mk/default.mk (pkgdir): * mk/targets.mk (GITVERSION): (GITSTATUS): (DATE): (YEAR): Only expand the variables once, not in every make sub-process. Previous code ran pwd/date/git in every make sub-process, slowing things down significantly and unnecessarily. --- mk/default.mk | 2 +- mk/targets.mk | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mk/default.mk b/mk/default.mk index 4ad1a4281..b43a9b3ac 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -32,7 +32,7 @@ TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest # Where to store Org dependencies -pkgdir = $(shell pwd)/pkg-deps +pkgdir := $(shell pwd)/pkg-deps # Extra flags to be passed to Emacs EFLAGS ?= diff --git a/mk/targets.mk b/mk/targets.mk index ab8b830bb..18faa02f5 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -14,15 +14,15 @@ ifneq ($(wildcard .git),) # Use the org.el header. ORGVERSION := $(patsubst %-dev,%,$(shell $(BATCH) --eval "(require 'lisp-mnt)" \ --visit lisp/org.el --eval '(princ (lm-header "version"))')) - GITVERSION ?= $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)") - GITSTATUS ?= $(shell git status -uno --porcelain) + GITVERSION := $(shell git describe --match release\* --abbrev=6 HEAD 2>/dev/null || echo "release_N/A-N/A-$(shell git describe --match release\* --abbrev=6 --always HEAD)") + GITSTATUS := $(shell git status -uno --porcelain) else -include mk/version.mk GITVERSION ?= N/A ORGVERSION ?= N/A endif -DATE = $(shell date +%Y-%m-%d) -YEAR = $(shell date +%Y) +DATE := $(shell date +%Y-%m-%d) +YEAR := $(shell date +%Y) ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: 0006-mk-Echo-main-compilation-states-when-running-make.patch --] [-- Type: text/x-patch, Size: 2268 bytes --] From 9c22dcd8cb0ea0e17e322bbad3d62975572ea80c Mon Sep 17 00:00:00 2001 Message-Id: <9c22dcd8cb0ea0e17e322bbad3d62975572ea80c.1680511419.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 14:05:22 +0200 Subject: [PATCH 6/7] mk: Echo main compilation states when running make * lisp/Makefile (all compile compile-dirty): ($(LISPV)): ($(LISPI)): Echo compile stage. * mk/targets.mk (uppkg): Echo compile stage and hide the installation command. --- lisp/Makefile | 7 +++++-- mk/targets.mk | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lisp/Makefile b/lisp/Makefile index f507f18a2..45d8109f0 100644 --- a/lisp/Makefile +++ b/lisp/Makefile @@ -20,6 +20,7 @@ _ORGCM_ := dirall single source slint1 slint2 # do not clean here, done in toplevel make all compile compile-dirty:: autoloads + @$(info ========= Compiling lisp files using '$(ORGCM)' target) ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),) $(MAKE) compile-$(ORGCM) else @@ -52,12 +53,14 @@ slint1: autoloads: cleanauto $(LISPI) $(LISPV) $(LISPV): $(LISPF) - @echo "org-version: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org version number) + @$(info org-version: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_VERSION) $(LISPI): $(LISPV) $(LISPF) - @echo "org-loaddefs: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org loaddefs) + @$(info org-loaddefs: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_INSTALL) diff --git a/mk/targets.mk b/mk/targets.mk index 18faa02f5..072106237 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -103,9 +103,10 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f endif uppkg:: - -$(MKDIR) -p $(pkgdir) - -$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + - $(INSTALL_PACKAGES) + $(info ========= Installing required third-party packages) + @$(MKDIR) -p $(pkgdir) + @$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + + -@$(INSTALL_PACKAGES) up0 up1 up2:: git checkout $(GIT_BRANCH) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: 0007-mk-Do-not-run-package-refresh-packages-unless-necess.patch --] [-- Type: text/x-patch, Size: 2322 bytes --] From 53da71e055630ef8bc6b1191f11a4ec03dabd8c7 Mon Sep 17 00:00:00 2001 Message-Id: <53da71e055630ef8bc6b1191f11a4ec03dabd8c7.1680511419.git.yantar92@posteo.net> In-Reply-To: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> References: <313f2b6acdf67f29f4f5f671e8278bb3e566cabf.1680511418.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 15:11:06 +0200 Subject: [PATCH 7/7] mk: Do not run `package-refresh-packages' unless necessary * mk/default.mk (package-install): (package-define-refresh-mark): (package-need-refresh-mark): (package-refresh-maybe): (package-install-maybe): (INSTALL_PACKAGES): Update the command avoiding `package-refresh-packages' when all the required third-party packages are already present in the `load-path'. --- mk/default.mk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mk/default.mk b/mk/default.mk index b43a9b3ac..67bf96c2e 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -81,7 +81,10 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' -package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' +package-define-refresh-mark = --eval '(setq org--compile-packages-missing nil)' +package-need-refresh-mark = --eval '(unless (require '"'"'$(package) nil t) (setq org--compile-packages-missing t))' +package-refresh-maybe = --eval '(if org--compile-packages-missing (package-refresh-contents) (message "No third-party packages need to be installed"))' +package-install-maybe = --eval '(unless (require '"'"'$(package) nil t) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ @@ -93,8 +96,8 @@ INSTALL_PACKAGES = else INSTALL_PACKAGES = \ $(BATCH) \ - --eval '(package-refresh-contents)' \ - $(foreach package,$(EPACKAGES),$(package-install)) + $(package-define-refresh-mark) $(foreach package,$(EPACKAGES),$(package-need-refresh-mark)) $(package-refresh-maybe) \ + $(foreach package,$(EPACKAGES),$(package-install-maybe)) endif BTEST = $(BATCH) $(BTEST_INIT) \ -- 2.40.0 [-- Attachment #9: Type: text/plain, Size: 224 bytes --] -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-02 17:00 ` [PATCH v2] " Ihor Radchenko 2023-04-03 8:46 ` [PATCH v3] " Ihor Radchenko @ 2023-04-08 11:15 ` Max Nikulin 2023-04-08 11:41 ` Ihor Radchenko 1 sibling, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-08 11:15 UTC (permalink / raw) To: emacs-orgmode On 03/04/2023 00:00, Ihor Radchenko wrote: > Max Nikulin writes: > >> Ihor, do added makefile rules follow best practices used by other Emacs >> packages in respect to dependencies? > I know no other Emacs packages that manage dependencies using make. org-ql uses a helper shell script. org-roam and projectile use eldev that is procedural, not declarative build system. I have not figured out which way magit handles dependencies. I have no more ideas what projects may involve unit tests and dependencies. Actually Org uses make just as interface, not as a declarative build system that is able to minimize work by updating only necessary targets. Build rules are effectively procedural: complete rebuild on every invocation. >> I do not like the idea of network queries on every make. > Any better suggestions? Do not run install dependencies for regular targets like test or compile. At least do not do it unless it is explicitly requested by command line argument or a variable in local.mk >>> +pkgdir = $(shell pwd)/pkg-deps >> >> Make has CURDIR variable, but I am unsure if it is safe to use it in >> this context. > > Actually, we need pkgdir := $(shell pwd)/pkg-deps. > CURDIR is wrong because default.mk will trigger evaluation in every make > sub-process as well. default.mk is included from top level Makefile only. By the way, it is better to explicitly express that path is relative to top project directory by defining e.g. top_builddir (or abs_top_builddir) at first and pkgdir = $(top_builddir)/pkg-deps Today I noticed the following trick in (likely stale) https://github.com/org-roam/org-roam/blob/main/default.mk TOP := $(dir $(lastword $(MAKEFILE_LIST))) I have not realized if it is safe enough. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-08 11:15 ` [PATCH v2] " Max Nikulin @ 2023-04-08 11:41 ` Ihor Radchenko 2023-04-08 16:37 ` Max Nikulin 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-04-08 11:41 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: >> I know no other Emacs packages that manage dependencies using make. > > org-ql uses a helper shell script. org-roam and projectile use eldev > that is procedural, not declarative build system. I have not figured out > which way magit handles dependencies. I have no more ideas what projects > may involve unit tests and dependencies. I see. Unfortunately, using third-party non-standard packages like makem.sh or eldev will be more troublesome. We will need to sync Org repo with them or demand users to install them separately. Also, eldev is not on ELPA, and we cannot use it at all. As for makem.sh, AFAIK, it will be even worse wrt network access - it tries refreshing and downloading some packages by default, unless we explicitly disable that feature. And under the hood, makem.sh anyway does the same emacs --eval thing I used in the patch. >>> I do not like the idea of network queries on every make. >> Any better suggestions? > > Do not run install dependencies for regular targets like test or > compile. At least do not do it unless it is explicitly requested by > command line argument or a variable in local.mk compat.el is required for "compile" target. Compilation will simply fail with older Emacs. And "test" triggers "compile". >> Actually, we need pkgdir := $(shell pwd)/pkg-deps. >> CURDIR is wrong because default.mk will trigger evaluation in every make >> sub-process as well. > > default.mk is included from top level Makefile only. Not sure here. I just noticed that GITVERSION got re-calculated many times when looking at debug output of make. (It was slowing things down significantly). GITVERSION is in targets.mk though. > By the way, it is > better to explicitly express that path is relative to top project > directory by defining e.g. top_builddir (or abs_top_builddir) at first and > > pkgdir = $(top_builddir)/pkg-deps How to define top_builddir? If also via `pwd`, I see not much difference. > Today I noticed the following trick in (likely stale) > https://github.com/org-roam/org-roam/blob/main/default.mk > > TOP := $(dir $(lastword $(MAKEFILE_LIST))) > > I have not realized if it is safe enough. Reading through 6.14 Other Special Variables section of make manual, it does not look safe - MAKEFILE_LIST may be altered by presence of includes. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-08 11:41 ` Ihor Radchenko @ 2023-04-08 16:37 ` Max Nikulin 2023-04-13 12:42 ` Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-08 16:37 UTC (permalink / raw) To: emacs-orgmode > +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) Is there a way to express (or (compat "29.1.4.1") (emacs "28.1")) to avoid installing compat in the case of sufficiently new emacs? E.g. dpkg/apt allows such alternatives. Early I asked concerning compat-29.1.3. I would prefer to install elpa-compat system package to avoid network activity in response to make. Required version matters for those who builds packages for backport repositories for various linux distributions. It allows to decide if it is necessary to provide newer elpa-compat or it is enough to package elpa-org. On 08/04/2023 18:41, Ihor Radchenko wrote: > > I see. Unfortunately, using third-party non-standard packages like > makem.sh or eldev will be more troublesome. We will need to sync Org > repo with them or demand users to install them separately. I was looking for sources of inspiration. I do not suggest to take these tools. Perhaps somebody may suggest a better example of build scripts for Emacs packages. >>>> I do not like the idea of network queries on every make. >>> Any better suggestions? >> >> Do not run install dependencies for regular targets like test or >> compile. At least do not do it unless it is explicitly requested by >> command line argument or a variable in local.mk > > compat.el is required for "compile" target. Compilation will simply fail > with older Emacs. And "test" triggers "compile". There are different types of build systems. Some of them allows to specify which dependencies should be pulled, some do not. My expectation is that make does not attempt to manage dependencies. For me it is OK to type an additional command to install them and to fail otherwise. In my opinion > + @$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + command tells that package management capabilities in Emacs are rather rudimentary (in comparison to e.g. python toolchain). That is why I am in favor to more manual dependency management. Notice that I am not against an option to do it from make. Untested: $(FIND) $(pkgdir) -name \*.elc -delete "@" for silencing is intentionally dropped, parenthesis are unnecessary for single condition. >>> Actually, we need pkgdir := $(shell pwd)/pkg-deps. >>> CURDIR is wrong because default.mk will trigger evaluation in every make >>> sub-process as well. >> >> default.mk is included from top level Makefile only. > > Not sure here. I just noticed that GITVERSION got re-calculated many > times when looking at debug output of make. (It was slowing things down > significantly). GITVERSION is in targets.mk though. GITVERSION is defined as ?=, so it is a variable with deferred evaluation. Immediately evaluated variable may defined using := >> pkgdir = $(top_builddir)/pkg-deps > > How to define top_builddir? If also via `pwd`, I see not much difference. I consider it as self-documenting code. Intermediate variable makes it apparent for readers that the directory is relative to the top of the package file tree. Since out of source tree builds are not supported, I would consider adding emacs version to path. The idea is to allow keeping installed packages when switching between several emacs versions. A note concerning variable name. For me it is associated for the directory where current package should be installed. I do not remember origin, but I noticed that such meaning is used in arch https://wiki.archlinux.org/title/creating_packages#Defining_PKGBUILD_variables Perhaps the same name is in gentoo in other sense that makes it suitable for storage of dependencies. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-08 16:37 ` Max Nikulin @ 2023-04-13 12:42 ` Ihor Radchenko 2023-04-17 17:20 ` Max Nikulin 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-04-13 12:42 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 4757 bytes --] Max Nikulin <manikulin@gmail.com> writes: >> +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) > > Is there a way to express (or (compat "29.1.4.1") (emacs "28.1")) to > avoid installing compat in the case of sufficiently new emacs? E.g. > dpkg/apt allows such alternatives. No, AFAIK: D.8 Conventional Headers for Emacs Libraries ‘Package-Requires’ If this exists, it names packages on which the current package depends for proper operation. *Note Packaging Basics::. This is used by the package manager both at download time (to ensure that a complete set of packages is downloaded) and at activation time (to ensure that a package is only activated if all its dependencies have been). Its format is a list of lists on a single line. The ‘car’ of each sub-list is the name of a package, as a symbol. The ‘cadr’ of each sub-list is the minimum acceptable version number, as a string that can be parsed by ‘version-to-list’. An entry that lacks a version (i.e., an entry which is just a symbol, or a sub-list of one element) is equivalent to entry with version "0". For instance: ;; Package-Requires: ((gnus "1.0") (bubbles "2.7.2") cl-lib (seq)) The package code automatically defines a package named ‘emacs’ with the version number of the currently running Emacs. This can be used to require a minimal version of Emacs for a package. > Early I asked concerning compat-29.1.3. I would prefer to install > elpa-compat system package to avoid network activity in response to > make. Required version matters for those who builds packages for > backport repositories for various linux distributions. It allows to > decide if it is necessary to provide newer elpa-compat or it is enough > to package elpa-org. We can put older version require now, indeed. However, later we should not constrain ourselves about bumping compat version as necessary. Considering Debian lifecycle, it is pretty much guaranteed that we will require the compat version that is not installed by Debian, eventually. In any case, see the attached additional patch. >> compat.el is required for "compile" target. Compilation will simply fail >> with older Emacs. And "test" triggers "compile". > > There are different types of build systems. Some of them allows to > specify which dependencies should be pulled, some do not. My expectation > is that make does not attempt to manage dependencies. For me it is OK to > type an additional command to install them and to fail otherwise. Sure. And you will have such option (EFLAGS). However, I decided to enable auto-downloading by default to not break the previous working compilation instructions. It may, however, be worth documenting EFLAGS in WORG. See the attached patch. > In my opinion > >> + @$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + > > command tells that package management capabilities in Emacs are rather > rudimentary (in comparison to e.g. python toolchain). That is why I am > in favor to more manual dependency management. Notice that I am not > against an option to do it from make. May you elaborate what you mean by "more manual"? What concrete change in the patch do you have in mind? > Untested: > > $(FIND) $(pkgdir) -name \*.elc -delete > > "@" for silencing is intentionally dropped, parenthesis are unnecessary > for single condition. Looks fine, except that now we have part of the targets using $RM variable and part of the targets ignoring it. I am not sure if it is a problem. I am slightly in favour of keeping the existing approach with $RM. >>> default.mk is included from top level Makefile only. >> >> Not sure here. I just noticed that GITVERSION got re-calculated many >> times when looking at debug output of make. (It was slowing things down >> significantly). GITVERSION is in targets.mk though. > > GITVERSION is defined as ?=, so it is a variable with deferred > evaluation. Immediately evaluated variable may defined using := That's what I did in one of the patches (use :=). >>> pkgdir = $(top_builddir)/pkg-deps >> >> How to define top_builddir? If also via `pwd`, I see not much difference. > > I consider it as self-documenting code. Intermediate variable makes it > apparent for readers that the directory is relative to the top of the > package file tree. Agree. Will do. See the attached. > Since out of source tree builds are not supported, I would consider > adding emacs version to path. The idea is to allow keeping installed > packages when switching between several emacs versions. Done. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-mk-default.mk-pkgdir-Make-it-more-clear-that-we-inde.patch --] [-- Type: text/x-patch, Size: 904 bytes --] From c5ba5773e69d16930fc12db6fbe0d907fae926cd Mon Sep 17 00:00:00 2001 Message-Id: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 8 Apr 2023 19:05:37 +0200 Subject: [PATCH 1/4] mk/default.mk (pkgdir): Make it more clear that we indent to use top git dir * mk/default.mk (top_builddir): New variable storing top-level directory. (pkgdir): Use the new variable. --- mk/default.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/default.mk b/mk/default.mk index 67bf96c2e..92a3942da 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -32,7 +32,8 @@ TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest # Where to store Org dependencies -pkgdir := $(shell pwd)/pkg-deps +top_builddir := $(shell pwd) +pkgdir := $(top_builddir)/pkg-deps # Extra flags to be passed to Emacs EFLAGS ?= -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-mk-Separate-third-party-package-dirs-for-different-E.patch --] [-- Type: text/x-patch, Size: 2126 bytes --] From ddebc0e86b43e655b057927ca9869143232c3ee5 Mon Sep 17 00:00:00 2001 Message-Id: <ddebc0e86b43e655b057927ca9869143232c3ee5.1681389559.git.yantar92@posteo.net> In-Reply-To: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> References: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Mon, 10 Apr 2023 19:57:24 +0200 Subject: [PATCH 2/4] mk: Separate third-party package dirs for different Emacs versions * mk/default.mk (EMACS_VERSION): New variable holding current Emacs version, according to EMACS. (pkgdir_top): New variable holding top pkgdir, parent of per-Emacs version directories. (pkgdir): Set as a sub-directory of pkgdir_top named as Emacs version. * mk/targets.mk (uppkg): Do not clear .elc files. This is no longer needed as we do not need to worry about .elc being used by different Emacs version. (cleanpkg): Update, deleting the whole top pkgdir. --- mk/default.mk | 4 +++- mk/targets.mk | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mk/default.mk b/mk/default.mk index 92a3942da..bd6efeb6f 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -6,6 +6,7 @@ # Name of your emacs binary EMACS = emacs +EMACS_VERSION := $(shell $(EMACS) -Q --batch --eval '(message "%s" emacs-version)' 2>&1) # Where local software is found prefix = /usr/share @@ -33,7 +34,8 @@ testdir = $(TMPDIR)/tmp-orgtest # Where to store Org dependencies top_builddir := $(shell pwd) -pkgdir := $(top_builddir)/pkg-deps +pkgdir_top := $(top_builddir)/pkg-deps +pkgdir := $(pkgdir_top)/$(EMACS_VERSION) # Extra flags to be passed to Emacs EFLAGS ?= diff --git a/mk/targets.mk b/mk/targets.mk index 072106237..2171159ac 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -105,7 +105,6 @@ endif uppkg:: $(info ========= Installing required third-party packages) @$(MKDIR) -p $(pkgdir) - @$(FIND) $(pkgdir) \( -name \*.elc \) -exec $(RM) {} + -@$(INSTALL_PACKAGES) up0 up1 up2:: @@ -167,4 +166,4 @@ cleantest: } cleanpkg: - -$(RMR) $(pkgdir) + -$(RMR) $(pkgdir_top) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Makefile-Document-new-targets-in-make-helpall.patch --] [-- Type: text/x-patch, Size: 1518 bytes --] From a96ccb3b4d8b534e3d5a7bcccada368b0a220b69 Mon Sep 17 00:00:00 2001 Message-Id: <a96ccb3b4d8b534e3d5a7bcccada368b0a220b69.1681389559.git.yantar92@posteo.net> In-Reply-To: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> References: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Thu, 13 Apr 2023 14:33:16 +0200 Subject: [PATCH 3/4] * Makefile: Document new targets in make helpall Document the newly added cleanpkg and uppkg targets. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f476a3ea7..5e0e0fdff 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ helpall:: $(info Cleaning) $(info ========) $(info make clean - remove built Org ELisp files and documentation) + $(info make cleanpkg - remove third-party packages downloaded via make uppkg) $(info make cleanall - remove everything that can be built and all remnants) $(info make clean-install - remove previous Org installation) $(info ) @@ -81,6 +82,7 @@ helpall:: $(info Convenience) $(info ===========) $(info make up0 - pull from upstream) + $(info make uppkg - download third-party packages required for compilation) $(info make up1 - pull from upstream, build and check) $(info make up2 - pull from upstream, build, check and install) $(info make update - pull from upstream and build) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-lisp-org.el-Require-lower-Compat-version.patch --] [-- Type: text/x-patch, Size: 1327 bytes --] From 0f5b5b445b649d6dda0a2637cc52ef6b6fed90e1 Mon Sep 17 00:00:00 2001 Message-Id: <0f5b5b445b649d6dda0a2637cc52ef6b6fed90e1.1681389559.git.yantar92@posteo.net> In-Reply-To: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> References: <c5ba5773e69d16930fc12db6fbe0d907fae926cd.1681389559.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Thu, 13 Apr 2023 14:36:42 +0200 Subject: [PATCH 4/4] * lisp/org.el: Require lower Compat version Compat 29.1.3.2 is pre-installed on current Ubuntu 23.04. Do not require later version as it is (1) not yet necessary, (2) will make life slightly easier for people who do not want to download staff unnecessarily. Link: https://list.orgmode.org/orgmode/u09ejk$vi1$1@ciao.gmane.io/ --- lisp/org.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/org.el b/lisp/org.el index 065813acf..26128815f 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry <bzg@gnu.org> ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.3.2")) ;; Version: 9.7-pre -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0001-dev-org-build-system.org-Document-newly-added-target.patch --] [-- Type: text/x-patch, Size: 2171 bytes --] From 1d90f3459b9a51502dc40d683fafb45803335eb4 Mon Sep 17 00:00:00 2001 Message-Id: <1d90f3459b9a51502dc40d683fafb45803335eb4.1681389714.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Thu, 13 Apr 2023 14:32:20 +0200 Subject: [PATCH] * dev/org-build-system.org: Document newly added targets and options (Make Targets =mk/targets.mk=): Document EGLAGS and EPACKAGES variables. (Cleaning): (Compatibility and Convenience): Document cleanpkg and uppkg targets. --- dev/org-build-system.org | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dev/org-build-system.org b/dev/org-build-system.org index 37d07fe5..a3a7d8e8 100644 --- a/dev/org-build-system.org +++ b/dev/org-build-system.org @@ -118,6 +118,13 @@ ** Make Targets =mk/targets.mk= be useful in some situations. The following variables are considered stable: +- =EFLAGS= :: Additional flags passed to Emacs executable. Applies to + all targets. +- =EPACKAGES= :: Additional packages to install before compilation. + This is useful to install optional packages for + test suite. The packages will not be installed, if + already available in the ~load-path~ that can be passed + via =EFLAGS=. - =TEST_NO_AUTOCLEAN= :: Define to a non-null value to keep the test directory around for inspection. This is mostly useful for debugging the test suite. @@ -214,6 +221,7 @@ ** Documentation ** Cleaning - =clean= :: Cleans in =lisp/= and =doc/=. +- =cleanpkg= :: Cleans in =pkg-deps/=. - =cleanall= :: Cleans everything that can be cleaned, including several types of backup files, so do not use this when you have active edit sessions! @@ -224,6 +232,7 @@ ** Compatibility and Convenience - =up0= :: Updates the current Git branch from upstream by doing a =git pull=. +- =uppkg= :: Download packages to be available for =make compile=. - =up1= :: Does =up0= and then builds and checks Org. - =up2= :: Does =up1= and installs Org if there was no test error. - =update= :: Does =up0= and then builds Org. Does not test. -- 2.40.0 [-- Attachment #7: Type: text/plain, Size: 224 bytes --] -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-13 12:42 ` Ihor Radchenko @ 2023-04-17 17:20 ` Max Nikulin 2023-04-20 9:27 ` Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-17 17:20 UTC (permalink / raw) To: emacs-orgmode On 13/04/2023 19:42, Ihor Radchenko wrote: > Max Nikulin writes: >> My expectation >> is that make does not attempt to manage dependencies. For me it is OK to >> type an additional command to install them and to fail otherwise. > > Sure. And you will have such option (EFLAGS). > However, I decided to enable auto-downloading by default to not break > the previous working compilation instructions. For me adding external dependencies is strong enough reason to change compiling instructions. My vote is for clear separation of dependency management (even if performed through make targets) and compiling/testing/etc. Last years I rarely use make directly to build software besides the cases when I am involved in development. I strongly prefer .deb packages. Earlier it was usual practice that "make" or "make all" failed if dependencies were not provided. Actually often it was configure that reported unavailable libraries. So network requests may be more surprising for users than failures due to missed dependencies. It is OK for e.g. gradle, but not for make to fetch packages. I expect that maintainers of packages from Linux distributions would prefer to avoid mixing of compiling and loading dependencies as well. In my opinion, ideally there should be 3 options for dependency management: 1. Completely disabled. If load from default paths failed than it is a fatal error. 2. Use specified directory outside of Org tree (~/.emacs.d/elpa by default) or any other directory that you named pkgdir. Only dedicated target may clean this directory. 3. Install packages to Org source/build directory. You decided to make 3 the default variant. I believe, it should be activated by a variable, e.g. AUTODEP = 1 in local.mk or from command line "make compile AUTODEP=1 I think, it is better to require an additional command make autoloads make fetch-dependencies make compile > +package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' I do not like that versions of dependencies are ignored. I have noticed `package-install-from-buffer'. Perhaps it can be used to generate a stub package (e.g. org-build-deps) with Package-Requires line obtained from org.el. The only purpose of this package is to pull dependencies. It is just an idea, I have not tried such approach. >> $(FIND) $(pkgdir) -name \*.elc -delete > > Looks fine, except that now we have part of the targets using $RM > variable and part of the targets ignoring it. I am not sure if it is a > problem. I am slightly in favour of keeping the existing approach with > $RM. I have realized that -delete action is not a part of POSIX https://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html Anyway you removed this line and I like it since I suspected some issues when "make compile" is invoked twice. >> Is there a way to express (or (compat "29.1.4.1") (emacs "28.1")) to >> avoid installing compat in the case of sufficiently new emacs? E.g. >> dpkg/apt allows such alternatives. > > No, AFAIK: It is sour. Another deficiency of Emacs package management is that errors during compiling of dependencies do not cause immediate failure of make. > +EMACS_VERSION := $(shell $(EMACS) -Q --batch --eval '(message "%s" emacs-version)' 2>&1) Ideally $(BATCH) should be used, but it is defined below. (princ emacs-version) is an alternative, but I have not idea which variant is better. > -;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) > +;; Package-Requires: ((emacs "26.1") (compat "29.1.3.2")) thanks > Subject: [PATCH 3/7] Use compat.el library instead of ad-hoc compatibility > function set > > * mk/default.mk (EPACKAGES): Demand compat library during compile time. when I asked for more granular commits I expected this change in > Subject: [PATCH 2/7] org-compat: Enable compat.el To separate adding dependency and replacing org-compat functions to compat. Earlier I used the following procedure: git rebase -i, mark some commit for edit, git gui, unstage lines from commit, create new commit, reorder and squash/fixup commits on next iteration of rebase -i. Perhaps magit can do the same tricks as "git gui". If all changes of some file should be moved to another commit it should be easier to use git checkout COMMIT FILE. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-17 17:20 ` Max Nikulin @ 2023-04-20 9:27 ` Ihor Radchenko 2023-04-28 15:27 ` Max Nikulin 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-04-20 9:27 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: >> Sure. And you will have such option (EFLAGS). >> However, I decided to enable auto-downloading by default to not break >> the previous working compilation instructions. > > For me adding external dependencies is strong enough reason to change > compiling instructions. My vote is for clear separation of dependency > management (even if performed through make targets) and > compiling/testing/etc. > ... > In my opinion, ideally there should be 3 options for dependency management: > 1. Completely disabled. If load from default paths failed than it is a > fatal error. I have no problem with this approach when using system packages. However, it is almost guaranteed that compat.el is absent in global load-path as long as compat.el is not built-in. > 2. Use specified directory outside of Org tree (~/.emacs.d/elpa by > default) or any other directory that you named pkgdir. Only dedicated > target may clean this directory. This is mostly an equivalent of -L switch. I do not like the idea of using ~/.emacs.d/elpa default. It is fragile if this default ever changes. > 3. Install packages to Org source/build directory. > > You decided to make 3 the default variant. I believe, it should be > activated by a variable, e.g. AUTODEP = 1 in local.mk or from command > line "make compile AUTODEP=1 It is now activated by EPACKAGES being non-empty. > I think, it is better to require an additional command > > make autoloads > make fetch-dependencies > make compile Maybe. Then, also make doc and make install? And make repro, which is dislike in particular - make repro is supposed to be easy to use for users unfamiliar with Emacs internals or typical GNU make conventions. >> +package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))' > > I do not like that versions of dependencies are ignored. I have noticed > `package-install-from-buffer'. Perhaps it can be used to generate a stub > package (e.g. org-build-deps) with Package-Requires line obtained from > org.el. The only purpose of this package is to pull dependencies. It is > just an idea, I have not tried such approach. This sounds fragile. I see no reason to go this far and using so complex approach. >> +EMACS_VERSION := $(shell $(EMACS) -Q --batch --eval '(message "%s" emacs-version)' 2>&1) > > Ideally $(BATCH) should be used, but it is defined below. (princ > emacs-version) is an alternative, but I have not idea which variant is > better. I used $(EMACS) on purpose. $(BATCH) may contain more things, which we do not want (on purpose) here. >> Subject: [PATCH 3/7] Use compat.el library instead of ad-hoc compatibility >> function set >> >> * mk/default.mk (EPACKAGES): Demand compat library during compile time. > > when I asked for more granular commits I expected this change in > >> Subject: [PATCH 2/7] org-compat: Enable compat.el > > To separate adding dependency and replacing org-compat functions to compat. For me, PATCH 3/7 grouping is more reasonable. So, I disagree. Splitting EPACKAGES modification would create transient commit with non-working Org. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v2] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-20 9:27 ` Ihor Radchenko @ 2023-04-28 15:27 ` Max Nikulin 2023-04-30 10:39 ` [PATCH v4] " Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-04-28 15:27 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 5189 bytes --] Ihor, I do not like lengthy emacs commands and make functions to generate them. I think, it is better to move such code to a script. A proof of concept is attached, however it is rather rough draft ./epm.el -Q --epm-dir $(emacs_pkgdir)/emacs-%e install compat ./epm.el -Q -L ~/src/compat install compat or export EPMDIR="$HOME/.cache/epm/emacs-%e" ./epm.el install compat to just abort compilation due to absent dependency ./epm.el missing compat On 20/04/2023 16:27, Ihor Radchenko wrote: > Max Nikulin writes: > >>> Sure. And you will have such option (EFLAGS). By the way, accordingly to (info "(make) Command Variables") or (info "(standards) Command Variables") "Variables for Specifying Commands" https://www.gnu.org/prep/standards/html_node/Command-Variables.html it should be EMACSFLAGS rather than EFLAGS. >> In my opinion, ideally there should be 3 options for dependency management: >> 1. Completely disabled. If load from default paths failed than it is a >> fatal error. > > I have no problem with this approach when using system packages. > However, it is almost guaranteed that compat.el is absent in global > load-path as long as compat.el is not built-in. I see that installation attempt is not performed when packages are available. However form my point of view it is normal when compilation fails when dependency are not provided. It works so for decades for applications that use make. To be precise, usually I expect detection of missed libraries from configure scrips, but in some cases they are missed. Maybe such experience was formed when access to network was limited. For me it is quite natural that make does try to pull dependencies (at least by default) and it is my responsibility to ensure availability of necessary libraries. >> 2. Use specified directory outside of Org tree (~/.emacs.d/elpa by >> default) or any other directory that you named pkgdir. Only dedicated >> target may clean this directory. > > This is mostly an equivalent of -L switch. No, -L is for source directories of package (e.g. git repositories). I mean namely alternative `package-user-dir', but not managed by make. > I do not like the idea of > using ~/.emacs.d/elpa default. It is fragile if this default ever > changes. I still consider it as a reasonable default for a user having just one emacs version who is going to build and run org. Both steps may use the same package directory. A developer who switches between various emacs versions may have set of packages for each emacs version. >> 3. Install packages to Org source/build directory. >> >> You decided to make 3 the default variant. I believe, it should be >> activated by a variable, e.g. AUTODEP = 1 in local.mk or from command >> line "make compile AUTODEP=1 > > It is now activated by EPACKAGES being non-empty. And it is non-empty by default because it defines list of build dependencies, not whether they should be managed by make. >> I think, it is better to require an additional command >> >> make autoloads >> make fetch-dependencies >> make compile > > Maybe. Then, also make doc and make install? In general "make install" may be executed by root while "make all" is a task for regular user. "make doc" is an optional step, so I do not see any problem. Ideally it might be make fetch-dependencies # or specify package directory # or load path in local.mk make all followed by optional doc or install > And make repro, I have not justified my point of view to make repro yet. >> I do not like that versions of dependencies are ignored. I have noticed >> `package-install-from-buffer'. Perhaps it can be used to generate a stub >> package (e.g. org-build-deps) with Package-Requires line obtained from >> org.el. The only purpose of this package is to pull dependencies. It is >> just an idea, I have not tried such approach. > > This sounds fragile. I see no reason to go this far and using so complex > approach. My idea is to ensure that *required* version is installed, not some stale one. I have not tried such approach though. >>> Subject: [PATCH 3/7] Use compat.el library instead of ad-hoc compatibility >>> function set >>> >>> * mk/default.mk (EPACKAGES): Demand compat library during compile time. >> >> when I asked for more granular commits I expected this change in >> >>> Subject: [PATCH 2/7] org-compat: Enable compat.el >> >> To separate adding dependency and replacing org-compat functions to compat. > > For me, PATCH 3/7 grouping is more reasonable. So, I disagree. > Splitting EPACKAGES modification would create transient commit with > non-working Org. I just do not like that a single line change in default.mk (modification of build process) is buried in a large patch (changes of the code). My idea was that > -EPACKAGES ?= > +EPACKAGES ?= compat should be in the same commit as > -;; Package-Requires: ((emacs "26.1")) > +;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1")) Currently patch 2 requires compat, but it is provided till patch 3. Despite in commit 2 the package does not do anything useful, I considered this commit as preparations to actively use introduced dependency. [-- Attachment #2: epm.el --] [-- Type: text/x-emacs-lisp, Size: 3982 bytes --] #!/bin/sh ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- ":"; exec emacs --script "$0" "$@" (require 'format-spec) (require 'package) (require 'subr-x) (defvar epm-dir nil "Overrides `package-user-dir'.") (defvar epm-verbose nil) (defun epm-nonempty-p (s) (and s (not (string-empty-p s)))) (defun epm-init () (unless (epm-nonempty-p epm-dir) (setq epm-dir (getenv "EPMDIR"))) (when (epm-nonempty-p epm-dir) (let* ((fmt-expanded (format-spec epm-dir `((?e . ,emacs-version)))) (dir (directory-file-name (expand-file-name fmt-expanded)))) ;; `package-user-dir' ~/.emacs.d/elpa by default ;; `package-directory-list' does not include it (setq package-user-dir dir))) (package-initialize)) (defun epm-library-unavailable-p (lib) (unless (locate-library lib) lib)) (defun epm-missing (libs) ;; TODO consider `require' catching load errors (delq nil (mapcar #'epm-library-unavailable-p libs))) (defun epm-cmd-help (_cmd _args) "List commands." (princ "Usage: epm [--dbg|--debug-on-error] [--epm-dir] COMMAND ARGS... CLI tool to install ELPA packages. Any Emacs option may be specified, e.g. --quck,-Q or --directory,-L DIR --dbg, --debug-on-error Enable `debug-on-error' --epm-dir DIR Set `package-user-dir'. \"%e\" is replaced by `emacs-version'. Alternatively EPMDIR environment may be specified. \n") (pcase-dolist (`(,name . ,func) epm-commands) (princ (concat name "\n")) (princ (replace-regexp-in-string "\\`\\|\n" "\\1 " (documentation func) 'fixedcase nil)) (princ "\n\n") )) (defun epm-cmd-missing (_ libs) "Report not installed libraries and exit with non-zero code." (let ((missing (epm-missing libs))) (when missing (princ (mapconcat #'identity missing " ")) (princ "\n") (kill-emacs 1)))) (defun epm-cmd-install (_ libs) "Install packages from LIBS that are not available yet" ;; TODO force option or update command (let ((missing (epm-missing libs))) (when missing (package-refresh-contents) (make-directory package-user-dir 'parents)) (dolist (pkg missing) (package-install (intern pkg))))) (defun epm-cmd-report (_ libs) "Report paths of available libraries" (princ (format "package-user-dir: %s\n" package-user-dir)) ;; (princ (format "load-path: %s\n" load-path)) (dolist (name libs) ;; (version-to-list version) (princ (format "%-20s %s " name (if (package-installed-p (intern name)) "package " " "))) (princ (locate-library name)) (princ "\n"))) (defvar epm-commands '(("help" . epm-cmd-help) ("install" . epm-cmd-install) ("missing" . epm-cmd-missing) ("report" . epm-cmd-report))) ;; Perhaps there is a way to use `command-switch-alist'. (defun epm-args-parse (arg-list) (let ((parse-opts t) unprocessed cmd) (while (and arg-list (or parse-opts (not cmd))) (pcase (pop arg-list) ("--" (setq parse-opts nil)) ((and (guard parse-opts) ;; otherwise processed after script exit (or "-L" (pred (lambda (x) (string-prefix-p x "--directory"))))) (push (expand-file-name (command-line-normalize-file-name (pop arg-list))) load-path)) ((and (guard parse-opts) "--epm-dir") (setq epm-dir (pop arg-list))) ((and (guard parse-opts) (or "--dbg" "--debug-on-error")) ;; -d is handled as --display, --debug as --debug-init (setq debug-on-error t)) ((and (guard (not cmd)) (pred (string-match-p "\\`[^-]")) arg) (push arg cmd) (unless parse-opts (push "--" cmd))) (arg (if cmd (push arg cmd) (push arg unprocessed))))) (cons (nreverse cmd) (nreverse unprocessed)))) (pcase-let ((`(,cmd . ,unprocessed) (epm-args-parse command-line-args-left))) (unless (setq command-line-args-left unprocessed) (epm-init) (let ((func (cdr (assoc (car cmd) epm-commands)))) (if func (funcall func (car cmd) (cdr cmd)) (error "Unknown command %s" (car cmd)))))) ^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-28 15:27 ` Max Nikulin @ 2023-04-30 10:39 ` Ihor Radchenko 2023-05-03 12:14 ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin 2023-05-06 6:39 ` [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Max Nikulin 0 siblings, 2 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-04-30 10:39 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 5147 bytes --] Max Nikulin <manikulin@gmail.com> writes: > I do not like lengthy emacs commands and make functions to generate > them. I think, it is better to move such code to a script. A proof of > concept is attached, however it is rather rough draft > > ./epm.el -Q --epm-dir $(emacs_pkgdir)/emacs-%e install compat > ./epm.el -Q -L ~/src/compat install compat Good idea. Although, we should not overdo this package management thing. If we really need complex functionality here, we should better just use cask/eldev instead of re-inventing the wheel. Are you willing to improve the draft to be ready for upstream? I will provide some inline comments below. > By the way, accordingly to (info "(make) Command Variables") or (info > "(standards) Command Variables") "Variables for Specifying Commands" > https://www.gnu.org/prep/standards/html_node/Command-Variables.html > > it should be EMACSFLAGS rather than EFLAGS. Fair point. I now rearranged the commits as you asked and incorporated this change. See the attached. Note that also I changed the way compat.el is loaded, making Org throw an error for older Emacs versions. This will produce more useful error if someone attempts to load Org as is, without installing compat.el in older Emacs. >> I have no problem with this approach when using system packages. >> However, it is almost guaranteed that compat.el is absent in global >> load-path as long as compat.el is not built-in. > > I see that installation attempt is not performed when packages are > available. However form my point of view it is normal when compilation > fails when dependency are not provided. It works so for decades for > applications that use make. To be precise, usually I expect detection of > missed libraries from configure scrips, but in some cases they are > missed. Maybe such experience was formed when access to network was limited. > > For me it is quite natural that make does try to pull dependencies (at > least by default) and it is my responsibility to ensure availability of > necessary libraries. I think that we need to zoom out a bit and discuss the contexts where Org build system is used: 1. During Org development, by developers who know what they are doing 2. By ordinary users, not necessarily familiar with GNU make and all the associated build process conventions. Org developers may need to use the whole spectrum of make targets, and will generally benefit from isolation of Org from the main Emacs configuration folder. For example, my `package-user-dir' contains a number of forks with additional patches applied - it is not the environment I want to develop (and test) Org in. Org users will likely use make autoloads, make, make docs, and make repro. Here, it will make sense to re-use default .emacs.d and package directory when running make, as ordinary users running make are most likely aiming to build Org for their own usage. However, make repro and optionally make docs should avoid re-using user packages as it may cause inconsistent results if the `package-user-dir' is messed up. One way to handle the above scenarios might be your idea with AUTODEP. By default, it will be "auto": - make compile, docs :: Re-use default `package-user-dir' - make repro :: Auto-download and ignore `package-user-dir' - other targets :: Prompt the user Alternatives will be meant to be used as AUTODEP=download/user/no make target. triggering unconditional downloading, using `package-user-dir', and not using any guess, correspondingly. WDYT? >>> I do not like that versions of dependencies are ignored. I have noticed >>> `package-install-from-buffer'. Perhaps it can be used to generate a stub >>> package (e.g. org-build-deps) with Package-Requires line obtained from >>> org.el. The only purpose of this package is to pull dependencies. It is >>> just an idea, I have not tried such approach. >> >> This sounds fragile. I see no reason to go this far and using so complex >> approach. > > My idea is to ensure that *required* version is installed, not some > stale one. I have not tried such approach though. I think that it is stretching a bit beyond the complexity we should allow within Org build system. In your scenario, I can simply do make cleanpkg and re-download the latest dependencies. Again, package management is not something we want to overdo. If really necessary, we will use cask or other proper Elisp development tool. > #!/bin/sh > ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- > ":"; exec emacs --script "$0" "$@" Let's not lock to bash. AFAIK, our makefiles can currently work on Windows. Using /bin/sh will lead to regression. So, a simple --batch script for Emacs will be better here. > (defun epm-init () > (unless (epm-nonempty-p epm-dir) > (setq epm-dir (getenv "EPMDIR"))) > (when (epm-nonempty-p epm-dir) > (let* ((fmt-expanded (format-spec epm-dir `((?e . ,emacs-version)))) > (dir (directory-file-name (expand-file-name fmt-expanded)))) > ;; `package-user-dir' ~/.emacs.d/elpa by default > ;; `package-directory-list' does not include it What does this comment refer to? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: v4-0001-Upgrade-Org-build-system-to-handle-third-party-de.patch --] [-- Type: text/x-patch, Size: 7555 bytes --] From 3946dbb956afcd005cba0f1899acae5a74a109d4 Mon Sep 17 00:00:00 2001 Message-Id: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH v4 1/8] Upgrade Org build system to handle third-party dependencies * mk/default.mk (pkgdir_top): New variable holding the location of third-party packages to be downloaded if necessary during compilation. (EMACS_VERSION): New variable holding current Emacs version, according to EMACS. (pkgdir): New variable holding subdir where the third-party packages are downloaded, according to EMACS_VERSION. (EMACSFLAGS): New variable holding extra flags to be passed to Emacs executable when running make. We follow "PROGRAMFLAGS" convention as requested by GNU standards: https://www.gnu.org/prep/standards/html_node/Command-Variables.html (EPACKAGES): List of packages to be installed (unless already present in the `load-path') during compilation. (package-install): (INSTALL_PACKAGES): New command to download and install missing packages. (EMACSQ): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (check test): (repro): (compile compile-dirty): Use the new uppkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_BASE): (CONF_DEST): (CONF_CALL): Update according to the new variables and targets. * .gitignore: Ignore the downloaded packages. This commit paves the way towards third-party built-time dependencies for Org. In particular, towards including compat.el dependency. According to EPACKAGES, we can auto-download necessary packages, unless they are manually specified via -L switches in EMACSFLAGS. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 1 + mk/default.mk | 31 ++++++++++++++++++++++++++++++- mk/targets.mk | 25 ++++++++++++++++--------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 4bb81c359..0d9c5b297 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ local*.mk .gitattributes mk/x11idle ChangeLog +pkg-deps/ # Files generated during `make packages/org` in a clone of `elpa.git`. diff --git a/mk/default.mk b/mk/default.mk index fa46661e8..393d7336a 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -6,6 +6,7 @@ # Name of your emacs binary EMACS = emacs +EMACS_VERSION := $(shell $(EMACS) -Q --batch --eval '(message "%s" emacs-version)' 2>&1) # Where local software is found prefix = /usr/share @@ -31,6 +32,17 @@ GIT_BRANCH = TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest +# Where to store Org dependencies +top_builddir := $(shell pwd) +pkgdir_top := $(top_builddir)/pkg-deps +pkgdir := $(pkgdir_top)/$(EMACS_VERSION) + +# Extra flags to be passed to Emacs +EMACSFLAGS ?= + +# Third-party packages to install when running make +EPACKAGES ?= + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -72,12 +84,25 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' +package-define-refresh-mark = --eval '(setq org--compile-packages-missing nil)' +package-need-refresh-mark = --eval '(unless (require '"'"'$(package) nil t) (setq org--compile-packages-missing t))' +package-refresh-maybe = --eval '(if org--compile-packages-missing (package-refresh-contents) (message "No third-party packages need to be installed"))' +package-install-maybe = --eval '(unless (require '"'"'$(package) nil t) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ --eval '(add-to-list '"'"'load-path (concat default-directory "testing"))' BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST) +ifeq (,$(EPACKAGES)) +INSTALL_PACKAGES = +else +INSTALL_PACKAGES = \ + $(BATCH) \ + $(package-define-refresh-mark) $(foreach package,$(EPACKAGES),$(package-need-refresh-mark)) $(package-refresh-maybe) \ + $(foreach package,$(EPACKAGES),$(package-install-maybe)) +endif + BTEST = $(BATCH) $(BTEST_INIT) \ -l org-batch-test-init \ --eval '(setq \ @@ -116,7 +141,11 @@ REPRO = $(NOBATCH) $(REPRO_INIT) $(REPRO_ARGS) # start Emacs with no user and site configuration # EMACSQ = -vanilla # XEmacs -EMACSQ = $(EMACS) -Q +EMACSQ = $(EMACS) -Q \ + $(EMACSFLAGS) \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)' # Using emacs in batch mode. BATCH = $(EMACSQ) -batch \ diff --git a/mk/targets.mk b/mk/targets.mk index 06016561c..18140c5c0 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \ check test install $(INSTSUB) \ info html pdf card refcard doc docs \ autoloads cleanall clean $(CLEANDIRS:%=clean%) \ clean-install cleanelc cleandirs \ - cleanlisp cleandoc cleandocs cleantest \ + cleanlisp cleandoc cleandocs cleantest cleanpkg \ compile compile-dirty uncompiled \ config config-test config-exe config-all config-eol config-version \ vanilla repro -CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC -CONF_DEST = lispdir infodir datadir testdir +CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES +CONF_DEST = lispdir infodir datadir testdir pkgdir CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO -CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION +CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION config-eol:: EOL = \# config-eol:: config-all config config-all:: @@ -86,7 +86,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: uppkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -94,7 +94,7 @@ all clean-install:: vanilla: -@$(NOBATCH) & -check test:: compile +check test:: uppkg compile check test test-dirty:: -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) @@ -102,6 +102,10 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f $(MAKE) cleantest endif +uppkg:: + @$(MKDIR) -p $(pkgdir) + -@$(INSTALL_PACKAGES) + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -126,7 +130,7 @@ $(INSTSUB): autoloads: lisp $(MAKE) -C $< $@ -repro: cleanall autoloads +repro: cleanall uppkg autoloads -@$(REPRO) & cleandirs: @@ -134,7 +138,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest +cleanall: cleandirs cleantest cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -159,3 +163,6 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: + -$(RMR) $(pkgdir_top) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: v4-0002-org-compat-Add-optional-compat.el-support.patch --] [-- Type: text/x-patch, Size: 2869 bytes --] From f30e75e3b14b3cb955d2dcd11f210cfaceef07b6 Mon Sep 17 00:00:00 2001 Message-Id: <f30e75e3b14b3cb955d2dcd11f210cfaceef07b6.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Mon, 3 Apr 2023 10:40:00 +0200 Subject: [PATCH v4 2/8] org-compat: Add optional compat.el support * lisp/org-compat.el (compat): Load Compat library, when available. (org-compat-function): (org-compat-call): Add compatibility macros available even when Compat is not available (Org is a part of Emacs). --- lisp/org-compat.el | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 34b27546d..9c286961a 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -94,6 +94,48 @@ (defvar org-table-tab-recognizes-table.el) (defvar org-table1-hline-regexp) (defvar org-fold-core-style) +\f +;;; compat.el + +;; Do not throw an error when not available - assume latest Emacs +;; version (built-in Org). +(require 'compat nil 'noerror) + +;; Provide compatibility macros when we are a part of Emacs. +;; See https://elpa.gnu.org/packages/doc/compat.html#Usage + +(defmacro org-compat-function (fun) + "Return compatibility function symbol for FUN. + +If the Emacs version provides a sufficiently recent version of +FUN, the symbol FUN is returned itself. Otherwise the macro +returns the symbol of a compatibility function which supports the +behavior and calling convention of the current stable Emacs +version. For example Compat 29.1 will provide compatibility +functions which implement the behavior and calling convention of +Emacs 29.1. + +See also `org-compat-call' to directly call compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `#',(if (fboundp compat) compat fun))) + +(defmacro org-compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. + +A good example function is `plist-get' which was extended with an +additional predicate argument in Emacs 29.1. The compatibility +function, which supports this additional argument, can be +obtained via (compat-function plist-get) and called +via (compat-call plist-get plist prop predicate). It is not +possible to directly call (plist-get plist prop predicate) on +Emacs older than 29.1, since the original `plist-get' function +does not yet support the predicate argument. Note that the +Compat library never overrides existing functions. + +See also `org-compat-function' to lookup compatibility functions." + (let ((compat (intern (format "compat--%s" fun)))) + `(,(if (fboundp compat) compat fun) ,@args))) + \f ;;; Emacs < 29 compatibility -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: v4-0003-Add-compat.el-dependency.patch --] [-- Type: text/x-patch, Size: 1808 bytes --] From 03902b1efe931145870c64f517442b49f7ec92a3 Mon Sep 17 00:00:00 2001 Message-Id: <03902b1efe931145870c64f517442b49f7ec92a3.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 29 Apr 2023 11:34:00 +0200 Subject: [PATCH v4 3/8] Add compat.el dependency * mk/default.mk (EPACKAGES): Demand compat library during compile time. * lisp/org.el: Add Compat to package-requires. Compat 29.1.3.2 is pre-installed on current Ubuntu 23.04. Do not require later version as it is (1) not yet necessary, (2) will make life slightly easier for people who do not want to download staff unnecessarily. Link: https://list.orgmode.org/orgmode/u09ejk$vi1$1@ciao.gmane.io/ --- lisp/org.el | 2 +- mk/default.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 78040a8e3..162982405 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry <bzg@gnu.org> ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.3.2")) ;; Version: 9.7-pre diff --git a/mk/default.mk b/mk/default.mk index 393d7336a..cc5775362 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -41,7 +41,7 @@ pkgdir := $(pkgdir_top)/$(EMACS_VERSION) EMACSFLAGS ?= # Third-party packages to install when running make -EPACKAGES ?= +EPACKAGES ?= compat # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: v4-0004-Use-compat.el-library-instead-of-ad-hoc-compatibi.patch --] [-- Type: text/x-patch, Size: 32940 bytes --] From 239c8626b95c19ec1ac466b14876b826c37b4986 Mon Sep 17 00:00:00 2001 Message-Id: <239c8626b95c19ec1ac466b14876b826c37b4986.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Mon, 3 Apr 2023 10:41:50 +0200 Subject: [PATCH v4 4/8] Use compat.el library instead of ad-hoc compatibility function set * lisp/org.el (org-fill-paragraph): * lisp/org-compat.el: Obsolete org-* compatibility functions that are already available in compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case', `org-file-name-concat', `org-directory-empty-p', `org-string-clean-whitespace', `org-format-prompt', `org-xor', `org-string-distance', `org-buffer-hash'. * lisp/ob-core.el (org-babel-results-keyword): Use functions provided by compat.el. (org-babel-insert-result): * lisp/oc-basic.el (org-cite-basic--parse-bibliography): * lisp/oc.el (org-cite-adjust-note): * lisp/ol-gnus.el (org-gnus-group-link): (org-gnus-article-link): (org-gnus-store-link): * lisp/ol.el: (org-store-link): * lisp/org-attach.el: * lisp/org-capture.el: (org-capture-fill-template): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el: * lisp/org-persist.el (org-persist-directory): (org-persist-read:file): (org-persist-read:url): (org-persist--load-index): (org-persist-write:file): (org-persist-write:index): (org-persist--merge-index-with-disk): (org-persist-read): (org-persist-write): (org-persist-write-all): (org-persist--gc-persist-file): (org-persist-gc): * lisp/org-refile.el (org-refile-get-location): * lisp/ox.el (org-export-resolve-radio-link): * testing/lisp/test-ol.el (test-org-link/toggle-link-display): * testing/lisp/test-org-capture.el (test-org-capture/abort): Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- lisp/ob-core.el | 10 +- lisp/oc-basic.el | 6 +- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +- lisp/ol.el | 4 +- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +- lisp/org-compat.el | 180 ++++--------------------------- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-persist.el | 38 +++---- lisp/org-refile.el | 2 +- lisp/org.el | 4 +- lisp/ox.el | 6 +- testing/lisp/test-ol.el | 10 +- testing/lisp/test-org-capture.el | 2 +- 16 files changed, 74 insertions(+), 212 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index a2a84ad20..9034feb7e 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS" :type 'string :safe (lambda (v) (and (stringp v) - (org-string-equal-ignore-case "RESULTS" v)))) + (string-equal-ignore-case "RESULTS" v)))) (defcustom org-babel-noweb-wrap-start "<<" "String used to begin a noweb reference in a code block. @@ -927,7 +927,7 @@ (defun org-babel-check-src-block () (match-string 4)))))) (dolist (name names) (when (and (not (string= header name)) - (<= (org-string-distance header name) too-close) + (<= (string-distance header name) too-close) (not (member header names))) (error "Supplied header \"%S\" is suspiciously close to \"%S\"" header name)))) @@ -2521,7 +2521,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex ;; Escape contents from "export" wrap. Wrap ;; inline results within an export snippet with ;; appropriate value. - ((org-string-equal-ignore-case type "export") + ((string-equal-ignore-case type "export") (let ((backend (pcase split (`(,_) "none") (`(,_ ,b . ,_) b)))) @@ -2532,14 +2532,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex backend) "@@)}}}"))) ;; Escape contents from "example" wrap. Mark ;; inline results as verbatim. - ((org-string-equal-ignore-case type "example") + ((string-equal-ignore-case type "example") (funcall wrap opening-line closing-line nil nil "{{{results(=" "=)}}}")) ;; Escape contents from "src" wrap. Mark ;; inline results as inline source code. - ((org-string-equal-ignore-case type "src") + ((string-equal-ignore-case type "src") (let ((inline-open (pcase split (`(,_) diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index fdcb5bda2..88bce4418 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info) (dolist (file (org-cite-list-bibliography-files)) (when (file-readable-p file) (with-temp-buffer - (when (or (org-file-has-changed-p file) + (when (or (file-has-changed-p file) (not (gethash file org-cite-basic--file-id-cache))) (insert-file-contents file) (set-visited-file-name file t) - (puthash file (org-buffer-hash) org-cite-basic--file-id-cache)) + (puthash file (buffer-hash) org-cite-basic--file-id-cache)) (condition-case nil (unwind-protect (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache))) @@ -488,7 +488,7 @@ (defun org-cite-basic--close-keys (key keys) "List cite keys close to KEY in terms of string distance." (seq-filter (lambda (k) (>= org-cite-basic-max-key-distance - (org-string-distance k key))) + (string-distance k key))) keys)) (defun org-cite-basic--set-keymap (beg end suggestions) diff --git a/lisp/oc.el b/lisp/oc.el index 4b1420271..9b96ef8d3 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct) (match-string 3 previous))))) ;; Bail you when there is no quote and either no punctuation, or ;; punctuation on both sides. - (when (or quote (org-xor punct final-punct)) + (when (or quote (xor punct final-punct)) ;; Phase 1: handle punctuation rule. (pcase rule ((guard (not quote)) nil) diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el index 7c07ce045..e121cfba3 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -98,8 +98,8 @@ (defun org-gnus-group-link (group) `org-gnus-prefer-web-links' is reversed." (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group))) (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups - (org-xor current-prefix-arg - org-gnus-prefer-web-links)) + (xor current-prefix-arg + org-gnus-prefer-web-links)) (concat "https://groups.google.com/group/" unprefixed-group) (concat "gnus:" group)))) @@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive) If `org-store-link' was called with a prefix arg the meaning of `org-gnus-prefer-web-links' is reversed." - (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links) + (if (and (xor current-prefix-arg org-gnus-prefer-web-links) newsgroups ;make web links only for nntp groups (not x-no-archive)) ;and if X-No-Archive isn't set (format "https://groups.google.com/groups/search?as_umsgid=%s" @@ -169,7 +169,7 @@ (defun org-gnus-store-link () newsgroups x-no-archive) ;; Fetching an article is an expensive operation; newsgroup and ;; x-no-archive are only needed for web links. - (when (org-xor current-prefix-arg org-gnus-prefer-web-links) + (when (xor current-prefix-arg org-gnus-prefer-web-links) ;; Make sure the original article buffer is up-to-date. (save-window-excursion (gnus-summary-select-article)) (setq to (or to (gnus-fetch-original-field "To"))) diff --git a/lisp/ol.el b/lisp/ol.el index e2bf90acd..d7056abde 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let* ((element (org-element-at-point)) (name (org-element-property :name element)) (context @@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let ((context (org-link--normalize-string (or (org-link--context-from-region) (org-current-line-string)) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 824af69da..581708f5f 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -678,7 +678,7 @@ (defun org-attach-sync () (let ((files (org-attach-file-list attach-dir))) (org-attach-tag (not files))) (when org-attach-sync-delete-empty-dir - (when (and (org-directory-empty-p attach-dir) + (when (and (directory-empty-p attach-dir) (if (eq 'query org-attach-sync-delete-empty-dir) (yes-or-no-p "Attachment directory is empty. Delete?") t)) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index b96e9f336..c5b1c6d50 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1323,9 +1323,9 @@ (defun org-capture-place-item () ;; prioritize the existing list. (when prepend? (let ((ordered? (eq 'ordered (org-element-property :type item)))) - (when (org-xor ordered? - (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" - template)) + (when (xor ordered? + (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" + template)) (org-cycle-list-bullet (if ordered? "1." "-"))))) ;; Eventually repair the list for proper indentation and ;; bullets. @@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation) (setq org-capture--prompt-history (gethash prompt org-capture--prompt-history-table)) (push (org-completing-read - (org-format-prompt (or prompt "Enter string") default) + (format-prompt (or prompt "Enter string") default) completions nil nil nil 'org-capture--prompt-history default) strings) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 9c286961a..c40510c35 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec)) (declare-function org-fold-show-all "org-fold" (&optional types)) (declare-function org-fold-show-children "org-fold" (&optional level)) (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers)) -;; `org-string-equal-ignore-case' is in _this_ file but isn't at the -;; top-level. -(declare-function org-string-equal-ignore-case "org-compat" (string1 string2)) (defvar calendar-mode-map) (defvar org-complex-heading-regexp) @@ -136,105 +133,26 @@ (defmacro org-compat-call (fun &rest args) (let ((compat (intern (format "compat--%s" fun)))) `(,(if (fboundp compat) compat fun) ,@args))) -\f -;;; Emacs < 29 compatibility - -(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal) - "Internal variable used by `org-file-has-changed-p'.") - -(if (fboundp 'file-has-changed-p) - (defalias 'org-file-has-changed-p #'file-has-changed-p) - (defun org-file-has-changed-p (file &optional tag) - "Return non-nil if FILE has changed. -The size and modification time of FILE are compared to the size -and modification time of the same FILE during a previous -invocation of `org-file-has-changed-p'. Thus, the first invocation -of `org-file-has-changed-p' always returns non-nil when FILE exists. -The optional argument TAG, which must be a symbol, can be used to -limit the comparison to invocations with identical tags; it can be -the symbol of the calling function, for example." - (let* ((file (directory-file-name (expand-file-name file))) - (remote-file-name-inhibit-cache t) - (fileattr (file-attributes file 'integer)) - (attr (and fileattr - (cons (file-attribute-size fileattr) - (file-attribute-modification-time fileattr)))) - (sym (concat (symbol-name tag) "@" file)) - (cachedattr (gethash sym org-file-has-changed-p--hash-table))) - (when (not (equal attr cachedattr)) - (puthash sym attr org-file-has-changed-p--hash-table))))) - -(if (fboundp 'string-equal-ignore-case) - (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case) - ;; From Emacs subr.el. - (defun org-string-equal-ignore-case (string1 string2) - "Like `string-equal', but case-insensitive. -Upper-case and lower-case letters are treated as equal. -Unibyte strings are converted to multibyte for comparison." - (eq t (compare-strings string1 0 nil string2 0 nil t)))) - -\f -;;; Emacs < 28.1 compatibility - -(if (fboundp 'file-name-concat) - (defalias 'org-file-name-concat #'file-name-concat) - (defun org-file-name-concat (directory &rest components) - "Append COMPONENTS to DIRECTORY and return the resulting string. - -Elements in COMPONENTS must be a string or nil. -DIRECTORY or the non-final elements in COMPONENTS may or may not end -with a slash -- if they don't end with a slash, a slash will be -inserted before contatenating." - (save-match-data - (mapconcat - #'identity - (delq nil - (mapcar - (lambda (str) - (when (and str (not (seq-empty-p str)) - (string-match "\\(.+\\)/?" str)) - (match-string 1 str))) - (cons directory components))) - "/")))) - -(if (fboundp 'directory-empty-p) - (defalias 'org-directory-empty-p #'directory-empty-p) - (defun org-directory-empty-p (dir) - "Return t if DIR names an existing directory containing no other files." - (and (file-directory-p dir) - (null (directory-files dir nil directory-files-no-dot-files-regexp t))))) - -(if (fboundp 'string-clean-whitespace) - (defalias 'org-string-clean-whitespace #'string-clean-whitespace) - ;; From Emacs subr-x.el. - (defun org-string-clean-whitespace (string) - "Clean up whitespace in STRING. -All sequences of whitespaces in STRING are collapsed into a -single space character, and leading/trailing whitespace is -removed." - (let ((blank "[[:blank:]\r\n]+")) - (string-trim (replace-regexp-in-string blank " " string t t) - blank blank)))) - -(if (fboundp 'format-prompt) - (defalias 'org-format-prompt #'format-prompt) - ;; From Emacs minibuffer.el, inlining - ;; `minibuffer-default-prompt-format' value and replacing `length<' - ;; (both new in Emacs 28.1). - (defun org-format-prompt (prompt default &rest format-args) - "Compatibility substitute for `format-prompt'." - (concat - (if (null format-args) - prompt - (apply #'format prompt format-args)) - (and default - (or (not (stringp default)) - (> (length default) 0)) - (format " (default %s)" - (if (consp default) - (car default) - default))) - ": "))) +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "9.7") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "9.7") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "9.7") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "9.7") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "9.7") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "9.7") +(define-obsolete-function-alias 'org-xor + 'xor "9.7") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "9.7") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "9.7") \f ;;; Emacs < 27.1 compatibility @@ -252,22 +170,6 @@ (if (version< emacs-version "27.1") (replace-buffer-contents source)) (defalias 'org-replace-buffer-contents #'replace-buffer-contents)) -(unless (fboundp 'proper-list-p) - ;; `proper-list-p' was added in Emacs 27.1. The function below is - ;; taken from Emacs subr.el 200195e824b^. - (defun proper-list-p (object) - "Return OBJECT's length if it is a proper list, nil otherwise. -A proper list is neither circular nor dotted (i.e., its last cdr -is nil)." - (and (listp object) (ignore-errors (length object))))) - -(if (fboundp 'xor) - ;; `xor' was added in Emacs 27.1. - (defalias 'org-xor #'xor) - (defsubst org-xor (a b) - "Exclusive `or'." - (if a (not b) b))) - (unless (fboundp 'pcomplete-uniquify-list) ;; The misspelled variant was made obsolete in Emacs 27.1 (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list)) @@ -297,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p) (when (fboundp 'set-face-extend) (mapc (lambda (f) (set-face-extend f extend-p)) faces))) -(if (fboundp 'string-distance) - (defalias 'org-string-distance 'string-distance) - (defun org-string-distance (s1 s2) - "Return the edit (levenshtein) distance between strings S1 S2." - (let* ((l1 (length s1)) - (l2 (length s2)) - (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) - (number-sequence 1 (1+ l1))))) - (in (lambda (i j) (aref (aref dist i) j)))) - (setf (aref (aref dist 0) 0) 0) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist 0) j) j)) - (dolist (i (number-sequence 1 l1)) - (setf (aref (aref dist i) 0) i) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist i) j) - (min - (1+ (funcall in (1- i) j)) - (1+ (funcall in i (1- j))) - (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) - (funcall in (1- i) (1- j))))))) - (funcall in l1 l2)))) - (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance "9.5") @@ -340,23 +219,6 @@ (if (fboundp 'line-number-display-width) (defalias 'org-line-number-display-width 'line-number-display-width) (defun org-line-number-display-width (&rest _) 0)) -(if (fboundp 'buffer-hash) - (defalias 'org-buffer-hash 'buffer-hash) - (defun org-buffer-hash () (md5 (current-buffer)))) - -(unless (fboundp 'file-attribute-modification-time) - (defsubst file-attribute-modification-time (attributes) - "The modification time in ATTRIBUTES returned by `file-attributes'. -This is the time of the last change to the file's contents, and -is a Lisp timestamp in the same style as `current-time'." - (nth 5 attributes))) - -(unless (fboundp 'file-attribute-size) - (defsubst file-attribute-size (attributes) - "The size (in bytes) in ATTRIBUTES returned by `file-attributes'. -This is a floating point number if the size is too large for an integer." - (nth 7 attributes))) - \f ;;; Obsolete aliases (remove them after the next major release). @@ -1460,7 +1322,7 @@ (defun org-mode-flyspell-verify () (and log (let ((drawer (org-element-lineage element '(drawer)))) (and drawer - (org-string-equal-ignore-case + (string-equal-ignore-case log (org-element-property :drawer-name drawer)))))) nil) (t diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 43c6b2b74..c699c115b 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p (lambda (p) (next-single-char-property-change p 'invisible nil limit))))) (next pos)) (while (and (funcall cmp next limit) - (not (org-xor + (not (xor invisible-initially? (funcall invisible-p (if previous-p diff --git a/lisp/org-lint.el b/lisp/org-lint.el index dc18b657c..3aa148e69 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast) ast 'node-property (lambda (property) - (and (org-string-equal-ignore-case + (and (string-equal-ignore-case "CUSTOM_ID" (org-element-property :key property)) (org-element-property :value property))) (lambda (property _) (org-element-property :begin property)) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index d8b7dc4a1..45031c1dc 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -279,12 +279,12 @@ (defgroup org-persist nil (defcustom org-persist-directory (expand-file-name - (org-file-name-concat + (file-name-concat (let ((cache-dir (when (fboundp 'xdg-cache-home) (xdg-cache-home)))) (if (or (seq-empty-p cache-dir) (not (file-exists-p cache-dir)) - (file-exists-p (org-file-name-concat + (file-exists-p (file-name-concat user-emacs-directory "org-persist"))) user-emacs-directory @@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data) (defun org-persist-read:file (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:url (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:index (cont index-file _) "Read index container CONT from INDEX-FILE." @@ -750,7 +750,7 @@ (defun org-persist--load-index () "Load `org-persist--index'." (org-persist-load:index `(index ,org-persist--storage-version) - (org-file-name-concat org-persist-directory org-persist-index-file) + (file-name-concat org-persist-directory org-persist-index-file) nil)) ;;;; Writing container data @@ -805,7 +805,7 @@ (defun org-persist-write:file (c collection) (setq path (cadr c))) (let* ((persist-file (plist-get collection :persist-file)) (ext (file-name-extension path)) - (file-copy (org-file-name-concat + (file-copy (file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) (unless (file-exists-p file-copy) @@ -851,7 +851,7 @@ (defun org-persist-write:index (container _) org-persist-directory)))) (when (file-exists-p org-persist-directory) (let ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file))) + (file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) (org-persist--write-elisp-file index-file org-persist--index t t) (setq org-persist--index-age @@ -866,7 +866,7 @@ (defun org-persist--save-index () (defun org-persist--merge-index-with-disk () "Merge `org-persist--index' with the current index file on disk." (let* ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file)) + (file-name-concat org-persist-directory org-persist-index-file)) (disk-index (and (file-exists-p index-file) (org-file-newer-than-p index-file org-persist--index-age) @@ -888,8 +888,8 @@ (defun org-persist--merge-index (base other) (dolist (item (nreverse new)) (unless (or (memq 'index (mapcar #'car (plist-get item :container))) (not (file-exists-p - (org-file-name-concat org-persist-directory - (plist-get item :persist-file)))) + (file-name-concat org-persist-directory + (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) (nreverse combined)) @@ -990,7 +990,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) (persist-file (when collection - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (data nil)) @@ -1078,7 +1078,7 @@ (defun org-persist-write (container &optional associated ignore-return) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) (when (or (file-exists-p org-persist-directory) (org-persist--save-index)) - (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file))) + (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file))) (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection))) (plist-get collection :container)))) (puthash file data org-persist--write-cache) @@ -1098,11 +1098,11 @@ (defun org-persist-write-all (&optional associated) ;; The container is an `index' container. (eq 'index (caar (plist-get (car org-persist--index) :container))) (or (not (file-exists-p org-persist-directory)) - (org-directory-empty-p org-persist-directory))) + (directory-empty-p org-persist-directory))) ;; Do not write anything, and clear up `org-persist-directory' to reduce ;; clutter. (when (and (file-exists-p org-persist-directory) - (org-directory-empty-p org-persist-directory)) + (directory-empty-p org-persist-directory)) (delete-directory org-persist-directory)) ;; Write the data. (let (all-containers) @@ -1143,7 +1143,7 @@ (defun org-persist--gc-persist-file (persist-file) "Garbage collect PERSIST-FILE." (when (file-exists-p persist-file) (delete-file persist-file) - (when (org-directory-empty-p (file-name-directory persist-file)) + (when (directory-empty-p (file-name-directory persist-file)) (delete-directory (file-name-directory persist-file))))) (defmacro org-persist-associated-files:generic (container collection) @@ -1181,7 +1181,7 @@ (defun org-persist-gc () (let (new-index (remote-files-num 0) (orphan-files - (delete (org-file-name-concat org-persist-directory org-persist-index-file) + (delete (file-name-concat org-persist-directory org-persist-index-file) (when (file-exists-p org-persist-directory) (directory-files-recursively org-persist-directory ".+"))))) (dolist (collection org-persist--index) @@ -1189,7 +1189,7 @@ (defun org-persist-gc () (web-file (and file (string-match-p "\\`https?://" file))) (file-remote (when file (file-remote-p file))) (persist-file (when (plist-get collection :persist-file) - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (expired? (org-persist--gc-expired-p diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 03c351cf6..9797a0633 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes) (prompt (let ((default (or (car org-refile-history) (and (assoc cbnex tbl) (setq cdef cbnex) cbnex)))) - (org-format-prompt prompt default))) + (format-prompt prompt default))) pa answ parent-target child parent old-hist) (setq old-hist org-refile-history) (setq answ (funcall cfunc prompt tbl nil (not new-nodes) diff --git a/lisp/org.el b/lisp/org.el index 162982405..15fdd2212 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -19486,7 +19486,7 @@ (defun org-fill-paragraph (&optional justify region) (barf-if-buffer-read-only) (list (when current-prefix-arg 'full) t))) (let ((hash (and (not (buffer-modified-p)) - (org-buffer-hash)))) + (buffer-hash)))) (cond ((and region transient-mark-mode mark-active (not (eq (region-beginning) (region-end)))) @@ -19511,7 +19511,7 @@ (defun org-fill-paragraph (&optional justify region) ;; If we didn't change anything in the buffer (and the buffer was ;; previously unmodified), then flip the modification status back ;; to "unchanged". - (when (and hash (equal hash (org-buffer-hash))) + (when (and hash (equal hash (buffer-hash))) (set-buffer-modified-p nil)) ;; Return non-nil. t)) diff --git a/lisp/ox.el b/lisp/ox.el index d75a80a2e..a3f37b5e8 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4643,11 +4643,11 @@ (defun org-export-resolve-radio-link (link info) Return value can be a radio-target object or nil. Assume LINK has type \"radio\"." - (let ((path (org-string-clean-whitespace (org-element-property :path link)))) + (let ((path (string-clean-whitespace (org-element-property :path link)))) (org-element-map (plist-get info :parse-tree) 'radio-target (lambda (radio) - (and (org-string-equal-ignore-case - (org-string-clean-whitespace (org-element-property :value radio)) + (and (string-equal-ignore-case + (string-clean-whitespace (org-element-property :value radio)) path) radio)) info 'first-match))) diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el index a38d9f979..565539571 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display () (dotimes (_ 2) (goto-char 1) (re-search-forward "\\[") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "example") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "com") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "\\[") (should-not (org-invisible-p)) (re-search-forward "link") (should-not (org-invisible-p)) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (org-toggle-link-display))))) \f diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 0ed44c6af..6a47b3384 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort () "Test aborting a capture process." ;; Newly create capture buffer should not be saved. (let ((capture-file (make-temp-name - (org-file-name-concat + (file-name-concat temporary-file-directory "org-test")))) (unwind-protect -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: v4-0005-org-manual.org-Document-compat-library-installati.patch --] [-- Type: text/x-patch, Size: 2228 bytes --] From 1f086a879fcaeaca3e8b4e1c6a9b6c686e3a2fdf Mon Sep 17 00:00:00 2001 Message-Id: <1f086a879fcaeaca3e8b4e1c6a9b6c686e3a2fdf.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH v4 5/8] org-manual.org: Document compat library installation * doc/org-manual.org (Using Org's git repository): Document that users must also install compat library when using git version of Org. * etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to support older Emacs versions): Announce amendments to the Org installation from git sources. --- doc/org-manual.org | 4 ++++ etc/ORG-NEWS | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/doc/org-manual.org b/doc/org-manual.org index 007126714..89fdd3d0f 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -140,6 +140,10 @@ *** Using Org's git repository (add-to-list 'load-path "~/src/org-mode/lisp") #+end_src +You must also manually install =compat= library required by Org mode. +Using built-in =package.el=, you can run =M-x package-install <RET> +compat <RET>=. + You can also compile with =make=, generate the documentation with =make doc=, create a local configuration with =make config= and install Org with =make install=. Please run =make help= to get the diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 03894f128..6fd117ef7 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Org mode now uses =compat.el= third-party package to support older Emacs versions + +This change is mostly technical and should not affect most users. +However, people who install Org from git source might be affected. +It is now necessary to manually install =compat.el= using Emacs' +package manager. + *** "Priority" used to sort items in agenda is renamed to "urgency" Previously, ~priority-up~ and ~priority-down~ in -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #7: v4-0006-mk-Echo-main-compilation-states-when-running-make.patch --] [-- Type: text/x-patch, Size: 2057 bytes --] From 3ff50698fd9c0d9cf9795f3a7fcef9b3b7730061 Mon Sep 17 00:00:00 2001 Message-Id: <3ff50698fd9c0d9cf9795f3a7fcef9b3b7730061.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Sun, 2 Apr 2023 14:05:22 +0200 Subject: [PATCH v4 6/8] mk: Echo main compilation states when running make * lisp/Makefile (all compile compile-dirty): ($(LISPV)): ($(LISPI)): Echo compile stage. * mk/targets.mk (uppkg): Echo compile stage and hide the installation command. --- lisp/Makefile | 7 +++++-- mk/targets.mk | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/Makefile b/lisp/Makefile index f507f18a2..45d8109f0 100644 --- a/lisp/Makefile +++ b/lisp/Makefile @@ -20,6 +20,7 @@ _ORGCM_ := dirall single source slint1 slint2 # do not clean here, done in toplevel make all compile compile-dirty:: autoloads + @$(info ========= Compiling lisp files using '$(ORGCM)' target) ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),) $(MAKE) compile-$(ORGCM) else @@ -52,12 +53,14 @@ slint1: autoloads: cleanauto $(LISPI) $(LISPV) $(LISPV): $(LISPF) - @echo "org-version: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org version number) + @$(info org-version: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_VERSION) $(LISPI): $(LISPV) $(LISPF) - @echo "org-loaddefs: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org loaddefs) + @$(info org-loaddefs: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_INSTALL) diff --git a/mk/targets.mk b/mk/targets.mk index 18140c5c0..ddd959c61 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -103,6 +103,7 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f endif uppkg:: + $(info ========= Installing required third-party packages) @$(MKDIR) -p $(pkgdir) -@$(INSTALL_PACKAGES) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #8: v4-0007-Makefile-Document-new-targets-in-make-helpall.patch --] [-- Type: text/x-patch, Size: 1521 bytes --] From 6e0254d985970e6a96ad9f0f9a8f9ec377b9dce2 Mon Sep 17 00:00:00 2001 Message-Id: <6e0254d985970e6a96ad9f0f9a8f9ec377b9dce2.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Thu, 13 Apr 2023 14:33:16 +0200 Subject: [PATCH v4 7/8] * Makefile: Document new targets in make helpall Document the newly added cleanpkg and uppkg targets. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f476a3ea7..5e0e0fdff 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ helpall:: $(info Cleaning) $(info ========) $(info make clean - remove built Org ELisp files and documentation) + $(info make cleanpkg - remove third-party packages downloaded via make uppkg) $(info make cleanall - remove everything that can be built and all remnants) $(info make clean-install - remove previous Org installation) $(info ) @@ -81,6 +82,7 @@ helpall:: $(info Convenience) $(info ===========) $(info make up0 - pull from upstream) + $(info make uppkg - download third-party packages required for compilation) $(info make up1 - pull from upstream, build and check) $(info make up2 - pull from upstream, build, check and install) $(info make update - pull from upstream and build) -- 2.40.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #9: v4-0008-lisp-org-compat.el-Throw-error-without-compat-in-.patch --] [-- Type: text/x-patch, Size: 1476 bytes --] From 4316fc76877bea60d89e32af0caf14d4da363f69 Mon Sep 17 00:00:00 2001 Message-Id: <4316fc76877bea60d89e32af0caf14d4da363f69.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko <yantar92@posteo.net> Date: Tue, 18 Apr 2023 13:05:53 +0200 Subject: [PATCH v4 8/8] * lisp/org-compat.el: Throw error without compat in older Emacs Demand compat when using older Emacs. This is a better approach compared to (require 'compat nil 'noerror) because not erring on the `require' would generate a bunch of cryptic errors about functions not being defined from user perspective. --- lisp/org-compat.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index c40510c35..205fb30af 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -94,9 +94,10 @@ (defvar org-fold-core-style) \f ;;; compat.el -;; Do not throw an error when not available - assume latest Emacs -;; version (built-in Org). -(require 'compat nil 'noerror) +;; Use compat for older Emacs, supplying helpful error message if +;; compat is not available. +(when (version< emacs-version "29") + (org-require-package 'compat)) ;; Provide compatibility macros when we are a part of Emacs. ;; See https://elpa.gnu.org/packages/doc/compat.html#Usage -- 2.40.0 [-- Attachment #10: Type: text/plain, Size: 224 bytes --] -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH] epm.el: A CLI tool for package.el 2023-04-30 10:39 ` [PATCH v4] " Ihor Radchenko @ 2023-05-03 12:14 ` Max Nikulin 2023-05-04 10:24 ` Ihor Radchenko 2023-05-06 6:39 ` [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Max Nikulin 1 sibling, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-05-03 12:14 UTC (permalink / raw) To: emacs-orgmode [-- Attachment #1: Type: text/plain, Size: 4229 bytes --] On 30/04/2023 17:39, Ihor Radchenko wrote: > Max Nikulin writes: > >> ./epm.el -Q --epm-dir $(emacs_pkgdir)/emacs-%e install compat > > Good idea. Although, we should not overdo this package management thing. > If we really need complex functionality here, we should better just use > cask/eldev instead of re-inventing the wheel. I have not tried cask or eldev, so I can not reason on supposed workflow. > Are you willing to improve the draft to be ready for upstream? See the attachment. Interface is subject to change to better fit particular use cases. > I think that we need to zoom out a bit and discuss the contexts where > Org build system is used: > > 1. During Org development, by developers who know what they are doing ...and who prefer failure to files installed to unexpected directory when configuration contains a mistake or it is not activated. > 2. By ordinary users, not necessarily familiar with GNU make and all the > associated build process conventions. For those who are not familiar with convention any target may be specified in docs, keeping usual meaning of the default "all" target. > For example, my `package-user-dir' contains a > number of forks with additional patches applied - it is not the > environment I want to develop (and test) Org in. I think, for ordinary user it is better to keep build time and runtime `package-user-dir' the same. Developers, especially when multiple versions are involved, should have isolated sandboxes similar to "python3 -m venv" and activating scripts setting proper environment variables. > Org users will likely use make autoloads, make, make docs, and make > repro. make autoloads should be necessary only to run org uncompiled. My impression is that some bugs may exist, so make clean and make autoloads are necessary during updates. > However, make repro and > optionally make docs should avoid re-using user packages as it may cause > inconsistent results if the `package-user-dir' is messed up. I agree concerning "make repro", but unsure for docs. > One way to handle the above scenarios might be your idea with AUTODEP. > By default, it will be "auto": > - make compile, docs :: Re-use default `package-user-dir' > - make repro :: Auto-download and ignore `package-user-dir' > - other targets :: Prompt the user > Alternatives will be meant to be used as > > AUTODEP=download/user/no make target. > > triggering unconditional downloading, using `package-user-dir', and not > using any guess, correspondingly. In general I agree that strategy may depend on specified target. The only issue that make allows to specify several targets. An I am unsure concerning user prompt. I have realized that as soon as build dependencies are involved, Makefile should use emacs -q, not emacs -Q since -Q excludes site-lisp directories created by e.g. elpa-compat debian package. > I think that it is stretching a bit beyond the complexity we should > allow within Org build system. In your scenario, I can simply do > make cleanpkg and re-download the latest dependencies. I would prefer clear error message that package version is not satisfactory. However such feature may be added later. >> #!/bin/sh >> ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- >> ":"; exec emacs --script "$0" "$@" > > Let's not lock to bash. AFAIK, our makefiles can currently work on > Windows. Using /bin/sh will lead to regression. It is POSIX shell, not BASH. I am unsure if make can be used on windows when e.g. cygwin is not available. Makefiles are full of POSIX tool invocations. Anyway, since emacs binary is customizable in Makefile, the correct way to use this script from Makefile is like (perhaps with more flags) $(EMACS_Q) --script mk/epm.el --epm-dir $(EPMDIR) missing compat A convenience way mk/epm.el -q report compat htmlize is for default emacs from PATH when a user works with shell prompt. >> (dir (directory-file-name (expand-file-name fmt-expanded)))) >> ;; `package-user-dir' ~/.emacs.d/elpa by default >> ;; `package-directory-list' does not include it > > What does this comment refer to? To lack of my experience with package.el and site-lisp infrastructure. [-- Attachment #2: 0001-epm.el-A-CLI-tool-for-package.el.patch --] [-- Type: text/x-patch, Size: 9177 bytes --] From 6e0d73abf527901df080f0f5d7d272722d89c87a Mon Sep 17 00:00:00 2001 From: Max Nikulin <manikulin@gmail.com> Date: Wed, 3 May 2023 18:39:49 +0700 Subject: [PATCH] epm.el: A CLI tool for package.el * mk/epm.el: A helper to install build time dependencies from ELPA. --- mk/epm.el | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100755 mk/epm.el diff --git a/mk/epm.el b/mk/epm.el new file mode 100755 index 000000000..2816702bb --- /dev/null +++ b/mk/epm.el @@ -0,0 +1,243 @@ +#!/bin/sh +":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- +":"; exec emacs --script "$0" "$@" +;;; epm.el --- Emacs package management helper for Org Mode + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; Author: Max Nikulin <manikulin@gmail.com> +;; Created: 2 May 2023 +;; Keywords: maint, tools +;; Package-Requires: ((emacs "26.1")) +;; URL: https://orgmode.org +;; Version: 0.1 + +;; This file is not part of GNU Emacs. +;; +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; epm.el is an attempt to create a tool that allows simple package +;; management outside of interactive Emacs session. Its purpose +;; is dependency management for make based workflow for building +;; and testing and for continuous integration (CI) systems. +;; It install not available yet packages from ELPA. +;; +;; Before compiling or running Org mode uncompiled it is necessary +;; to install dependencies. If libraries are already available +;; in your `load-path' then the following commands should be no-op. +;; +;; As a user who prefers to use Org mode version from git +;; likely you would prefer default ~/emacs.d/elpa directory +;; for installed packages +;; +;; mk/epm.el -q install compat +;; +;; If you are a developer and you need to separate environment from +;; main Emacs configuration, you may choose some alternative +;; package directory and use %e substitution for Emacs version. +;; +;; export EPMDIR="$HOME/.cache/epm/emacs-%e" +;; /path/to/emacs-src/emacs -q --script mk/epm.el install compat +;; +;; or +;; +;; /path/to/emacs-src/emacs -q --script mk/epm.el \ +;; --epm-dir "$HOME/.cache/epm/emacs-%e" install compat +;; +;; Of course, you should specify location to overriden `package-user-dir' +;; in local.mk. +;; +;; When a bug is suspected, it is better to install dependencies +;; e.g. to TMPDIR to avoid issues with content of user init directory. +;; +;; If you prefer to avoid ELPA packages and this script, you still have +;; --directory/-L option and EMACSLOADPATH environment variable +;; to specify where required libraries may be loaded. +;; +;; Since required dependency may be installed e.g. as elpa-compat Debian +;; package, it is not recommended to use --quick/-Q or --no-site-lisp/-nsl +;; options, prefer --no-user-init/-q instead unless you suspect some +;; issue with site-lisp directories. +;; +;; Limitations: +;; - package.el allows to check if minimum version requirement is satisfied +;; for a package, but I have not found API to check it for a library from +;; `load-path'. +;; - Upgrading of a package is not implemented and I am unsure if convenient +;; API exists. +;; - Ideally istead of library list it should be possible to specify .el file +;; and dependencies should be taken from the Package-Requires header. +;; +;; To get list of libraries that are not available run +;; +;; mk/epm.el -q missing compat +;; +;; Non-zero exit code means missing dependencies, its list is printed to stdout. +;; To check which file will be loaded try +;; +;; mk/epm.el -q report htmlize compat +;; +;; Overview of available commands are provided by +;; +;; mk/epm.el -q help + +;;; Code: + +(require 'format-spec) +(require 'package) +(require 'subr-x) + +(defvar epm-dir nil + "Overrides `package-user-dir' and EPMDIR environment.") + +(defun epm--get-script-name () + "Guess command line argument spefifying this script. + +Real argument is not available: +`argi' is \"-scriptload\", `argval' is local variable of `command-line-1', +`load-file-name' is absolute path, `file-relative-name' is too aggressive +and adds \"..\" to root." + (let ((relative (file-relative-name load-file-name + command-line-default-directory))) + (if (string-suffix-p load-file-name relative) + load-file-name + relative))) + +(defvar epm-script-name (epm--get-script-name) + "Name of epm.el as it appears in Emacs command line options") + +(defun epm-nonempty-p (s) + (and s (not (string-empty-p s)))) + +(defun epm-init () + (unless (epm-nonempty-p epm-dir) + (setq epm-dir (getenv "EPMDIR"))) + (when (epm-nonempty-p epm-dir) + (let* ((fmt-expanded (format-spec epm-dir `((?e . ,emacs-version)))) + (dir (directory-file-name (expand-file-name fmt-expanded command-line-default-directory)))) + ;; `package-user-dir' ~/.emacs.d/elpa by default even with -Q + ;; `package-directory-list' does not include `package-user-dir'. + (setq package-user-dir dir))) + ;; TODO (load site-run-file 'no-error 'no-message) + ;; may be necessary to load elpa-* deb packages when -Q option + ;; is used. See Info node "(elisp) Init File". + (package-initialize)) + +(defun epm-library-unavailable-p (lib) + (unless (locate-library lib) + lib)) + +(defun epm-missing (libs) + ;; TODO consider `require' catching load errors + (delq nil (mapcar #'epm-library-unavailable-p libs))) + +(defun epm-cmd-help (_cmd _args) + "List commands." + (princ (format "\ +Usage: %s [--dbg|--debug-on-error] [--epm-dir DIR] COMMAND ARGS... + or: %s --script %s [--dbg|--debug-on-error] [--epm-dir DIR] COMMAND ARGS... + +A CLI tool to install ELPA packages. + +Any Emacs option may be specified, e.g. --quck,-Q, --no-init-file,-q, +or --directory,-L DIR + +--dbg, --debug-on-error + Enable `debug-on-error' + +--epm-dir DIR + Set `package-user-dir'. + \"%%e\" is replaced by `emacs-version'. + Alternatively EPMDIR environment variable may be specified. +\n" + epm-script-name (car command-line-args) epm-script-name)) + (pcase-dolist (`(,name . ,func) epm-commands) + (princ name) + (terpri) + (princ + (replace-regexp-in-string + "\\`\\|\n" "\\1 " + (documentation func) 'fixedcase nil)) + (terpri) + (terpri))) + +(defun epm-cmd-missing (_ libs) + "Report not installed libraries and exit with non-zero code." + (let ((missing (epm-missing libs))) + (when missing + (princ (mapconcat #'identity missing " ")) + (terpri) + (kill-emacs 1)))) + +(defun epm-cmd-install (_ libs) + "Install packages from LIBS that are not available yet" + ;; TODO force option or update command + (let ((missing (epm-missing libs))) + (when missing + (package-refresh-contents) + (make-directory package-user-dir 'parents)) + (dolist (pkg missing) + (package-install (intern pkg))))) + +(defun epm-cmd-report (_ libs) + "Report paths of available libraries" + (princ (format "package-user-dir: %s\n" package-user-dir)) + ;; (princ (format "load-path: %s\n" load-path)) + (dolist (name libs) + ;; (version-to-list version) + (princ (format "%-20s %s " name + (if (package-installed-p (intern name)) + "package " + " "))) + (princ (locate-library name)) + (terpri))) + +(defvar epm-commands + '(("help" . epm-cmd-help) + ("install" . epm-cmd-install) + ("missing" . epm-cmd-missing) + ("report" . epm-cmd-report))) + +(defun epm-command-line-function () + "Handle command line options and arguments specific to epm. + +Implements a handler for `command-line-functions'." + ;; There is no easy to determine if "--" argument has been processed earlier. + ;; TODO "--option=value" is handled by `command-line-1' only for standard arguments. + (pcase argi + ("--epm-dir" + (setq epm-dir (pop command-line-args-left)) + t) + ((or "--dbg" "--debug-on-error") + ;; -d is handled as --display, --debug as --debug-init + (setq debug-on-error t) + t) + ((pred (string-match-p "\\`[^-]")) + (epm-init) + (let ((func (cdr (assoc argi epm-commands))) + (cmd-args command-line-args-left)) + (if (not func) + (error "Unknown command %s" argi) + (setq command-line-args-left nil) + (funcall func argi cmd-args))) + t))) + +(push #'epm-command-line-function command-line-functions) + +;; Local Variables: +;; no-byte-compile: t +;; End: +;;; epm.el ends here -- 2.25.1 ^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH] epm.el: A CLI tool for package.el 2023-05-03 12:14 ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin @ 2023-05-04 10:24 ` Ihor Radchenko 2023-05-04 16:16 ` Max Nikulin 0 siblings, 1 reply; 36+ messages in thread From: Ihor Radchenko @ 2023-05-04 10:24 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: >> Good idea. Although, we should not overdo this package management thing. >> If we really need complex functionality here, we should better just use >> cask/eldev instead of re-inventing the wheel. > > I have not tried cask or eldev, so I can not reason on supposed workflow. Cask basically solves dependency management, including tracking outdated dependencies. See https://cask.readthedocs.io/en/latest/guide/usage.html#quickstart It can also be used from Makefile. The downside is that it has to be installed separately. >> Are you willing to improve the draft to be ready for upstream? > > See the attachment. Interface is subject to change to better fit > particular use cases. Thanks! >> 2. By ordinary users, not necessarily familiar with GNU make and all the >> associated build process conventions. > > For those who are not familiar with convention any target may be > specified in docs, keeping usual meaning of the default "all" target. I am mostly concerned about the existing users who are already settled on running the default "make". Their workflow will be broken with your suggestion. >> However, make repro and >> optionally make docs should avoid re-using user packages as it may cause >> inconsistent results if the `package-user-dir' is messed up. > > I agree concerning "make repro", but unsure for docs. I am also unsure about docs. Might be either way. > In general I agree that strategy may depend on specified target. The > only issue that make allows to specify several targets. I am not sure what will be the problem there. make all is also technically several targets. And running something like make compile repro is a bit silly anyway. > An I am unsure concerning user prompt. My main concern is for the users who changed their elpa directory location. They might run into issues unexpectedly. >> I think that it is stretching a bit beyond the complexity we should >> allow within Org build system. In your scenario, I can simply do >> make cleanpkg and re-download the latest dependencies. > > I would prefer clear error message that package version is not > satisfactory. However such feature may be added later. I think package.el technically suffers from the same problem. I do not think that we need to work around it ahead of Emacs. Not until it proves necessary. (and even then, we should better contribute upstream anyway) >>> #!/bin/sh >>> ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- >>> ":"; exec emacs --script "$0" "$@" >> >> Let's not lock to bash. AFAIK, our makefiles can currently work on >> Windows. Using /bin/sh will lead to regression. > > It is POSIX shell, not BASH. I am unsure if make can be used on windows > when e.g. cygwin is not available. Makefiles are full of POSIX tool > invocations. I thought that more portable way is using "env". > +(defun epm-nonempty-p (s) > + (and s (not (string-empty-p s)))) Can just use `seq-empty-p'. > + ;; TODO (load site-run-file 'no-error 'no-message) > + ;; may be necessary to load elpa-* deb packages when -Q option > + ;; is used. See Info node "(elisp) Init File". Given the explanation in the top comment, is this necessary? > +(defun epm-library-unavailable-p (lib) > + (unless (locate-library lib) > + lib)) > +(defun epm-missing (libs) > + ;; TODO consider `require' catching load errors > + (delq nil (mapcar #'epm-library-unavailable-p libs))) Maybe just (cl-remove-if #'locate-library libs)? -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] epm.el: A CLI tool for package.el 2023-05-04 10:24 ` Ihor Radchenko @ 2023-05-04 16:16 ` Max Nikulin 2023-05-05 9:39 ` Ihor Radchenko 0 siblings, 1 reply; 36+ messages in thread From: Max Nikulin @ 2023-05-04 16:16 UTC (permalink / raw) To: emacs-orgmode On 04/05/2023 17:24, Ihor Radchenko wrote: > Max Nikulin writes: >> For those who are not familiar with convention any target may be >> specified in docs, keeping usual meaning of the default "all" target. > > I am mostly concerned about the existing users who are already settled > on running the default "make". Their workflow will be broken with your > suggestion. I hope, it is possible to achieve helpful error message with a link explaining change. >> An I am unsure concerning user prompt. > > My main concern is for the users who changed their elpa directory > location. They might run into issues unexpectedly. My opinion is that an error is better for make than user prompt. Try to load from default `package-user-dir' but install there only if it is explicitly enabled. >>>> #!/bin/sh >>>> ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- >>>> ":"; exec emacs --script "$0" "$@" >>> >>> Let's not lock to bash. AFAIK, our makefiles can currently work on >>> Windows. Using /bin/sh will lead to regression. > > I thought that more portable way is using "env". Either env would invoke sh anyway (like in org publish scripts) or it is necessary to use env -S feature of relatively recent GNU env. For cmd.exe it is better to provide a .bat file running emacs --script epm.el ...(something for POSIX $@) >> +(defun epm-nonempty-p (s) >> + (and s (not (string-empty-p s)))) > > Can just use `seq-empty-p'. I am neutral in respect to such change. I just decided to minimize dependencies. >> + ;; TODO (load site-run-file 'no-error 'no-message) >> + ;; may be necessary to load elpa-* deb packages when -Q option >> + ;; is used. See Info node "(elisp) Init File". > > Given the explanation in the top comment, is this necessary? Do you have any arguments against switching from emacs -Q to emacs -q? I am still unsure if it is safe enough, but not doing it is not better. I am considering adding -q to this script when it is called directly. Unfortunately Emacs does not have an option to override effect of -q. ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH] epm.el: A CLI tool for package.el 2023-05-04 16:16 ` Max Nikulin @ 2023-05-05 9:39 ` Ihor Radchenko 0 siblings, 0 replies; 36+ messages in thread From: Ihor Radchenko @ 2023-05-05 9:39 UTC (permalink / raw) To: Max Nikulin; +Cc: emacs-orgmode Max Nikulin <manikulin@gmail.com> writes: > Do you have any arguments against switching from emacs -Q to emacs -q? I > am still unsure if it is safe enough, but not doing it is not better. I > am considering adding -q to this script when it is called directly. > Unfortunately Emacs does not have an option to override effect of -q. Given that --batch implies -q, it should be relatively safe. Maybe except make repro, where we want to minimize environment effects. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) 2023-04-30 10:39 ` [PATCH v4] " Ihor Radchenko 2023-05-03 12:14 ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin @ 2023-05-06 6:39 ` Max Nikulin 1 sibling, 0 replies; 36+ messages in thread From: Max Nikulin @ 2023-05-06 6:39 UTC (permalink / raw) To: emacs-orgmode On 30/04/2023 17:39, Ihor Radchenko wrote: > Date: Mon, 3 Apr 2023 10:41:50 +0200 > Subject: [PATCH v4 4/8] Use compat.el library instead of ad-hoc compatibility > function set Ihor, I have not noticed removal of > ;; `flatten-tree' was added in Emacs 27.1. > (defalias 'org-protocol-flatten > (if (fboundp 'flatten-tree) 'flatten-tree from org-protocol.el Perhaps I will post more comments, so there is no point to send updated patch set in response to this message. ^ permalink raw reply [flat|nested] 36+ messages in thread
end of thread, other threads:[~2023-05-06 6:48 UTC | newest] Thread overview: 36+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-10-11 10:36 Useful package? Compat.el Timothy 2021-10-11 14:28 ` Russell Adams 2021-10-11 14:40 ` Timothy 2021-10-11 18:04 ` Joost Kremers 2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko 2023-01-27 13:34 ` [POLL] Use compat.el in Org? Bastien Guerry 2023-01-27 20:38 ` Tim Cross 2023-01-27 21:38 ` Daniel Mendler 2023-01-27 22:29 ` Samuel Wales 2023-01-28 16:04 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Kyle Meyer 2023-01-30 11:35 ` Greg Minshall 2023-01-30 19:33 ` Ihor Radchenko 2023-01-30 19:40 ` Greg Minshall 2023-01-30 21:38 ` Daniel Mendler 2023-04-01 10:31 ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Ihor Radchenko 2023-04-01 11:38 ` Daniel Mendler 2023-04-01 14:20 ` Max Nikulin 2023-04-02 8:52 ` Ihor Radchenko 2023-04-02 15:31 ` Max Nikulin 2023-04-02 16:04 ` Ihor Radchenko 2023-04-02 16:37 ` Max Nikulin 2023-04-02 17:00 ` [PATCH v2] " Ihor Radchenko 2023-04-03 8:46 ` [PATCH v3] " Ihor Radchenko 2023-04-08 11:15 ` [PATCH v2] " Max Nikulin 2023-04-08 11:41 ` Ihor Radchenko 2023-04-08 16:37 ` Max Nikulin 2023-04-13 12:42 ` Ihor Radchenko 2023-04-17 17:20 ` Max Nikulin 2023-04-20 9:27 ` Ihor Radchenko 2023-04-28 15:27 ` Max Nikulin 2023-04-30 10:39 ` [PATCH v4] " Ihor Radchenko 2023-05-03 12:14 ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin 2023-05-04 10:24 ` Ihor Radchenko 2023-05-04 16:16 ` Max Nikulin 2023-05-05 9:39 ` Ihor Radchenko 2023-05-06 6:39 ` [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Max Nikulin
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).