See attached a new patch series Things that are different:
When installing packages I still override `package-user-dir' to install them into "$(pkgdir)" but when doing other things, I simply add the directory to `package-directory-list' so that users can still use `package-user-dir' if they so choose. However, this could have bad consequences for people using multiple emacs versions that only overwrite `EMACSLOADPATH` and not `package-user-dir'. I'm not familiar with how most people do multiple Emacs versions so please let me know if this is a concern. I added a simple override flag to skip cleanpkg when doing the repro target I switched org-dependencies.el to use `lm-package-requires' and then added emacs 28 and 29 compatibility. (turns out Emacs 29 does not have that function) Ihor Radchenko <[email protected]> writes: > Morgan Smith <[email protected]> writes: > >> ... I'd be >> interested in knowing how you figure out what functions are available in >> what versions of Emacs. > > Some functions have this information in help buffer. > But in most cases, I simply run emacs-28, emacs-29, emacs-30, ... > and check if a given function is available. > > Another possibility is checking git history on function source in Emacs > git sources. I was hoping for something a little more automated. Thanks anyways! >>>> 1. emacs-28 has issues with elpa signature >> >> Can't reproduce that locally. I assume your emacs-28 package depends on >> outdated certificates or something? Seems like a package issue, not an >> Emacs issue. > > Interesting. In any case, I think it is no longer relevant. Emacs 31 is > soon-to-be-released. On main, we can already drop emacs-28 support. I get that we're all excited to drop Emacs 28 support but only checking current Emacs (which doesn't need compat) and Emacs 29 doesn't feel like enough testing of this feature for me. So I am also testing it with Emacs 28 myself. > >> I can't help but feel like we are adding complexity for little benefit. >> Currently it is easy to work on org-mode completely offline. With this >> change installed an accidental "git clean -xfd" (which I do all the >> time) will bring an offline development session to a halt (assuming the >> hacker is using an older emacs). > > Yes, I have been thinking about this from the very beginning when adding > compat was suggested. For now, Org does not have any non-optional > third-party dependencies. Adding compat means we will have one. > But I think that it is worth it, especially given that adding compat > will reduce maintenance burden significantly. I remember countless times > when we have to carefully think about supporting/not supporting old > Emacs versions. Compat will make our life much easier. Maybe it is important to note that this is a non-optional third-party dependency for older emacs only. I imagine most developers will be on the latest Emacs so I suppose it is possible it is not as big a deal as I think it is >> I wish there was a better way to leverage packages installed on a user's >> system. This change completely overrides "package-user-dir". > > Maybe we can use package-directory-list. Done! > Daniel also suggested another approach - ship compat together with Org > mode, just as Emacs ships third-party libraries. Not for ELPA, just for > git repository. > > The idea is to keep your code, but *commit* the compat to Git repo. > Then, we can have a special make target to update compat in git. > WDYT? I've spent a lot of time unvendoring code for the Guix project so asking me to vendor code feels very wrong. I don't really have a good argument against doing it other then that one though. Are git submodules any good these days? Last I tried they where terrible but also getting regular improvements (this was like 4 years ago). If we combine the fact that this is a non-issue on the latest emacs + will now be able to use a user's compat installed in `package-user-dir' + we offer a way to download compat into the repo; maybe we can just call that good enough?
>From 8a5b060a9a2735593fa04dea17e5537c561ab313 Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Mon, 18 May 2026 23:53:11 -0400 Subject: [PATCH 1/7] mk/org-fixup.el: Remove dependency on org-compat.el This simply isn't needed and will simplify the dependency tree slightly. * mk/org-fixup.el: * mk/default.mk (MAKE_ORG_INSTALL, MAKE_ORG_VERSION, MAKE_LOCAL_MK): * doc/Makefile (%_letter.tex): Don't load "org-compat.el". * lisp/org-compat.el: Run "(org-assert-version)" because we can now. --- doc/Makefile | 1 - lisp/org-compat.el | 4 +--- mk/default.mk | 3 --- mk/org-fixup.el | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 0a56dbdd9..1b32dcf2d 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -105,6 +105,5 @@ endif %_letter.tex: %.tex $(BATCH) \ --eval '(add-to-list `load-path "../lisp")' \ - --eval '(load "org-compat.el")' \ --eval '(load "../mk/org-fixup.el")' \ --eval '(org-make-letterformat "$(<F)" "$(@F)")' diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 75e772a17..bc617b8e6 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -36,9 +36,7 @@ (eval-when-compile (require 'subr-x)) ; Emacs < 28 -;; We rely on org-compat when generating Org version. Checking Org -;; version here will interfere with Org build process. -;; (org-assert-version) +(org-assert-version) (declare-function org-agenda-diary-entry "org-agenda") (declare-function org-agenda-maybe-redo "org-agenda" ()) diff --git a/mk/default.mk b/mk/default.mk index 9ecda3c10..acc0a3866 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -129,7 +129,6 @@ BATCHO = $(BATCH) \ # How to generate local.mk MAKE_LOCAL_MK = $(BATCHO) \ - --eval '(load "org-compat.el")' \ --eval '(load "../mk/org-fixup.el")' \ --eval '(org-make-local-mk)' @@ -139,13 +138,11 @@ BATCHL = $(BATCH) \ # How to generate org-loaddefs.el MAKE_ORG_INSTALL = $(BATCHL) \ - --eval '(load "org-compat.el")' \ --eval '(load "../mk/org-fixup.el")' \ --eval '(org-make-org-loaddefs)' # How to generate org-version.el MAKE_ORG_VERSION = $(BATCHL) \ - --eval '(load "org-compat.el")' \ --eval '(load "../mk/org-fixup.el")' \ --eval '(org-make-org-version "$(ORGVERSION)" "$(GITVERSION)")' diff --git a/mk/org-fixup.el b/mk/org-fixup.el index 451da335b..8a97abb52 100644 --- a/mk/org-fixup.el +++ b/mk/org-fixup.el @@ -24,8 +24,6 @@ ;; ;;; Commentary: -(require 'org-compat "org-compat.el") - (defun org-make-manual () "Generate the Texinfo file out of the Org manual." (require 'ox-texinfo) base-commit: 3be43293849b49a17ec78b889b1f9cf359a3248f -- 2.54.0
>From 705f7e23e730bb339010c4cce12e43baff2d1781 Mon Sep 17 00:00:00 2001 From: Ihor Radchenko <[email protected]> Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH 2/7] Upgrade Org build system to handle third-party dependencies * mk/org-dependencies.el: New file (org-dependencies-installed-p): A way to check if dependencies are installed. (org-install-dependencies): A way to install 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. (EMACSQ): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (checkpkg): New target to ensure packages are installed. (check test): (repro): (compile compile-dirty): Use the new checkpkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_DEST): 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. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost Co-authored-by: Morgan Smith <[email protected]> --- .gitignore | 1 + mk/default.mk | 15 ++++-- mk/org-dependencies.el | 105 +++++++++++++++++++++++++++++++++++++++++ mk/targets.mk | 32 ++++++++++--- 4 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 mk/org-dependencies.el diff --git a/.gitignore b/.gitignore index 0eb5d834a..e12bde7b6 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 acc0a3866..5a2eac556 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,11 @@ 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) + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -117,11 +123,14 @@ REPRO = $(NOBATCH) $(BTEST_INIT) $(REPRO_INIT) $(REPRO_ARGS) # start Emacs with no user and site configuration # EMACSQ = -vanilla # XEmacs -EMACSQ = $(EMACS) -Q +EMACSQ = $(EMACS) -Q \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(add-to-list `package-directory-list "$(pkgdir)")' \ + -f package-initialize # Using emacs in batch mode. -BATCH = $(EMACSQ) -batch \ - --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' +BATCH = $(EMACSQ) -batch # Emacs must be started in toplevel directory BATCHO = $(BATCH) \ diff --git a/mk/org-dependencies.el b/mk/org-dependencies.el new file mode 100644 index 000000000..e7bfb9fe9 --- /dev/null +++ b/mk/org-dependencies.el @@ -0,0 +1,105 @@ +;;; org-dependencies.el --- Ensure dependencies are met in the development repository -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Morgan Smith + +;; Author: Morgan Smith <[email protected]> +;; Keywords: + +;; This file is not part of GNU Emacs. + +;; This program 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. + +;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'package) +(require 'lisp-mnt) + +(cl-macrolet + ((static-when (condition &rest body) + (when (eval condition lexical-binding) + (cons 'progn body)))) + (static-when (version< emacs-version "29.9999") + (defun lm--prepare-package-dependencies (deps) + "Turn DEPS into an acceptable list of dependencies. + +Any parts missing a version string get a default version string +of \"0\" (meaning any version) and an appropriate level of lists +is wrapped around any parts requiring it." + (cond + ((not (listp deps)) + (error "Invalid requirement specifier: %S" deps)) + (t (mapcar (lambda (dep) + (cond + ((symbolp dep) `(,dep "0")) + ((stringp dep) + (error "Invalid requirement specifier: %S" dep)) + ((and (listp dep) (null (cdr dep))) + (list (car dep) "0")) + (t dep))) + deps)))) + + (declare-function package-read-from-string "package" (str)) + + (defun lm-package-requires (&optional file) + "Return dependencies listed in file FILE, or current buffer if FILE is nil. +The return value is a list of elements of the form (PACKAGE VERSION) +where PACKAGE is the package name (a symbol) and VERSION is the +package version (a string)." + (require 'package) + (lm-with-file file + (and-let* ((require-lines (lm-header-multiline "package-requires"))) + (lm--prepare-package-dependencies + (package-read-from-string (mapconcat #'identity require-lines " ")))))))) + +(defvar org-dependencies--internal-cache nil) + +(defun org-dependencies () + "Get a list of dependencies from org.el. +Each item is a list of (PACKAGE MINIMUM-VERSION)." + (or org-dependencies--internal-cache + (setq org-dependencies--internal-cache + (lm-package-requires (locate-file "org.el" load-path))))) + +(defun org-dependencies-installed-p () + "Check if all the dependencies from `org-dependencies' are installed. +Throw an error if they are not installed." + (let ((backtrace-on-error-noninteractive nil)) + (dolist (dep (org-dependencies)) + (let ((package (car dep)) + (version (nth 1 dep))) + (when (not (package-installed-p package (version-to-list version))) + (if (package-installed-p package) + (error "ERROR: Package %S does not satisfy version requirement of %S + Consider running \"make uppkg\" to install dependencies" + package version) + (error "ERROR: Package %S not installed + Consider running \"make uppkg\" to install dependencies" + package))))) + t)) + +(defun org-install-dependencies () + "Install missing dependencies from `org-dependencies'." + (unless (ignore-errors (org-dependencies-installed-p)) + (package-refresh-contents) + (dolist (dep (org-dependencies)) + (let ((package (car dep)) + (version (nth 1 dep))) + (unless (package-installed-p package (version-to-list version)) + (let ((package-install-upgrade-built-in t)) + (package-install package))))))) + +(provide 'org-dependencies) +;;; org-dependencies.el ends here diff --git a/mk/targets.mk b/mk/targets.mk index a8bec6813..c9ac9aa5d 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -29,18 +29,18 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single native $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg checkpkg single native $(SUBDIRS) \ check test test-dirty install install-info $(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_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 ELN ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION @@ -91,7 +91,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: checkpkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -100,13 +100,24 @@ vanilla: -@$(NOBATCH) & check test:: compile -check test test-dirty:: +check test test-dirty:: checkpkg -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around for inspection $(MAKE) cleantest endif +checkpkg: + $(BATCHO) --eval '(load "../mk/org-dependencies.el")' \ + -f org-dependencies-installed-p + +uppkg: + $(info ========= Installing required third-party packages) + # package-user-dir is used for install location + $(BATCHO) --eval '(setq package-user-dir "$(pkgdir)")' \ + --eval '(load "../mk/org-dependencies.el")' \ + -f org-install-dependencies + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -130,7 +141,8 @@ $(INSTSUB): autoloads: lisp $(MAKE) -C $< $@ -repro: cleanall autoloads +repro: SKIP_CLEANPKG = yes +repro: cleanall checkpkg autoloads -@$(REPRO) & $(GITDIR): @@ -150,7 +162,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest cleangithooks +cleanall: cleandirs cleantest cleangithooks cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -175,3 +187,9 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: +ifeq ($(SKIP_CLEANPKG),) +else + -$(RMR) $(pkgdir_top) +endif -- 2.54.0
>From cd615421b62e05865f798032fed998dd992d3b6e Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Fri, 15 May 2026 16:40:48 -0400 Subject: [PATCH 3/7] Add compat.el dependency * lisp/org.el: Add Compat to package-requires. Co-authored-by: Ihor Radchenko <[email protected]> --- lisp/org.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/org.el b/lisp/org.el index 2071a9dc0..4f15fed7c 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;; Maintainer: Ihor Radchenko <[email protected]> ;; Keywords: outlines, hypermedia, calendar, text ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "28.2")) +;; Package-Requires: ((emacs "28.2") (compat "31")) ;; Version: 10.0-pre -- 2.54.0
>From 301eede5f261f86f085b9d5667383006dba4cde8 Mon Sep 17 00:00:00 2001 From: Morgan Smith <[email protected]> Date: Mon, 18 May 2026 23:19:26 -0400 Subject: [PATCH 4/7] lisp/org-compat.el: Use compat and obsolete old functions * lisp/org-compat.el: Require 'compat. 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', `org-list-of-strings-p', `org-assoc-delete-all', `org--flatten-tree', `org-completion-table-with-metadata', `org-babel-local-file-name' Co-authored-by: Ihor Radchenko <[email protected]> --- lisp/org-compat.el | 254 ++++++--------------------------------------- 1 file changed, 34 insertions(+), 220 deletions(-) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index bc617b8e6..aff1782ed 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -34,6 +34,8 @@ (require 'seq) (require 'org-macs) +(require 'compat) + (eval-when-compile (require 'subr-x)) ; Emacs < 28 (org-assert-version) @@ -81,9 +83,6 @@ (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)) (declare-function decoded-time-add "time-date" (time delta)) (defvar calendar-mode-map) @@ -97,18 +96,39 @@ org-table-tab-recognizes-table.el (defvar org-table1-hline-regexp) (defvar org-fold-core-style) +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "10.0") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "10.0") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "10.0") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "10.0") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "10.0") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "10.0") +(define-obsolete-function-alias 'org-xor + 'xor "10.0") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "10.0") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "10.0") +(define-obsolete-function-alias 'org-list-of-strings-p + 'list-of-strings-p "10.0") +(define-obsolete-function-alias 'org-assoc-delete-all + 'assoc-delete-all "10.0") +(define-obsolete-function-alias 'org--flatten-tree + 'flatten-tree "10.0") +(define-obsolete-function-alias 'org-completion-table-with-metadata + 'completion-table-with-metadata "10.0") +(define-obsolete-function-alias 'org-babel-local-file-name + 'file-local-name "10.0") + ;;; Emacs < 31 compatibility -(if (fboundp 'completion-table-with-metadata) - (defalias 'org-completion-table-with-metadata #'completion-table-with-metadata) - (defun org-completion-table-with-metadata (table metadata) - "Return new completion TABLE with METADATA. -METADATA should be an alist of completion metadata. See -`completion-metadata' for a list of supported metadata." - (lambda (string pred action) - (if (eq action 'metadata) - `(metadata . ,metadata) - (complete-with-action action table string pred))))) ;; Broken for negative months before emacs commit bc33b70b280 (if (version< "31" emacs-version) @@ -147,40 +167,6 @@ org-fold-core-style (delete-other-windows window) window))) -(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)))) - (defun org-buffer-text-pixel-width () "Return pixel width of text in current buffer. This function uses `buffer-text-pixel-size', when available, and falls @@ -243,77 +229,6 @@ org-buffer-text-pixel-width Ignore optional argument." (get-buffer-create buffer-or-name))) -(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 concatenating." - (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))) - ": "))) - -(if (fboundp 'list-of-strings-p) - (defalias 'org-list-of-strings-p #'list-of-strings-p) - ;; From Emacs subr.el. -;;;###autoload - (defun org-list-of-strings-p (object) - "Return t if OBJECT is nil or a list of strings." - (declare (pure t) (side-effect-free error-free)) - (while (and (consp object) (stringp (car object))) - (setq object (cdr object))) - (null object))) - ;;; Emacs < 27.1 compatibility @@ -325,25 +240,6 @@ org-buffer-text-pixel-width `(progn ,@body)) (defalias 'org-combine-change-calls 'combine-change-calls)) -;; `flatten-tree' was added in Emacs 27.1. -(if (fboundp 'flatten-tree) - (defalias 'org--flatten-tree #'flatten-tree) - ;; The implementation is taken from Emacs subr.el 8664ba18c7c5. - (defun org--flatten-tree (tree) - "Return a \"flattened\" copy of TREE. - -A `flatten-tree' polyfill for compatibility with Emacs versions -older than 27.1" - (let (elems) - (while (consp tree) - (let ((elem (pop tree))) - (while (consp elem) - (push (cdr elem) tree) - (setq elem (car elem))) - (if elem (push elem elems)))) - (if tree (push tree elems)) - (nreverse elems)))) - (with-no-warnings ; `replace-buffer-contents' is obsolete in Emacs 31 (cond ((version< emacs-version "27.1") @@ -355,22 +251,6 @@ org-buffer-text-pixel-width (defsubst org-replace-buffer-contents (source &optional max-secs max-costs) (replace-region-contents (point-min) (point-max) source max-secs max-costs))))) -(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)) @@ -400,30 +280,7 @@ org--set-faces-extend (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 +(define-obsolete-function-alias 'org-babel-edit-distance 'string-distance "9.5") (unless (fboundp 'with-connection-local-variables) @@ -436,24 +293,6 @@ 'org-babel-edit-distance `(with-connection-local-profiles (connection-local-get-profiles nil) ,@body))) -;; assoc-delete-all missing from 26.1 -(if (fboundp 'assoc-delete-all) - (defalias 'org-assoc-delete-all 'assoc-delete-all) - ;; from compat/compat-27.el - (defun org-assoc-delete-all (key alist &optional test) - "Delete all matching key from alist, default test equal" - (unless test (setq test #'equal)) - (while (and (consp (car alist)) - (funcall test (caar alist) key)) - (setq alist (cdr alist))) - (let ((tail alist) tail-cdr) - (while (setq tail-cdr (cdr tail)) - (if (and (consp (car tail-cdr)) - (funcall test (caar tail-cdr) key)) - (setcdr tail (cdr tail-cdr)) - (setq tail tail-cdr)))) - alist)) - ;;; Emacs < 26.1 compatibility @@ -461,23 +300,6 @@ 'org-babel-edit-distance (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))) - ;;; Obsolete aliases (remove them after the next major release). @@ -1630,14 +1452,6 @@ org-kill-new string) (apply 'kill-new string args)) -;; `file-local-name' was added in Emacs 26.1. -(defalias 'org-babel-local-file-name - (if (fboundp 'file-local-name) - 'file-local-name - (lambda (file) - "Return the local name component of FILE." - (or (file-remote-p file 'localname) file)))) - ;;;###autoload (defmacro org-check-version () "Try very hard to provide sensible version strings." -- 2.54.0
>From 8665a0bca073a7dd6b2fc03e7303ddb8a91b7431 Mon Sep 17 00:00:00 2001 From: Ihor Radchenko <[email protected]> Date: Mon, 3 Apr 2023 10:41:50 +0200 Subject: [PATCH 5/7] Use compat.el library instead of ad-hoc compatibility function set * lisp/org.el (org-fill-paragraph): * lisp/ob-core.el (org-babel-results-keyword) (org-babel-check-src-block, org-babel-insert-result) (org-babel-process-file-name): * lisp/ob-gnuplot.el (org-babel-gnuplot-process-vars): * lisp/oc-basic.el (org-cite-basic--parse-bibliography) (org-cite-basic--close-keys): * 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, org-insert-link): * lisp/org-attach.el (org-attach-sync): * lisp/org-capture.el (org-capture-place-item) (org-capture-fill-template): * lisp/org-colview.el (org-columns--summary-types-completion-function): * lisp/org-element.el (org-element-drawer-parser): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el (org-lint-duplicate-custom-id): * lisp/org-num.el (org-num-skip-tags): * lisp/org-persist.el (org-persist--load-index, org-persist-write:file) (org-persist-write:url, org-persist-write:index) (org-persist--merge-index-with-disk, org-persist--merge-index) (org-persist-read, org-persist-write, org-persist-write-all) (org-persist--gc-persist-file, org-persist--refresh-gc-lock) (org-persist--gc-orphan-p, org-persist-gc): * lisp/org-protocol.el (org-protocol-flatten-greedy) (org-protocol-flatten): * lisp/org-src.el (org-src--get-known-shells): * 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): Use functions provided by compat.el. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost Co-authored-by: Ihor Radchenko <[email protected]> --- lisp/ob-core.el | 16 ++++++------ lisp/ob-gnuplot.el | 2 +- lisp/oc-basic.el | 6 ++--- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +++--- lisp/ol.el | 6 ++--- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +++--- lisp/org-colview.el | 2 +- lisp/org-element.el | 2 +- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-num.el | 2 +- lisp/org-persist.el | 44 ++++++++++++++++---------------- lisp/org-protocol.el | 4 +-- lisp/org-refile.el | 2 +- lisp/org-src.el | 2 +- lisp/org.el | 4 +-- lisp/ox.el | 6 ++--- testing/lisp/test-ol.el | 10 ++++---- testing/lisp/test-org-capture.el | 2 +- 21 files changed, 67 insertions(+), 67 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index 7f283012c..e8007c677 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -144,7 +144,7 @@ org-babel-results-keyword :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. @@ -1059,7 +1059,7 @@ 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)))) @@ -2746,13 +2746,13 @@ org-babel-insert-result (closing-line (concat "#+end_" type))) (cond ;; Do nothing if type is "no" or "nil" - ((or (org-string-equal-ignore-case type "nil") - (org-string-equal-ignore-case type "no")) + ((or (string-equal-ignore-case type "nil") + (string-equal-ignore-case type "no")) nil) ;; 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)))) @@ -2763,14 +2763,14 @@ org-babel-insert-result 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 (`(,_) @@ -3560,7 +3560,7 @@ org-babel-process-file-name remotely. The file name is then processed by `expand-file-name'. Unless second argument NO-QUOTE-P is non-nil, the file name is additionally processed by `shell-quote-argument'." - (let ((f (org-babel-local-file-name (expand-file-name name)))) + (let ((f (file-local-name (expand-file-name name)))) (if no-quote-p f (shell-quote-argument f)))) (defvar org-babel-temporary-directory diff --git a/lisp/ob-gnuplot.el b/lisp/ob-gnuplot.el index eda902f9e..33e2c23ef 100644 --- a/lisp/ob-gnuplot.el +++ b/lisp/ob-gnuplot.el @@ -109,7 +109,7 @@ org-babel-gnuplot-process-vars (org-babel-temp-directory) "/gnuplot/" (file-remote-p val 'host) - (org-babel-local-file-name val)))) + (file-local-name val)))) (if (and (file-exists-p local-name) ;; only download file if remote is newer (file-newer-than-file-p local-name val)) local-name diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index c8f0f80f9..fc28fffbd 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -312,11 +312,11 @@ org-cite-basic--parse-bibliography (setq file (file-truename file)) (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))) @@ -570,7 +570,7 @@ org-cite-basic--close-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 31d52edbc..dda73474f 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1049,7 +1049,7 @@ org-cite-adjust-note (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 1964efdd7..987a7ed17 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -97,8 +97,8 @@ org-gnus-group-link `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)))) @@ -115,7 +115,7 @@ org-gnus-article-link 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" @@ -164,7 +164,7 @@ 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 3d0e32bcc..5bc8350ba 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -2673,8 +2673,8 @@ org-store-link (set-mark (point))))) (setq org-store-link-plist nil) ;; Negate `org-link-context-for-files' when given a single universal arg. - (let ((org-link-context-for-files (org-xor org-link-context-for-files - (equal arg '(4)))) + (let ((org-link-context-for-files (xor org-link-context-for-files + (equal arg '(4)))) link desc search agenda-link) ;; description (cond ;; Store a link using an external link type, if any function is @@ -2963,7 +2963,7 @@ org-insert-link org-link--insert-history))) (setq link (org-completing-read - (org-format-prompt "Insert link" (caar org-stored-links)) + (format-prompt "Insert link" (caar org-stored-links)) (append (mapcar (lambda (x) (concat x ":")) all-prefixes) (mapcar #'car org-stored-links) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index f44340fc7..07366afb0 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -732,7 +732,7 @@ 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 9712244df..c9c1497e5 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1444,9 +1444,9 @@ 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. @@ -2014,7 +2014,7 @@ org-capture-fill-template (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-colview.el b/lisp/org-colview.el index 66fdb911f..9c0ae7317 100644 --- a/lisp/org-colview.el +++ b/lisp/org-colview.el @@ -1144,7 +1144,7 @@ org-columns--summary-types-completion-function (doc (and doc (substring doc 0 (string-search "\n" doc))))) (if doc (format " -- %s" doc) "")))) (completion-table - (org-completion-table-with-metadata + (completion-table-with-metadata (lambda (str predicate action) (complete-with-action action candidates str predicate)) `(metadata . ((annotation-function . ,annotation-function)))))) diff --git a/lisp/org-element.el b/lisp/org-element.el index 58c65ad08..462692e90 100644 --- a/lisp/org-element.el +++ b/lisp/org-element.el @@ -1071,7 +1071,7 @@ org-element-drawer-parser (and contents-begin ;; We might be dealing with broken properties ;; drawer. Every change inside is sensitive. - (not (org-string-equal-ignore-case name "PROPERTIES")) + (not (string-equal-ignore-case name "PROPERTIES")) ;; Inserting blank line at contents-begin ;; will trigger :pre-blank change and may not ;; be robust. diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 5aef5002f..a9222b0a1 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -868,7 +868,7 @@ org-fold-core-next-visibility-change (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 df5c0d578..d5fe02100 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -424,7 +424,7 @@ org-lint-duplicate-custom-id 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-begin property)) diff --git a/lisp/org-num.el b/lisp/org-num.el index 7e07300ff..d2dd77a1c 100644 --- a/lisp/org-num.el +++ b/lisp/org-num.el @@ -140,7 +140,7 @@ org-num-skip-tags :group 'org-appearance :package-version '(Org . "9.3") :type '(repeat (string :tag "Tag")) - :safe #'org-list-of-strings-p) + :safe #'list-of-strings-p) ;;;###autoload (defcustom org-num-skip-unnumbered nil diff --git a/lisp/org-persist.el b/lisp/org-persist.el index 9f3edab82..5f459c24c 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -277,12 +277,12 @@ org-persist (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 @@ -746,13 +746,13 @@ 'org-persist-read:version (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." @@ -822,7 +822,7 @@ 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 @@ -883,7 +883,7 @@ org-persist-write:file (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) @@ -899,7 +899,7 @@ org-persist-write:url (when (cadr c) (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) @@ -938,7 +938,7 @@ org-persist-write:index (org-persist--check-write-access 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 nil) (setq org-persist--index-age @@ -954,7 +954,7 @@ org-persist--merge-index-with-disk "Merge `org-persist--index' with the current index file on disk." (org-persist--load-index) (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) @@ -980,7 +980,7 @@ org-persist--merge-index (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 + (file-name-concat org-persist-directory (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) @@ -1086,7 +1086,7 @@ org-persist-read (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)) @@ -1176,7 +1176,7 @@ org-persist-write (seq-find (lambda (v) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) - (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)))) (org-persist--write-elisp-file file data) @@ -1197,11 +1197,11 @@ org-persist-write-all ;; 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) @@ -1242,7 +1242,7 @@ org-persist--gc-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))))) (defalias 'org-persist-associated-files:elisp #'ignore) @@ -1266,7 +1266,7 @@ org-persist--refresh-gc-lock "Refresh session timestamp in `org-persist-gc-lock-file'. Remove expired sessions timestamps." (when org-persist--wrote-to-disk - (let* ((file (org-file-name-concat org-persist-directory org-persist-gc-lock-file)) + (let* ((file (file-name-concat org-persist-directory org-persist-gc-lock-file)) (alist (when (file-exists-p file) (org-persist--read-elisp-file file))) new-alist) (setf (alist-get before-init-time alist nil nil #'equal) @@ -1280,9 +1280,9 @@ org-persist--refresh-gc-lock (defun org-persist--gc-orphan-p () "Return non-nil, when orphan files should be garbage-collected. Remove current sessions from `org-persist-gc-lock-file'." - (let* ((file (org-file-name-concat org-persist-directory org-persist-gc-lock-file)) + (let* ((file (file-name-concat org-persist-directory org-persist-gc-lock-file)) (alist (when (file-exists-p file) (org-persist--read-elisp-file file)))) - (setq alist (org-assoc-delete-all before-init-time alist)) + (setq alist (assoc-delete-all before-init-time alist)) (ignore-errors (org-persist--write-elisp-file file alist)) ;; Only GC orphan files when there are no active sessions. (not alist))) @@ -1297,7 +1297,7 @@ org-persist-gc (remote-files-num 0) (orphan-files (when (org-persist--gc-orphan-p) ; also removes current session from lock file. - (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) @@ -1305,7 +1305,7 @@ 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-protocol.el b/lisp/org-protocol.el index d22053f4b..178ff2916 100644 --- a/lisp/org-protocol.el +++ b/lisp/org-protocol.el @@ -344,7 +344,7 @@ org-protocol-flatten-greedy `org-protocol-reverse-list-of-files' was set to t and the returned list will reflect that. emacsclient's first parameter will be the first one in the returned list." - (let* ((l (org--flatten-tree (if org-protocol-reverse-list-of-files + (let* ((l (flatten-tree (if org-protocol-reverse-list-of-files param-list (reverse param-list)))) (trigger (car l)) @@ -370,7 +370,7 @@ org-protocol-flatten-greedy l))) (define-obsolete-function-alias 'org-protocol-flatten - (if (fboundp 'flatten-tree) 'flatten-tree 'org--flatten-tree) + 'flatten-tree "9.7" "Transform LIST into a flat list. diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 2c966af96..f4604b2cb 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -692,7 +692,7 @@ org-refile-get-location (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-src.el b/lisp/org-src.el index d106cc5c4..aecf708d2 100644 --- a/lisp/org-src.el +++ b/lisp/org-src.el @@ -212,7 +212,7 @@ org-src--get-known-shells The shells are associated with `sh-mode'." (mapcar (lambda (shell) (cons (symbol-name shell) 'sh)) - (delete-dups (org--flatten-tree sh-ancestor-alist)))) + (delete-dups (flatten-tree sh-ancestor-alist)))) (defcustom org-src-lang-modes `(("C" . c) diff --git a/lisp/org.el b/lisp/org.el index 4f15fed7c..f78e47ba1 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -20361,7 +20361,7 @@ org-fill-paragraph (list (when current-prefix-arg 'full) t)) org-mode) (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)))) @@ -20386,7 +20386,7 @@ org-fill-paragraph ;; 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 182aefc1b..182d6c799 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4666,11 +4666,11 @@ org-export-resolve-radio-link 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 7f4f41348..a7b1137f4 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -72,19 +72,19 @@ test-org-link/toggle-link-display (font-lock-ensure) (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))))) diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 906ef5776..a9149c4e8 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -156,7 +156,7 @@ 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.54.0
>From 233ac2e72a78c34d14f9cbd659ac72b33e131ace Mon Sep 17 00:00:00 2001 From: Ihor Radchenko <[email protected]> Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH 6/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 863f8be0a..4156ccf5e 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -158,6 +158,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 9ea139fb5..805d4e5b8 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -43,6 +43,13 @@ header for =beamer= that includes theme configuration. For example: will make the Beamer exporter ignore the ~#+BEAMER_...~ keywords in the document that are related to theme configuration. +*** 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. + *** ~org-mouse~ tag and priority menus are now separate The "Tags and Priorities" section of the global context menu is split -- 2.54.0
>From 537077d6575a7f8c5729c7f78379ea32ab75684c Mon Sep 17 00:00:00 2001 From: Ihor Radchenko <[email protected]> Date: Thu, 13 Apr 2023 14:33:16 +0200 Subject: [PATCH 7/7] * 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 813125625..5ecd51b79 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,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 cleangithooks - remove Git hooks) $(info make cleanall - remove everything that can be built and all remnants) $(info make clean-install - remove previous Org installation) @@ -87,6 +88,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.54.0
