Hello!

I have now adjusted to patch series to use git submodules.

I've made "org-dependencies.el" print out exactly what commands you need
to run.

I've completely removed the cleanpkg target.  Not really sure what to do
there as I've handed over control of compiling everything to emacs's
builtin "package.el".  Maybe figuring that out can wait until after this
is merged?

Second patch is where the submodule actually gets added but all the
other changes I've made are in the first patch.

>From c7f9be0d82f1fdd1222d8caa8aef2bb06b78eb35 Mon Sep 17 00:00:00 2001
From: Ihor Radchenko <[email protected]>
Date: Sat, 1 Apr 2023 12:00:48 +0200
Subject: [PATCH 1/5] 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 (top_builddir): New variable holding the location of
the root of the repository.
(EMACSQ): Update, setting default package location.
* mk/targets.mk (uppkg): New target to install missing packages.
(checkpkg): New target to ensure packages are installed.
(check test test-dirty compile compile-dirty): Use the new checkpkg
target.
(.PHONY): Add uppkg and checkpkg

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]>
---
 mk/default.mk          |  11 +++-
 mk/org-dependencies.el | 133 +++++++++++++++++++++++++++++++++++++++++
 mk/targets.mk          |  15 ++++-
 3 files changed, 153 insertions(+), 6 deletions(-)
 create mode 100644 mk/org-dependencies.el

diff --git a/mk/default.mk b/mk/default.mk
index acc0a3866..9adda1508 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -31,6 +31,8 @@ GIT_BRANCH =
 TMPDIR ?= /tmp
 testdir = $(TMPDIR)/tmp-orgtest
 
+top_builddir := $(shell pwd)
+
 # Configuration for testing
 # Verbose ERT summary by default for Emacs-28 and above.
 # To override:
@@ -117,11 +119,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 '(setq package-user-dir (expand-file-name "./deps" "${top_builddir}"))' \
+	  --eval '(setq package-directory-list (list (expand-file-name "./deps" "${top_builddir}")))' \
+	  -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..e0893fa0d
--- /dev/null
+++ b/mk/org-dependencies.el
@@ -0,0 +1,133 @@
+;;; 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)
+
+;; Emacs < 30
+(unless (fboundp 'lm-package-requires)
+  (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 " ")))))))
+
+(defun org-dependencies-pretty-print-instructions (instructions)
+  "Print the INSTRUCTIONS to the terminal for the user.
+Printing is done with `error' so Emacs will terminate and allow the user
+to perform what is asked of them."
+  (with-temp-buffer
+    (insert "================================================================\n")
+    (dolist (line (split-string instructions "\n"))
+      (insert (format "= %-60s =\n" line)))
+    (insert "================================================================\n")
+    (let ((backtrace-on-error-noninteractive nil))
+      (error "%s" (buffer-string)))))
+
+(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."
+  (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)
+            (org-dependencies-pretty-print-instructions
+             (format "ERROR: Package %S does not satisfy version requirement of %S
+Consider running \"make uppkg\" to install dependencies"
+                     package version))
+          (org-dependencies-pretty-print-instructions
+           (format "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))
+    (let ((backtrace-on-error-noninteractive nil))
+      (dolist (dep (org-dependencies))
+        (let ((package (car dep))
+              (version (nth 1 dep)))
+          (unless (package-installed-p package (version-to-list version))
+            (let ((package-source-dir (concat "./deps/" (symbol-name package) "/")))
+              (unless (file-exists-p (concat package-source-dir (symbol-name package) ".el"))
+                (org-dependencies-pretty-print-instructions
+                 (format
+                  "ERROR: Cannot find %S locally.
+Try updating the git submodule.
+You can do so with this command:
+  git submodule update --init --depth=1 -- %S"
+                  package package-source-dir)))
+              (let ((package-install-upgrade-built-in t)
+                    (package-archives nil))
+                (package-install-file (expand-file-name package-source-dir)))
+              (unless (package-installed-p package (version-to-list version))
+                (org-dependencies-pretty-print-instructions
+                 (format
+                  "ERROR: Dependency %S is still not satisfied.
+Try updating the git submodule.
+You can do so with this command:
+  git submodule update --init --depth=1 -- %S"
+                  package package-source-dir))))))))))
+
+(provide 'org-dependencies)
+;;; org-dependencies.el ends here
diff --git a/mk/targets.mk b/mk/targets.mk
index a8bec6813..af9eea826 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -29,7 +29,7 @@ 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%) \
@@ -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,22 @@ 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)
+	$(BATCHO) --eval '(load "../mk/org-dependencies.el")' \
+	  -f org-install-dependencies
+
 up0 up1 up2::
 	git checkout $(GIT_BRANCH)
 	git remote update
-- 
2.54.0

>From e3e6e743d2d70877b3162d3d17432b74038955d9 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Fri, 15 May 2026 16:40:48 -0400
Subject: [PATCH 2/5] Add compat.el dependency

* lisp/org.el: Add Compat to package-requires.
* .gitmodules: Add Compat git submodule.
* deps/compat: This is where the Compat git submodule is mounted.

Co-authored-by: Ihor Radchenko <[email protected]>
---
 .gitmodules | 3 +++
 deps/compat | 1 +
 lisp/org.el | 2 +-
 3 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 .gitmodules
 create mode 160000 deps/compat

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..53edfc6c2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "deps/compat"]
+	path = deps/compat
+	url = https://github.com/emacs-compat/compat
diff --git a/deps/compat b/deps/compat
new file mode 160000
index 000000000..90880f814
--- /dev/null
+++ b/deps/compat
@@ -0,0 +1 @@
+Subproject commit 90880f81419577e1d3f68424d2a3adf31e6d663e
diff --git a/lisp/org.el b/lisp/org.el
index efd1c5fe8..c9724f603 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 fdda3f132c75de4b63eadcfe4ce5f0562459867d Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Mon, 18 May 2026 23:19:26 -0400
Subject: [PATCH 3/5] 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 d2be9746f76b6e2de9f390970af41ee7316eb02e Mon Sep 17 00:00:00 2001
From: Ihor Radchenko <[email protected]>
Date: Mon, 3 Apr 2023 10:41:50 +0200
Subject: [PATCH 4/5] Use compat.el library instead of ad-hoc compatibility
 functions

* 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 e525b8c34..e512f0ffc 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))))
@@ -2749,13 +2749,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))))
@@ -2766,14 +2766,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
 				 (`(,_)
@@ -3563,7 +3563,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 9480d662f..bd45044b9 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -2683,8 +2683,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
@@ -2973,7 +2973,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 7654f74f9..448a4243c 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -1490,9 +1490,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.
@@ -2060,7 +2060,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 0f902febf..dc9491644 100644
--- a/lisp/org-colview.el
+++ b/lisp/org-colview.el
@@ -1179,7 +1179,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 d4bd90b8b..eb373b42b 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 8f86c6cff..7fa8b8034 100644
--- a/lisp/org-src.el
+++ b/lisp/org-src.el
@@ -213,7 +213,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 c9724f603..c608db7e7 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -20480,7 +20480,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))))
@@ -20505,7 +20505,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 6c780e7c6..16b021b26 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4692,11 +4692,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 17445f32d..b5f334fdb 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 41497957098856dc401a9d190c017ab21e9597bb Mon Sep 17 00:00:00 2001
From: Ihor Radchenko <[email protected]>
Date: Sat, 1 Apr 2023 12:18:57 +0200
Subject: [PATCH 5/5] 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 10d5b564f..a40897b4b 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 3120f7ed5..361af081d 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

Reply via email to