emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@posteo.net>
To: Timothy <tecosaur@gmail.com>
Cc: Bastien <bzg@gnu.org>, Kyle Meyer <kyle@kyleam.com>,
	Org-mode <emacs-orgmode@gnu.org>,
	Daniel Mendler <mail@daniel-mendler.de>
Subject: [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el))
Date: Sat, 01 Apr 2023 10:31:10 +0000	[thread overview]
Message-ID: <87r0t3gahd.fsf@localhost> (raw)
In-Reply-To: <87v8ks6rhf.fsf@localhost>

[-- Attachment #1: Type: text/plain, Size: 713 bytes --]

Ihor Radchenko <yantar92@posteo.net> writes:

> I have recently been contacted by the current compat.el maintainer
> asking if we are willing to adapt compat.el in Org.

See the attached patch set adding support of compat.el.

I had to update Org's build system to handle third-party packages.
Please, give it a close check (first patch).

The second patch adds the actual Elisp part and replaces some
compatibility functions with what is provided by compat.el.
Note that not all the functions are available in compat.el for now.
Daniel, you might want to take a look.

The last patch adds the necessary explanation for users who install Org
from git. Now, they must install compat.el manually to make Org work.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Upgrade-Org-build-system-to-handle-third-party-depen.patch --]
[-- Type: text/x-patch, Size: 6315 bytes --]

From f95433f53878e8371bb28a045fdb5d06cf0877b9 Mon Sep 17 00:00:00 2001
Message-Id: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 1 Apr 2023 12:00:48 +0200
Subject: [PATCH 1/3] Upgrade Org build system to handle third-party
 dependencies

* mk/default.mk (pkgdir): New variable holding the location of
third-party packages to be downloaded if necessary during compilation.
(EFLAGS): New variable holding extra flags to be passed to Emacs
executable when running make.
(EPACKAGES): List of packages to be installed (unless already present
in the `load-path') during compilation.
(package-install):
(INSTALL_PACKAGES): New command to download and install missing packages.
(BATCH): Update, setting default package location to pkgdir.
* mk/targets.mk (uppkg): New target to download install missing
packages.
(check test):
(compile compile-dirty): Use the new uppkg target.
(cleanpkg): New target cleaning up the downloaded packages.
(cleanall): Use the new target.
(.PHONY):
(CONF_BASE):
(CONF_DEST):
(CONF_CALL): Update according to the new variables and targets.
* .gitignore: Ignore the downloaded packages.

This commit paves the way towards third-party built-time dependencies
for Org.  In particular, towards including compat.el dependency.

According to EPACKAGES, we can auto-download necessary packages,
unless they are manually specified via -L switches in EFLAGS.

Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost
---
 .gitignore    |  1 +
 mk/default.mk | 24 +++++++++++++++++++++++-
 mk/targets.mk | 24 ++++++++++++++++--------
 3 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4bb81c359..a58670c90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,6 +71,7 @@ t
 auto
 tmp
 TODO
+/pkg-deps
 
 # and collateral damage from Emacs
 
diff --git a/mk/default.mk b/mk/default.mk
index fa46661e8..997b22b66 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -31,6 +31,15 @@ GIT_BRANCH =
 TMPDIR ?= /tmp
 testdir = $(TMPDIR)/tmp-orgtest
 
+# Where to store Org dependencies
+pkgdir = $(shell pwd)/pkg-deps
+
+# Extra flags to be passed to Emacs
+EFLAGS ?=
+
+# Third-party packages to install when running make
+EPACKAGES ?=
+
 # Configuration for testing
 # Verbose ERT summary by default for Emacs-28 and above.
 # To override:
@@ -72,12 +81,22 @@ REPRO_ARGS ?=
 req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))'
 lst-ob-lang = ($(ob-lang) . t)
 req-extra   = --eval '(require '"'"'$(req))'
+package-install = --eval '(unless (require '"'"'$(package) nil t) (message "%s" load-path) (package-install '"'"'$(package)))'
 BTEST_RE   ?= \\(org\\|ob\\|ox\\)
 BTEST_LOAD  = \
 	--eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \
 	--eval '(add-to-list '"'"'load-path (concat default-directory "testing"))'
 BTEST_INIT  = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST)
 
+ifeq (,$(EPACKAGES))
+INSTALL_PACKAGES =
+else
+INSTALL_PACKAGES = \
+	$(BATCH) \
+        --eval '(package-refresh-contents)' \
+        $(foreach package,$(EPACKAGES),$(package-install))
+endif
+
 BTEST = $(BATCH) $(BTEST_INIT) \
 	  -l org-batch-test-init \
 	  --eval '(setq \
@@ -120,7 +139,10 @@ EMACSQ  = $(EMACS)  -Q
 
 # Using emacs in batch mode.
 BATCH	= $(EMACSQ) -batch \
-	  --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)'
+	  $(EFLAGS) \
+	  --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \
+          --eval '(make-directory "$(pkgdir)" t)' \
+	  --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)'
 
 # Emacs must be started in toplevel directory
 BATCHO	= $(BATCH) \
diff --git a/mk/targets.mk b/mk/targets.mk
index 0bd293d68..ab8b830bb 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),)
   GITVERSION := $(GITVERSION:.dirty=).dirty
 endif
 
-.PHONY:	all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \
+.PHONY:	all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \
 	check test install $(INSTSUB) \
 	info html pdf card refcard doc docs \
 	autoloads cleanall clean $(CLEANDIRS:%=clean%) \
 	clean-install cleanelc cleandirs \
-	cleanlisp cleandoc cleandocs cleantest \
+	cleanlisp cleandoc cleandocs cleantest cleanpkg \
 	compile compile-dirty uncompiled \
 	config config-test config-exe config-all config-eol config-version \
 	vanilla repro
 
-CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC
-CONF_DEST = lispdir infodir datadir testdir
+CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES
+CONF_DEST = lispdir infodir datadir testdir pkgdir
 CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE
 CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO
-CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
+CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION
 config-eol:: EOL = \#
 config-eol:: config-all
 config config-all::
@@ -86,7 +86,7 @@ local.mk:
 
 all compile::
 	$(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;)
-compile compile-dirty::
+compile compile-dirty:: uppkg
 	$(MAKE) -C lisp $@
 all clean-install::
 	$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;)
@@ -94,7 +94,7 @@ all clean-install::
 vanilla:
 	-@$(NOBATCH) &
 
-check test::	compile
+check test::	uppkg compile
 check test test-dirty::
 	-$(MKDIR) $(testdir)
 	TMPDIR=$(testdir) $(BTEST)
@@ -102,6 +102,11 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f
 	$(MAKE) cleantest
 endif
 
+uppkg::
+	-$(MKDIR) -p $(pkgdir)
+	-$(FIND) $(pkgdir) \(  -name \*.elc \) -exec $(RM) {} +
+	$(INSTALL_PACKAGES)
+
 up0 up1 up2::
 	git checkout $(GIT_BRANCH)
 	git remote update
@@ -134,7 +139,7 @@ cleandirs:
 
 clean:	cleanlisp cleandoc
 
-cleanall: cleandirs cleantest
+cleanall: cleandirs cleantest cleanpkg
 	-$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} +
 	-$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} +
 
@@ -159,3 +164,6 @@ cleantest:
 	  $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \
 	  $(RMR) $(testdir) ; \
 	}
+
+cleanpkg:
+	-$(RMR) $(pkgdir)
-- 
2.39.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Use-compat.el-library-instead-of-ad-hoc-compatibilit.patch --]
[-- Type: text/x-patch, Size: 34712 bytes --]

From 6c4c71426c15b6307cecc1ebffc75dbd6d5135b4 Mon Sep 17 00:00:00 2001
Message-Id: <6c4c71426c15b6307cecc1ebffc75dbd6d5135b4.1680344979.git.yantar92@posteo.net>
In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net>
References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 1 Apr 2023 12:10:13 +0200
Subject: [PATCH 2/3] Use compat.el library instead of ad-hoc compatibility
 function set

* mk/default.mk (EPACKAGES): Demand compat library during compile time.
* lisp/org.el: Add compat dependency.
(org-fill-paragraph):
* lisp/org-compat.el: Implement compat.el compatibility layer.
Obsolete org-* compatibility functions that are already available in
compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case',
`org-file-name-concat', `org-directory-empty-p',
`org-string-clean-whitespace', `org-format-prompt', `org-xor',
`org-string-distance', `org-buffer-hash'.
* lisp/ob-core.el (org-babel-results-keyword): Use functions provided
by compat.el.
(org-babel-insert-result):
* lisp/oc-basic.el (org-cite-basic--parse-bibliography):
* lisp/oc.el (org-cite-adjust-note):
* lisp/ol-gnus.el (org-gnus-group-link):
(org-gnus-article-link):
(org-gnus-store-link):
* lisp/ol.el:
(org-store-link):
* lisp/org-attach.el:
* lisp/org-capture.el:
(org-capture-fill-template):
* lisp/org-fold-core.el (org-fold-core-next-visibility-change):
* lisp/org-lint.el:
* lisp/org-persist.el (org-persist-directory):
(org-persist-read:file):
(org-persist-read:url):
(org-persist--load-index):
(org-persist-write:file):
(org-persist-write:index):
(org-persist--merge-index-with-disk):
(org-persist-read):
(org-persist-write):
(org-persist-write-all):
(org-persist--gc-persist-file):
(org-persist-gc):
* lisp/org-refile.el (org-refile-get-location):
* lisp/ox.el (org-export-resolve-radio-link):
* testing/lisp/test-ol.el (test-org-link/toggle-link-display):
* testing/lisp/test-org-capture.el (test-org-capture/abort):

Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost
---
 lisp/ob-core.el                  |   8 +-
 lisp/oc-basic.el                 |   4 +-
 lisp/oc.el                       |   2 +-
 lisp/ol-gnus.el                  |   8 +-
 lisp/ol.el                       |   4 +-
 lisp/org-attach.el               |   2 +-
 lisp/org-capture.el              |   8 +-
 lisp/org-compat.el               | 220 +++++++++----------------------
 lisp/org-fold-core.el            |   2 +-
 lisp/org-lint.el                 |   2 +-
 lisp/org-persist.el              |  38 +++---
 lisp/org-refile.el               |   2 +-
 lisp/org.el                      |   6 +-
 lisp/ox.el                       |   6 +-
 mk/default.mk                    |   2 +-
 testing/lisp/test-ol.el          |  10 +-
 testing/lisp/test-org-capture.el |   2 +-
 17 files changed, 115 insertions(+), 211 deletions(-)

diff --git a/lisp/ob-core.el b/lisp/ob-core.el
index 471887a3a..65d9fdc72 100644
--- a/lisp/ob-core.el
+++ b/lisp/ob-core.el
@@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS"
   :type 'string
   :safe (lambda (v)
 	  (and (stringp v)
-	       (org-string-equal-ignore-case "RESULTS" v))))
+	       (string-equal-ignore-case "RESULTS" v))))
 
 (defcustom org-babel-noweb-wrap-start "<<"
   "String used to begin a noweb reference in a code block.
@@ -2518,7 +2518,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex
 		       ;; Escape contents from "export" wrap.  Wrap
 		       ;; inline results within an export snippet with
 		       ;; appropriate value.
-		       ((org-string-equal-ignore-case type "export")
+		       ((string-equal-ignore-case type "export")
 			(let ((backend (pcase split
 					 (`(,_) "none")
 					 (`(,_ ,b . ,_) b))))
@@ -2529,14 +2529,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex
 					   backend) "@@)}}}")))
 		       ;; Escape contents from "example" wrap.  Mark
 		       ;; inline results as verbatim.
-		       ((org-string-equal-ignore-case type "example")
+		       ((string-equal-ignore-case type "example")
 			(funcall wrap
 				 opening-line closing-line
 				 nil nil
 				 "{{{results(=" "=)}}}"))
 		       ;; Escape contents from "src" wrap.  Mark
 		       ;; inline results as inline source code.
-		       ((org-string-equal-ignore-case type "src")
+		       ((string-equal-ignore-case type "src")
 			(let ((inline-open
 			       (pcase split
 				 (`(,_)
diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el
index 12b627e71..eee354f26 100644
--- a/lisp/oc-basic.el
+++ b/lisp/oc-basic.el
@@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info)
       (dolist (file (org-cite-list-bibliography-files))
         (when (file-readable-p file)
           (with-temp-buffer
-            (when (or (org-file-has-changed-p file)
+            (when (or (file-has-changed-p file)
                       (not (gethash file org-cite-basic--file-id-cache)))
               (insert-file-contents file)
               (set-visited-file-name file t)
-              (puthash file (org-buffer-hash) org-cite-basic--file-id-cache))
+              (puthash file (buffer-hash) org-cite-basic--file-id-cache))
             (condition-case nil
                 (unwind-protect
 	            (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache)))
diff --git a/lisp/oc.el b/lisp/oc.el
index dde6f3a32..f39ae848b 100644
--- a/lisp/oc.el
+++ b/lisp/oc.el
@@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct)
                              (match-string 3 previous)))))
       ;; Bail you when there is no quote and either no punctuation, or
       ;; punctuation on both sides.
-      (when (or quote (org-xor punct final-punct))
+      (when (or quote (xor punct final-punct))
         ;; Phase 1: handle punctuation rule.
         (pcase rule
           ((guard (not quote)) nil)
diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el
index 7c07ce045..e121cfba3 100644
--- a/lisp/ol-gnus.el
+++ b/lisp/ol-gnus.el
@@ -98,8 +98,8 @@ (defun org-gnus-group-link (group)
 `org-gnus-prefer-web-links' is reversed."
   (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group)))
     (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups
-	     (org-xor current-prefix-arg
-		      org-gnus-prefer-web-links))
+	     (xor current-prefix-arg
+		  org-gnus-prefer-web-links))
 	(concat "https://groups.google.com/group/" unprefixed-group)
       (concat "gnus:" group))))
 
@@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive)
 
 If `org-store-link' was called with a prefix arg the meaning of
 `org-gnus-prefer-web-links' is reversed."
-  (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links)
+  (if (and (xor current-prefix-arg org-gnus-prefer-web-links)
 	   newsgroups		  ;make web links only for nntp groups
 	   (not x-no-archive))	  ;and if X-No-Archive isn't set
       (format "https://groups.google.com/groups/search?as_umsgid=%s"
@@ -169,7 +169,7 @@ (defun org-gnus-store-link ()
 	    newsgroups x-no-archive)
        ;; Fetching an article is an expensive operation; newsgroup and
        ;; x-no-archive are only needed for web links.
-       (when (org-xor current-prefix-arg org-gnus-prefer-web-links)
+       (when (xor current-prefix-arg org-gnus-prefer-web-links)
 	 ;; Make sure the original article buffer is up-to-date.
 	 (save-window-excursion (gnus-summary-select-article))
 	 (setq to (or to (gnus-fetch-original-field "To")))
diff --git a/lisp/ol.el b/lisp/ol.el
index 9e4781f6e..3d62a6fa0 100644
--- a/lisp/ol.el
+++ b/lisp/ol.el
@@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?)
 				(abbreviate-file-name
 				 (buffer-file-name (buffer-base-buffer)))))
 	   ;; Add a context search string.
-	   (when (org-xor org-link-context-for-files (equal arg '(4)))
+	   (when (xor org-link-context-for-files (equal arg '(4)))
 	     (let* ((element (org-element-at-point))
 		    (name (org-element-property :name element))
 		    (context
@@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?)
 			     (abbreviate-file-name
 			      (buffer-file-name (buffer-base-buffer)))))
 	;; Add a context search string.
-	(when (org-xor org-link-context-for-files (equal arg '(4)))
+	(when (xor org-link-context-for-files (equal arg '(4)))
 	  (let ((context (org-link--normalize-string
 			  (or (org-link--context-from-region)
 			      (org-current-line-string))
diff --git a/lisp/org-attach.el b/lisp/org-attach.el
index 8d01eda71..5cc40873c 100644
--- a/lisp/org-attach.el
+++ b/lisp/org-attach.el
@@ -674,7 +674,7 @@ (defun org-attach-sync ()
       (let ((files (org-attach-file-list attach-dir)))
 	(org-attach-tag (not files)))
       (when org-attach-sync-delete-empty-dir
-        (when (and (org-directory-empty-p attach-dir)
+        (when (and (directory-empty-p attach-dir)
                    (if (eq 'query org-attach-sync-delete-empty-dir)
                        (yes-or-no-p "Attachment directory is empty.  Delete?")
                      t))
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index b96e9f336..c5b1c6d50 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -1323,9 +1323,9 @@ (defun org-capture-place-item ()
 	      ;; prioritize the existing list.
 	      (when prepend?
 		(let ((ordered? (eq 'ordered (org-element-property :type item))))
-		  (when (org-xor ordered?
-				 (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)"
-						 template))
+		  (when (xor ordered?
+			     (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)"
+					     template))
 		    (org-cycle-list-bullet (if ordered? "1." "-")))))
 	      ;; Eventually repair the list for proper indentation and
 	      ;; bullets.
@@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation)
 		     (setq org-capture--prompt-history
 			   (gethash prompt org-capture--prompt-history-table))
                      (push (org-completing-read
-                            (org-format-prompt (or prompt "Enter string") default)
+                            (format-prompt (or prompt "Enter string") default)
 			    completions
 			    nil nil nil 'org-capture--prompt-history default)
 			   strings)
diff --git a/lisp/org-compat.el b/lisp/org-compat.el
index c47a4e8c2..046a3db97 100644
--- a/lisp/org-compat.el
+++ b/lisp/org-compat.el
@@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec))
 (declare-function org-fold-show-all "org-fold" (&optional types))
 (declare-function org-fold-show-children "org-fold" (&optional level))
 (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers))
-;; `org-string-equal-ignore-case' is in _this_ file but isn't at the
-;; top-level.
-(declare-function org-string-equal-ignore-case "org-compat" (string1 string2))
 
 (defvar calendar-mode-map)
 (defvar org-complex-heading-regexp)
@@ -95,104 +92,67 @@ (defvar org-table1-hline-regexp)
 (defvar org-fold-core-style)
 
 \f
-;;; Emacs < 29 compatibility
-
-(defvar org-file-has-changed-p--hash-table (make-hash-table :test #'equal)
-  "Internal variable used by `org-file-has-changed-p'.")
-
-(if (fboundp 'file-has-changed-p)
-    (defalias 'org-file-has-changed-p #'file-has-changed-p)
-  (defun org-file-has-changed-p (file &optional tag)
-    "Return non-nil if FILE has changed.
-The size and modification time of FILE are compared to the size
-and modification time of the same FILE during a previous
-invocation of `org-file-has-changed-p'.  Thus, the first invocation
-of `org-file-has-changed-p' always returns non-nil when FILE exists.
-The optional argument TAG, which must be a symbol, can be used to
-limit the comparison to invocations with identical tags; it can be
-the symbol of the calling function, for example."
-    (let* ((file (directory-file-name (expand-file-name file)))
-           (remote-file-name-inhibit-cache t)
-           (fileattr (file-attributes file 'integer))
-	   (attr (and fileattr
-                      (cons (file-attribute-size fileattr)
-		            (file-attribute-modification-time fileattr))))
-	   (sym (concat (symbol-name tag) "@" file))
-	   (cachedattr (gethash sym org-file-has-changed-p--hash-table)))
-      (when (not (equal attr cachedattr))
-        (puthash sym attr org-file-has-changed-p--hash-table)))))
-
-(if (fboundp 'string-equal-ignore-case)
-    (defalias 'org-string-equal-ignore-case #'string-equal-ignore-case)
-  ;; From Emacs subr.el.
-  (defun org-string-equal-ignore-case (string1 string2)
-    "Like `string-equal', but case-insensitive.
-Upper-case and lower-case letters are treated as equal.
-Unibyte strings are converted to multibyte for comparison."
-    (eq t (compare-strings string1 0 nil string2 0 nil t))))
-
-\f
-;;; Emacs < 28.1 compatibility
-
-(if (fboundp 'file-name-concat)
-    (defalias 'org-file-name-concat #'file-name-concat)
-  (defun org-file-name-concat (directory &rest components)
-    "Append COMPONENTS to DIRECTORY and return the resulting string.
-
-Elements in COMPONENTS must be a string or nil.
-DIRECTORY or the non-final elements in COMPONENTS may or may not end
-with a slash -- if they don't end with a slash, a slash will be
-inserted before contatenating."
-    (save-match-data
-      (mapconcat
-       #'identity
-       (delq nil
-             (mapcar
-              (lambda (str)
-                (when (and str (not (seq-empty-p str))
-                           (string-match "\\(.+\\)/?" str))
-                  (match-string 1 str)))
-              (cons directory components)))
-       "/"))))
-
-(if (fboundp 'directory-empty-p)
-    (defalias 'org-directory-empty-p #'directory-empty-p)
-  (defun org-directory-empty-p (dir)
-    "Return t if DIR names an existing directory containing no other files."
-    (and (file-directory-p dir)
-         (null (directory-files dir nil directory-files-no-dot-files-regexp t)))))
-
-(if (fboundp 'string-clean-whitespace)
-    (defalias 'org-string-clean-whitespace #'string-clean-whitespace)
-  ;; From Emacs subr-x.el.
-  (defun org-string-clean-whitespace (string)
-    "Clean up whitespace in STRING.
-All sequences of whitespaces in STRING are collapsed into a
-single space character, and leading/trailing whitespace is
-removed."
-    (let ((blank "[[:blank:]\r\n]+"))
-      (string-trim (replace-regexp-in-string blank " " string t t)
-                   blank blank))))
-
-(if (fboundp 'format-prompt)
-    (defalias 'org-format-prompt #'format-prompt)
-  ;; From Emacs minibuffer.el, inlining
-  ;; `minibuffer-default-prompt-format' value and replacing `length<'
-  ;; (both new in Emacs 28.1).
-  (defun org-format-prompt (prompt default &rest format-args)
-    "Compatibility substitute for `format-prompt'."
-    (concat
-     (if (null format-args)
-         prompt
-       (apply #'format prompt format-args))
-     (and default
-          (or (not (stringp default))
-              (> (length default) 0))
-          (format " (default %s)"
-                  (if (consp default)
-                      (car default)
-                    default)))
-     ": ")))
+;;; compat.el
+
+;; Do not throw an error when not available - assume latest Emacs
+;; version (built-in Org).
+(require 'compat nil 'noerror)
+
+;; Provide compatibility macros when we are a part of Emacs.
+;; See https://elpa.gnu.org/packages/doc/compat.html#Usage
+
+(defmacro org-compat-function (fun)
+  "Return compatibility function symbol for FUN.
+
+If the Emacs version provides a sufficiently recent version of
+FUN, the symbol FUN is returned itself.  Otherwise the macro
+returns the symbol of a compatibility function which supports the
+behavior and calling convention of the current stable Emacs
+version.  For example Compat 29.1 will provide compatibility
+functions which implement the behavior and calling convention of
+Emacs 29.1.
+
+See also `org-compat-call' to directly call compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `#',(if (fboundp compat) compat fun)))
+
+(defmacro org-compat-call (fun &rest args)
+  "Call compatibility function or macro FUN with ARGS.
+
+A good example function is `plist-get' which was extended with an
+additional predicate argument in Emacs 29.1.  The compatibility
+function, which supports this additional argument, can be
+obtained via (compat-function plist-get) and called
+via (compat-call plist-get plist prop predicate).  It is not
+possible to directly call (plist-get plist prop predicate) on
+Emacs older than 29.1, since the original `plist-get' function
+does not yet support the predicate argument.  Note that the
+Compat library never overrides existing functions.
+
+See also `org-compat-function' to lookup compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `(,(if (fboundp compat) compat fun) ,@args)))
+
+;; Obsolete compatibility wrappers used before inclusion of compat.el.
+
+(define-obsolete-function-alias 'org-file-has-changed-p
+  'file-has-changed-p "9.7")
+(define-obsolete-function-alias 'org-string-equal-ignore-case
+  'string-equal-ignore-case "9.7")
+(define-obsolete-function-alias 'org-file-name-concat
+  'file-name-concat "9.7")
+(define-obsolete-function-alias 'org-directory-empty-p
+  'directory-empty-p "9.7")
+(define-obsolete-function-alias 'org-string-clean-whitespace
+  'string-clean-whitespace "9.7")
+(define-obsolete-function-alias 'org-format-prompt
+  'format-prompt "9.7")
+(define-obsolete-function-alias 'org-xor
+  'xor "9.7")
+(define-obsolete-function-alias 'org-string-distance
+  'string-distance "9.7")
+(define-obsolete-function-alias 'org-buffer-hash
+  'buffer-hash "9.7")
 
 \f
 ;;; Emacs < 27.1 compatibility
@@ -210,22 +170,6 @@ (if (version< emacs-version "27.1")
       (replace-buffer-contents source))
   (defalias 'org-replace-buffer-contents #'replace-buffer-contents))
 
-(unless (fboundp 'proper-list-p)
-  ;; `proper-list-p' was added in Emacs 27.1.  The function below is
-  ;; taken from Emacs subr.el 200195e824b^.
-  (defun proper-list-p (object)
-    "Return OBJECT's length if it is a proper list, nil otherwise.
-A proper list is neither circular nor dotted (i.e., its last cdr
-is nil)."
-    (and (listp object) (ignore-errors (length object)))))
-
-(if (fboundp 'xor)
-    ;; `xor' was added in Emacs 27.1.
-    (defalias 'org-xor #'xor)
-  (defsubst org-xor (a b)
-    "Exclusive `or'."
-    (if a (not b) b)))
-
 (unless (fboundp 'pcomplete-uniquify-list)
   ;; The misspelled variant was made obsolete in Emacs 27.1
   (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list))
@@ -255,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p)
   (when (fboundp 'set-face-extend)
     (mapc (lambda (f) (set-face-extend f extend-p)) faces)))
 
-(if (fboundp 'string-distance)
-    (defalias 'org-string-distance 'string-distance)
-  (defun org-string-distance (s1 s2)
-    "Return the edit (levenshtein) distance between strings S1 S2."
-    (let* ((l1 (length s1))
-	   (l2 (length s2))
-	   (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil))
-				  (number-sequence 1 (1+ l1)))))
-	   (in (lambda (i j) (aref (aref dist i) j))))
-      (setf (aref (aref dist 0) 0) 0)
-      (dolist (j (number-sequence 1 l2))
-        (setf (aref (aref dist 0) j) j))
-      (dolist (i (number-sequence 1 l1))
-        (setf (aref (aref dist i) 0) i)
-        (dolist (j (number-sequence 1 l2))
-	  (setf (aref (aref dist i) j)
-	        (min
-	         (1+ (funcall in (1- i) j))
-	         (1+ (funcall in i (1- j)))
-	         (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1)
-		    (funcall in (1- i) (1- j)))))))
-      (funcall in l1 l2))))
-
 (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance
   "9.5")
 
@@ -298,23 +219,6 @@ (if (fboundp 'line-number-display-width)
     (defalias 'org-line-number-display-width 'line-number-display-width)
   (defun org-line-number-display-width (&rest _) 0))
 
-(if (fboundp 'buffer-hash)
-    (defalias 'org-buffer-hash 'buffer-hash)
-  (defun org-buffer-hash () (md5 (current-buffer))))
-
-(unless (fboundp 'file-attribute-modification-time)
-  (defsubst file-attribute-modification-time (attributes)
-    "The modification time in ATTRIBUTES returned by `file-attributes'.
-This is the time of the last change to the file's contents, and
-is a Lisp timestamp in the same style as `current-time'."
-    (nth 5 attributes)))
-
-(unless (fboundp 'file-attribute-size)
-  (defsubst file-attribute-size (attributes)
-    "The size (in bytes) in ATTRIBUTES returned by `file-attributes'.
-This is a floating point number if the size is too large for an integer."
-    (nth 7 attributes)))
-
 \f
 ;;; Obsolete aliases (remove them after the next major release).
 
@@ -1416,7 +1320,7 @@ (defun org-mode-flyspell-verify ()
 	  (and log
 	       (let ((drawer (org-element-lineage element '(drawer))))
 		 (and drawer
-		      (org-string-equal-ignore-case
+		      (string-equal-ignore-case
 		       log (org-element-property :drawer-name drawer))))))
 	nil)
        (t
diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el
index 43c6b2b74..c699c115b 100644
--- a/lisp/org-fold-core.el
+++ b/lisp/org-fold-core.el
@@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p
 			  (lambda (p) (next-single-char-property-change p 'invisible nil limit)))))
 	 (next pos))
     (while (and (funcall cmp next limit)
-		(not (org-xor
+		(not (xor
                     invisible-initially?
                     (funcall invisible-p
                              (if previous-p
diff --git a/lisp/org-lint.el b/lisp/org-lint.el
index 0e2967b6c..adc893aff 100644
--- a/lisp/org-lint.el
+++ b/lisp/org-lint.el
@@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast)
    ast
    'node-property
    (lambda (property)
-     (and (org-string-equal-ignore-case
+     (and (string-equal-ignore-case
            "CUSTOM_ID" (org-element-property :key property))
 	  (org-element-property :value property)))
    (lambda (property _) (org-element-property :begin property))
diff --git a/lisp/org-persist.el b/lisp/org-persist.el
index 8e73fbc4b..21c09567f 100644
--- a/lisp/org-persist.el
+++ b/lisp/org-persist.el
@@ -279,12 +279,12 @@ (defgroup org-persist nil
 
 (defcustom org-persist-directory
   (expand-file-name
-   (org-file-name-concat
+   (file-name-concat
     (let ((cache-dir (when (fboundp 'xdg-cache-home)
                        (xdg-cache-home))))
       (if (or (seq-empty-p cache-dir)
               (not (file-exists-p cache-dir))
-              (file-exists-p (org-file-name-concat
+              (file-exists-p (file-name-concat
                               user-emacs-directory
                               "org-persist")))
           user-emacs-directory
@@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data)
 
 (defun org-persist-read:file (_ path __)
   "Read file container from PATH."
-  (when (and path (file-exists-p (org-file-name-concat org-persist-directory path)))
-    (org-file-name-concat org-persist-directory path)))
+  (when (and path (file-exists-p (file-name-concat org-persist-directory path)))
+    (file-name-concat org-persist-directory path)))
 
 (defun org-persist-read:url (_ path __)
   "Read file container from PATH."
-  (when (and path (file-exists-p (org-file-name-concat org-persist-directory path)))
-    (org-file-name-concat org-persist-directory path)))
+  (when (and path (file-exists-p (file-name-concat org-persist-directory path)))
+    (file-name-concat org-persist-directory path)))
 
 (defun org-persist-read:index (cont index-file _)
   "Read index container CONT from INDEX-FILE."
@@ -750,7 +750,7 @@ (defun org-persist--load-index ()
   "Load `org-persist--index'."
   (org-persist-load:index
    `(index ,org-persist--storage-version)
-   (org-file-name-concat org-persist-directory org-persist-index-file)
+   (file-name-concat org-persist-directory org-persist-index-file)
    nil))
 
 ;;;; Writing container data
@@ -804,7 +804,7 @@ (defun org-persist-write:file (c collection)
         (setq path (cadr c)))
       (let* ((persist-file (plist-get collection :persist-file))
              (ext (file-name-extension path))
-             (file-copy (org-file-name-concat
+             (file-copy (file-name-concat
                          org-persist-directory
                          (format "%s-%s.%s" persist-file (md5 path) ext))))
         (unless (file-exists-p file-copy)
@@ -850,7 +850,7 @@ (defun org-persist-write:index (container _)
                  org-persist-directory))))
   (when (file-exists-p org-persist-directory)
     (let ((index-file
-           (org-file-name-concat org-persist-directory org-persist-index-file)))
+           (file-name-concat org-persist-directory org-persist-index-file)))
       (org-persist--merge-index-with-disk)
       (org-persist--write-elisp-file index-file org-persist--index t t)
       (setq org-persist--index-age
@@ -865,7 +865,7 @@ (defun org-persist--save-index ()
 (defun org-persist--merge-index-with-disk ()
   "Merge `org-persist--index' with the current index file on disk."
   (let* ((index-file
-          (org-file-name-concat org-persist-directory org-persist-index-file))
+          (file-name-concat org-persist-directory org-persist-index-file))
          (disk-index
           (and (file-exists-p index-file)
                (org-file-newer-than-p index-file org-persist--index-age)
@@ -887,8 +887,8 @@ (defun org-persist--merge-index (base other)
         (dolist (item (nreverse new))
           (unless (or (memq 'index (mapcar #'car (plist-get item :container)))
                       (not (file-exists-p
-                            (org-file-name-concat org-persist-directory
-                                                  (plist-get item :persist-file))))
+                          (file-name-concat org-persist-directory
+                                            (plist-get item :persist-file))))
                       (member (plist-get item :persist-file) base-files))
             (push item combined)))
         (nreverse combined))
@@ -989,7 +989,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load
   (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated)))
          (persist-file
           (when collection
-            (org-file-name-concat
+            (file-name-concat
              org-persist-directory
              (plist-get collection :persist-file))))
          (data nil))
@@ -1077,7 +1077,7 @@ (defun org-persist-write (container &optional associated ignore-return)
                          (run-hook-with-args-until-success 'org-persist-before-write-hook v associated))
                        (plist-get collection :container)))
       (when (or (file-exists-p org-persist-directory) (org-persist--save-index))
-        (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file)))
+        (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file)))
               (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection)))
                             (plist-get collection :container))))
           (puthash file data org-persist--write-cache)
@@ -1097,11 +1097,11 @@ (defun org-persist-write-all (&optional associated)
            ;; The container is an `index' container.
            (eq 'index (caar (plist-get (car org-persist--index) :container)))
            (or (not (file-exists-p org-persist-directory))
-               (org-directory-empty-p org-persist-directory)))
+               (directory-empty-p org-persist-directory)))
       ;; Do not write anything, and clear up `org-persist-directory' to reduce
       ;; clutter.
       (when (and (file-exists-p org-persist-directory)
-                 (org-directory-empty-p org-persist-directory))
+                 (directory-empty-p org-persist-directory))
         (delete-directory org-persist-directory))
     ;; Write the data.
     (let (all-containers)
@@ -1142,7 +1142,7 @@ (defun org-persist--gc-persist-file (persist-file)
   "Garbage collect PERSIST-FILE."
   (when (file-exists-p persist-file)
     (delete-file persist-file)
-    (when (org-directory-empty-p (file-name-directory persist-file))
+    (when (directory-empty-p (file-name-directory persist-file))
       (delete-directory (file-name-directory persist-file)))))
 
 (defmacro org-persist-associated-files:generic (container collection)
@@ -1180,7 +1180,7 @@ (defun org-persist-gc ()
   (let (new-index
         (remote-files-num 0)
         (orphan-files
-         (delete (org-file-name-concat org-persist-directory org-persist-index-file)
+         (delete (file-name-concat org-persist-directory org-persist-index-file)
                  (when (file-exists-p org-persist-directory)
                    (directory-files-recursively org-persist-directory ".+")))))
     (dolist (collection org-persist--index)
@@ -1188,7 +1188,7 @@ (defun org-persist-gc ()
              (web-file (and file (string-match-p "\\`https?://" file)))
              (file-remote (when file (file-remote-p file)))
              (persist-file (when (plist-get collection :persist-file)
-                             (org-file-name-concat
+                             (file-name-concat
                               org-persist-directory
                               (plist-get collection :persist-file))))
              (expired? (org-persist--gc-expired-p
diff --git a/lisp/org-refile.el b/lisp/org-refile.el
index 03c351cf6..9797a0633 100644
--- a/lisp/org-refile.el
+++ b/lisp/org-refile.el
@@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes)
          (prompt (let ((default (or (car org-refile-history)
                                     (and (assoc cbnex tbl) (setq cdef cbnex)
                                          cbnex))))
-                   (org-format-prompt prompt default)))
+                   (format-prompt prompt default)))
 	 pa answ parent-target child parent old-hist)
     (setq old-hist org-refile-history)
     (setq answ (funcall cfunc prompt tbl nil (not new-nodes)
diff --git a/lisp/org.el b/lisp/org.el
index 10ade32dd..e9fa9a241 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding:
 ;; Maintainer: Bastien Guerry <bzg@gnu.org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; URL: https://orgmode.org
-;; Package-Requires: ((emacs "26.1"))
+;; Package-Requires: ((emacs "26.1") (compat "29.1.4.1"))
 
 ;; Version: 9.7-pre
 
@@ -19445,7 +19445,7 @@ (defun org-fill-paragraph (&optional justify region)
 		 (barf-if-buffer-read-only)
 		 (list (when current-prefix-arg 'full) t)))
   (let ((hash (and (not (buffer-modified-p))
-		   (org-buffer-hash))))
+		   (buffer-hash))))
     (cond
      ((and region transient-mark-mode mark-active
 	   (not (eq (region-beginning) (region-end))))
@@ -19470,7 +19470,7 @@ (defun org-fill-paragraph (&optional justify region)
     ;; If we didn't change anything in the buffer (and the buffer was
     ;; previously unmodified), then flip the modification status back
     ;; to "unchanged".
-    (when (and hash (equal hash (org-buffer-hash)))
+    (when (and hash (equal hash (buffer-hash)))
       (set-buffer-modified-p nil))
     ;; Return non-nil.
     t))
diff --git a/lisp/ox.el b/lisp/ox.el
index a6169ea63..203136994 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4626,11 +4626,11 @@ (defun org-export-resolve-radio-link (link info)
 
 Return value can be a radio-target object or nil.  Assume LINK
 has type \"radio\"."
-  (let ((path (org-string-clean-whitespace (org-element-property :path link))))
+  (let ((path (string-clean-whitespace (org-element-property :path link))))
     (org-element-map (plist-get info :parse-tree) 'radio-target
       (lambda (radio)
-	(and (org-string-equal-ignore-case
-	      (org-string-clean-whitespace (org-element-property :value radio))
+	(and (string-equal-ignore-case
+	      (string-clean-whitespace (org-element-property :value radio))
               path)
 	     radio))
       info 'first-match)))
diff --git a/mk/default.mk b/mk/default.mk
index 997b22b66..4ad1a4281 100644
--- a/mk/default.mk
+++ b/mk/default.mk
@@ -38,7 +38,7 @@ pkgdir = $(shell pwd)/pkg-deps
 EFLAGS ?=
 
 # Third-party packages to install when running make
-EPACKAGES ?=
+EPACKAGES ?= compat
 
 # Configuration for testing
 # Verbose ERT summary by default for Emacs-28 and above.
diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el
index a38d9f979..565539571 100644
--- a/testing/lisp/test-ol.el
+++ b/testing/lisp/test-ol.el
@@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display ()
       (dotimes (_ 2)
         (goto-char 1)
         (re-search-forward "\\[")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "example")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "com")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "]")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (re-search-forward "\\[")
         (should-not (org-invisible-p))
         (re-search-forward "link")
         (should-not (org-invisible-p))
         (re-search-forward "]")
-        (should-not (org-xor org-link-descriptive (org-invisible-p)))
+        (should-not (xor org-link-descriptive (org-invisible-p)))
         (org-toggle-link-display)))))
 
 \f
diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el
index 0ed44c6af..6a47b3384 100644
--- a/testing/lisp/test-org-capture.el
+++ b/testing/lisp/test-org-capture.el
@@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort ()
   "Test aborting a capture process."
   ;; Newly create capture buffer should not be saved.
   (let ((capture-file (make-temp-name
-                       (org-file-name-concat
+                       (file-name-concat
                         temporary-file-directory
                         "org-test"))))
     (unwind-protect
-- 
2.39.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-org-manual.org-Document-compat-library-installation.patch --]
[-- Type: text/x-patch, Size: 2242 bytes --]

From cbc781d02021563b2f68b2179813e936ab379446 Mon Sep 17 00:00:00 2001
Message-Id: <cbc781d02021563b2f68b2179813e936ab379446.1680344979.git.yantar92@posteo.net>
In-Reply-To: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net>
References: <f95433f53878e8371bb28a045fdb5d06cf0877b9.1680344979.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 1 Apr 2023 12:18:57 +0200
Subject: [PATCH 3/3] org-manual.org: Document compat library installation

* doc/org-manual.org (Using Org's git repository): Document that users
must also install compat library when using git version of Org.
* etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to
support older Emacs versions): Announce amendments to the Org
installation from git sources.
---
 doc/org-manual.org | 4 ++++
 etc/ORG-NEWS       | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index 50662669e..aa9886e5f 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -140,6 +140,10 @@ *** Using Org's git repository
 (add-to-list 'load-path "~/src/org-mode/lisp")
 #+end_src
 
+You must also manually install =compat= library required by Org mode.
+Using built-in =package.el=, you can run =M-x package-install <RET>
+compat <RET>=.
+
 You can also compile with =make=, generate the documentation with
 =make doc=, create a local configuration with =make config= and
 install Org with =make install=.  Please run =make help= to get the
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index ac233a986..0302b8cda 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org.
 
 * Version 9.7 (not released yet)
 ** Important announcements and breaking changes
+*** Org mode now uses =compat.el= third-party package to support older Emacs versions
+
+This change is mostly technical and should not affect most users.
+However, people who install Org from git source might be affected.
+It is now necessary to manually install =compat.el= using Emacs'
+package manager.
+
 *** =python-mode.el (MELPA)= support in =ob-python.el= is removed
 
 =python-mode.el= support has been removed from =ob-python.el=.  The
-- 
2.39.1


[-- Attachment #5: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

  parent reply	other threads:[~2023-04-01 10:30 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-11 10:36 Useful package? Compat.el Timothy
2021-10-11 14:28 ` Russell Adams
2021-10-11 14:40   ` Timothy
2021-10-11 18:04     ` Joost Kremers
2023-01-27 13:23 ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Ihor Radchenko
2023-01-27 13:34   ` [POLL] Use compat.el in Org? Bastien Guerry
2023-01-27 20:38     ` Tim Cross
2023-01-27 21:38       ` Daniel Mendler
2023-01-27 22:29         ` Samuel Wales
2023-01-28 16:04   ` [POLL] Use compat.el in Org? (was: Useful package? Compat.el) Kyle Meyer
2023-01-30 11:35   ` Greg Minshall
2023-01-30 19:33     ` Ihor Radchenko
2023-01-30 19:40       ` Greg Minshall
2023-01-30 21:38         ` Daniel Mendler
2023-04-01 10:31   ` Ihor Radchenko [this message]
2023-04-01 11:38     ` [PATCH] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Daniel Mendler
2023-04-01 14:20       ` Max Nikulin
2023-04-02  8:52         ` Ihor Radchenko
2023-04-02 15:31           ` Max Nikulin
2023-04-02 16:04             ` Ihor Radchenko
2023-04-02 16:37     ` Max Nikulin
2023-04-02 17:00       ` [PATCH v2] " Ihor Radchenko
2023-04-03  8:46         ` [PATCH v3] " Ihor Radchenko
2023-04-08 11:15         ` [PATCH v2] " Max Nikulin
2023-04-08 11:41           ` Ihor Radchenko
2023-04-08 16:37             ` Max Nikulin
2023-04-13 12:42               ` Ihor Radchenko
2023-04-17 17:20                 ` Max Nikulin
2023-04-20  9:27                   ` Ihor Radchenko
2023-04-28 15:27                     ` Max Nikulin
2023-04-30 10:39                       ` [PATCH v4] " Ihor Radchenko
2023-05-03 12:14                         ` [PATCH] epm.el: A CLI tool for package.el Max Nikulin
2023-05-04 10:24                           ` Ihor Radchenko
2023-05-04 16:16                             ` Max Nikulin
2023-05-05  9:39                               ` Ihor Radchenko
2023-05-06  6:39                         ` [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) Max Nikulin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87r0t3gahd.fsf@localhost \
    --to=yantar92@posteo.net \
    --cc=bzg@gnu.org \
    --cc=emacs-orgmode@gnu.org \
    --cc=kyle@kyleam.com \
    --cc=mail@daniel-mendler.de \
    --cc=tecosaur@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).