From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms9.migadu.com with LMTPS id j8POCPZETmQwZwAASxT56A (envelope-from ) for ; Sun, 30 Apr 2023 12:37:42 +0200 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id mKC/B/ZETmTRxwAAauVa8A (envelope-from ) for ; Sun, 30 Apr 2023 12:37:42 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id EE5E727154 for ; Sun, 30 Apr 2023 12:37:40 +0200 (CEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pt4QF-0000b4-Lj; Sun, 30 Apr 2023 06:36:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pt4QE-0000aq-Nw for emacs-orgmode@gnu.org; Sun, 30 Apr 2023 06:36:50 -0400 Received: from mout01.posteo.de ([185.67.36.65]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pt4Q8-0007qW-Hn for emacs-orgmode@gnu.org; Sun, 30 Apr 2023 06:36:50 -0400 Received: from submission (posteo.de [185.67.36.169]) by mout01.posteo.de (Postfix) with ESMTPS id 3A40B2401A3 for ; Sun, 30 Apr 2023 12:36:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1682851002; bh=kFSJN/XW0A8NQ/m54KUPRl8g7U9AYEaH5hAR4TaD7qE=; h=From:To:Cc:Subject:Date:From; b=Ix6nDFlRTYhiDoVbRMtjWMgTcHtPjHdBOhYuB8t5y9BRqeH/kG/AIar7YuI0BFV6t azsxp+wp15hmCy3ekM3a3fNc2LpMHVNTplOby65WF4Bi3lmya8ys6IZI6syrZSmkUp GBX1JiJTFTr+cWE1ED99KsfqTSxolljU19s9pwX5WTCBt44JiCv4ZuWKD2UWimT0LD z+lIzKCEoHhrUoQ2Tr33CF01ibVvegGKEJoPck8+DUREx5cL4w0BlGF7/F9hoiKCml 9nMNUVlFWfjDgwCF635yM712yzP7WNlV4NSpsR3aD+n1N6X3V3vmcmHvAMuPma1U+L TqDtnEcCviY7A== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4Q8N7F3X1tz9rxD; Sun, 30 Apr 2023 12:36:41 +0200 (CEST) From: Ihor Radchenko To: Max Nikulin Cc: emacs-orgmode@gnu.org Subject: [PATCH v4] Add compat.el support to Org (was: [POLL] Use compat.el in Org? (was: Useful package? Compat.el)) In-Reply-To: References: <87sfx7degz.fsf@gmail.com> <87v8ks6rhf.fsf@localhost> <87r0t3gahd.fsf@localhost> <87wn2ujk27.fsf@localhost> <87jzymk3dq.fsf@localhost> <87o7nsdkcw.fsf@localhost> <878remykby.fsf@localhost> Date: Sun, 30 Apr 2023 10:39:41 +0000 Message-ID: <877cttirgy.fsf@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=185.67.36.65; envelope-from=yantar92@posteo.net; helo=mout01.posteo.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US ARC-Seal: i=1; s=key1; d=yhetil.org; t=1682851061; a=rsa-sha256; cv=none; b=f+TBWwET1r34z4W2ODp9Pvv7GaelYWTDbpv3Bs4rQTWKeGMZnO7XJepQiubc+Js5f+Ei52 MCgFbQspkbBBpSfoWRTJaQ9Y0P0MiQTIyigIXccEYPCmfmpOGJOQNQUgvBJUT46hmlDJPS +wS/06iOMKxyrPVK52ViJMF5WqJVcLuXJLRVJkn2UkyChlYM3INxukydP24KSdEjGwO6e1 JlB9pxdlO4kktjYjl0AhK4GC3qHuru5xgB7jG5jXBtS34NXMN8zdPsIxVe4hROPk/3oLzY 9E7wBXKUtKvfthVGUMXBP65YsPUtFQso1UclBAcVn0Afb3SsyaaKAMrm1xj7ow== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=Ix6nDFlR; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1682851061; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=0m0cgQx+jydCUtFLm02VXX9DHZRSfiI0KaGJ7O98Kek=; b=n8Y3od/Fy2i34MqZ+pbbNT4TSN3P/U/RsrZMVwt08zLGmAZUHzaEdIweQia8FJjkACd+v9 ct+Nd76sbnDXtezInj9BX7yP433SuUmAql/oCoeS1uLvm3zcN4JeRgxMkZ4KxQqx6EYMrM 1T33u7B2JKf3o0GAlcidhyS4jc8WRr3HTqDZRdDozT0ksa8PPy62fvBA2/OFan4ahuNlcj lrPs7AYTyUZl6erqN5Mj0o22MJno9O0ynhgDUr1nYYmDeLeg8bc/IedTDXvZVk8WZa+2pb 8qMQTpm/Loe/I+Rcx+FiYE4UYUV5+qXd8cfZBS5YQKmEyX8ymxLuU9ThtHI3pQ== X-Migadu-Scanner: scn1.migadu.com Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=Ix6nDFlR; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -4.59 X-Spam-Score: -4.59 X-Migadu-Queue-Id: EE5E727154 X-TUID: hRvWbN6mz5pE --=-=-= Content-Type: text/plain Max Nikulin writes: > I do not like lengthy emacs commands and make functions to generate > them. I think, it is better to move such code to a script. A proof of > concept is attached, however it is rather rough draft > > ./epm.el -Q --epm-dir $(emacs_pkgdir)/emacs-%e install compat > ./epm.el -Q -L ~/src/compat install compat Good idea. Although, we should not overdo this package management thing. If we really need complex functionality here, we should better just use cask/eldev instead of re-inventing the wheel. Are you willing to improve the draft to be ready for upstream? I will provide some inline comments below. > By the way, accordingly to (info "(make) Command Variables") or (info > "(standards) Command Variables") "Variables for Specifying Commands" > https://www.gnu.org/prep/standards/html_node/Command-Variables.html > > it should be EMACSFLAGS rather than EFLAGS. Fair point. I now rearranged the commits as you asked and incorporated this change. See the attached. Note that also I changed the way compat.el is loaded, making Org throw an error for older Emacs versions. This will produce more useful error if someone attempts to load Org as is, without installing compat.el in older Emacs. >> I have no problem with this approach when using system packages. >> However, it is almost guaranteed that compat.el is absent in global >> load-path as long as compat.el is not built-in. > > I see that installation attempt is not performed when packages are > available. However form my point of view it is normal when compilation > fails when dependency are not provided. It works so for decades for > applications that use make. To be precise, usually I expect detection of > missed libraries from configure scrips, but in some cases they are > missed. Maybe such experience was formed when access to network was limited. > > For me it is quite natural that make does try to pull dependencies (at > least by default) and it is my responsibility to ensure availability of > necessary libraries. I think that we need to zoom out a bit and discuss the contexts where Org build system is used: 1. During Org development, by developers who know what they are doing 2. By ordinary users, not necessarily familiar with GNU make and all the associated build process conventions. Org developers may need to use the whole spectrum of make targets, and will generally benefit from isolation of Org from the main Emacs configuration folder. For example, my `package-user-dir' contains a number of forks with additional patches applied - it is not the environment I want to develop (and test) Org in. Org users will likely use make autoloads, make, make docs, and make repro. Here, it will make sense to re-use default .emacs.d and package directory when running make, as ordinary users running make are most likely aiming to build Org for their own usage. However, make repro and optionally make docs should avoid re-using user packages as it may cause inconsistent results if the `package-user-dir' is messed up. One way to handle the above scenarios might be your idea with AUTODEP. By default, it will be "auto": - make compile, docs :: Re-use default `package-user-dir' - make repro :: Auto-download and ignore `package-user-dir' - other targets :: Prompt the user Alternatives will be meant to be used as AUTODEP=download/user/no make target. triggering unconditional downloading, using `package-user-dir', and not using any guess, correspondingly. WDYT? >>> I do not like that versions of dependencies are ignored. I have noticed >>> `package-install-from-buffer'. Perhaps it can be used to generate a stub >>> package (e.g. org-build-deps) with Package-Requires line obtained from >>> org.el. The only purpose of this package is to pull dependencies. It is >>> just an idea, I have not tried such approach. >> >> This sounds fragile. I see no reason to go this far and using so complex >> approach. > > My idea is to ensure that *required* version is installed, not some > stale one. I have not tried such approach though. I think that it is stretching a bit beyond the complexity we should allow within Org build system. In your scenario, I can simply do make cleanpkg and re-download the latest dependencies. Again, package management is not something we want to overdo. If really necessary, we will use cask or other proper Elisp development tool. > #!/bin/sh > ":"; # -*- mode: emacs-lisp; lexical-binding: t; -*- > ":"; exec emacs --script "$0" "$@" Let's not lock to bash. AFAIK, our makefiles can currently work on Windows. Using /bin/sh will lead to regression. So, a simple --batch script for Emacs will be better here. > (defun epm-init () > (unless (epm-nonempty-p epm-dir) > (setq epm-dir (getenv "EPMDIR"))) > (when (epm-nonempty-p epm-dir) > (let* ((fmt-expanded (format-spec epm-dir `((?e . ,emacs-version)))) > (dir (directory-file-name (expand-file-name fmt-expanded)))) > ;; `package-user-dir' ~/.emacs.d/elpa by default > ;; `package-directory-list' does not include it What does this comment refer to? --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0001-Upgrade-Org-build-system-to-handle-third-party-de.patch >From 3946dbb956afcd005cba0f1899acae5a74a109d4 Mon Sep 17 00:00:00 2001 Message-Id: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sat, 1 Apr 2023 12:00:48 +0200 Subject: [PATCH v4 1/8] Upgrade Org build system to handle third-party dependencies * mk/default.mk (pkgdir_top): New variable holding the location of third-party packages to be downloaded if necessary during compilation. (EMACS_VERSION): New variable holding current Emacs version, according to EMACS. (pkgdir): New variable holding subdir where the third-party packages are downloaded, according to EMACS_VERSION. (EMACSFLAGS): New variable holding extra flags to be passed to Emacs executable when running make. We follow "PROGRAMFLAGS" convention as requested by GNU standards: https://www.gnu.org/prep/standards/html_node/Command-Variables.html (EPACKAGES): List of packages to be installed (unless already present in the `load-path') during compilation. (package-install): (INSTALL_PACKAGES): New command to download and install missing packages. (EMACSQ): Update, setting default package location to pkgdir. * mk/targets.mk (uppkg): New target to download install missing packages. (check test): (repro): (compile compile-dirty): Use the new uppkg target. (cleanpkg): New target cleaning up the downloaded packages. (cleanall): Use the new target. (.PHONY): (CONF_BASE): (CONF_DEST): (CONF_CALL): Update according to the new variables and targets. * .gitignore: Ignore the downloaded packages. This commit paves the way towards third-party built-time dependencies for Org. In particular, towards including compat.el dependency. According to EPACKAGES, we can auto-download necessary packages, unless they are manually specified via -L switches in EMACSFLAGS. Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- .gitignore | 1 + mk/default.mk | 31 ++++++++++++++++++++++++++++++- mk/targets.mk | 25 ++++++++++++++++--------- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 4bb81c359..0d9c5b297 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ local*.mk .gitattributes mk/x11idle ChangeLog +pkg-deps/ # Files generated during `make packages/org` in a clone of `elpa.git`. diff --git a/mk/default.mk b/mk/default.mk index fa46661e8..393d7336a 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -6,6 +6,7 @@ # Name of your emacs binary EMACS = emacs +EMACS_VERSION := $(shell $(EMACS) -Q --batch --eval '(message "%s" emacs-version)' 2>&1) # Where local software is found prefix = /usr/share @@ -31,6 +32,17 @@ GIT_BRANCH = TMPDIR ?= /tmp testdir = $(TMPDIR)/tmp-orgtest +# Where to store Org dependencies +top_builddir := $(shell pwd) +pkgdir_top := $(top_builddir)/pkg-deps +pkgdir := $(pkgdir_top)/$(EMACS_VERSION) + +# Extra flags to be passed to Emacs +EMACSFLAGS ?= + +# Third-party packages to install when running make +EPACKAGES ?= + # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. # To override: @@ -72,12 +84,25 @@ REPRO_ARGS ?= req-ob-lang = --eval '(require '"'"'ob-$(ob-lang))' lst-ob-lang = ($(ob-lang) . t) req-extra = --eval '(require '"'"'$(req))' +package-define-refresh-mark = --eval '(setq org--compile-packages-missing nil)' +package-need-refresh-mark = --eval '(unless (require '"'"'$(package) nil t) (setq org--compile-packages-missing t))' +package-refresh-maybe = --eval '(if org--compile-packages-missing (package-refresh-contents) (message "No third-party packages need to be installed"))' +package-install-maybe = --eval '(unless (require '"'"'$(package) nil t) (package-install '"'"'$(package)))' BTEST_RE ?= \\(org\\|ob\\|ox\\) BTEST_LOAD = \ --eval '(add-to-list '"'"'load-path (concat default-directory "lisp"))' \ --eval '(add-to-list '"'"'load-path (concat default-directory "testing"))' BTEST_INIT = $(BTEST_PRE) $(BTEST_LOAD) $(BTEST_POST) +ifeq (,$(EPACKAGES)) +INSTALL_PACKAGES = +else +INSTALL_PACKAGES = \ + $(BATCH) \ + $(package-define-refresh-mark) $(foreach package,$(EPACKAGES),$(package-need-refresh-mark)) $(package-refresh-maybe) \ + $(foreach package,$(EPACKAGES),$(package-install-maybe)) +endif + BTEST = $(BATCH) $(BTEST_INIT) \ -l org-batch-test-init \ --eval '(setq \ @@ -116,7 +141,11 @@ REPRO = $(NOBATCH) $(REPRO_INIT) $(REPRO_ARGS) # start Emacs with no user and site configuration # EMACSQ = -vanilla # XEmacs -EMACSQ = $(EMACS) -Q +EMACSQ = $(EMACS) -Q \ + $(EMACSFLAGS) \ + --eval '(setq vc-handled-backends nil org-startup-folded nil org-element-cache-persistent nil)' \ + --eval '(make-directory "$(pkgdir)" t)' \ + --eval '(setq package-user-dir "$(pkgdir)")' --eval '(package-initialize)' # Using emacs in batch mode. BATCH = $(EMACSQ) -batch \ diff --git a/mk/targets.mk b/mk/targets.mk index 06016561c..18140c5c0 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -27,21 +27,21 @@ ifneq ($(GITSTATUS),) GITVERSION := $(GITVERSION:.dirty=).dirty endif -.PHONY: all oldorg update update2 up0 up1 up2 single $(SUBDIRS) \ +.PHONY: all oldorg update update2 up0 up1 up2 uppkg single $(SUBDIRS) \ check test install $(INSTSUB) \ info html pdf card refcard doc docs \ autoloads cleanall clean $(CLEANDIRS:%=clean%) \ clean-install cleanelc cleandirs \ - cleanlisp cleandoc cleandocs cleantest \ + cleanlisp cleandoc cleandocs cleantest cleanpkg \ compile compile-dirty uncompiled \ config config-test config-exe config-all config-eol config-version \ vanilla repro -CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC -CONF_DEST = lispdir infodir datadir testdir +CONF_BASE = EMACS DESTDIR ORGCM ORG_MAKE_DOC EPACKAGES +CONF_DEST = lispdir infodir datadir testdir pkgdir CONF_TEST = BTEST_PRE BTEST_POST BTEST_OB_LANGUAGES BTEST_EXTRA BTEST_RE CONF_EXEC = CP MKDIR RM RMR FIND CHMOD SUDO PDFTEX TEXI2PDF TEXI2HTML MAKEINFO INSTALL_INFO -CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION +CONF_CALL = BATCH BATCHL ELC ELCDIR NOBATCH INSTALL_PACKAGES BTEST MAKE_LOCAL_MK MAKE_ORG_INSTALL MAKE_ORG_VERSION config-eol:: EOL = \# config-eol:: config-all config config-all:: @@ -86,7 +86,7 @@ local.mk: all compile:: $(foreach dir, doc lisp, $(MAKE) -C $(dir) clean;) -compile compile-dirty:: +compile compile-dirty:: uppkg $(MAKE) -C lisp $@ all clean-install:: $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@;) @@ -94,7 +94,7 @@ all clean-install:: vanilla: -@$(NOBATCH) & -check test:: compile +check test:: uppkg compile check test test-dirty:: -$(MKDIR) $(testdir) TMPDIR=$(testdir) $(BTEST) @@ -102,6 +102,10 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f $(MAKE) cleantest endif +uppkg:: + @$(MKDIR) -p $(pkgdir) + -@$(INSTALL_PACKAGES) + up0 up1 up2:: git checkout $(GIT_BRANCH) git remote update @@ -126,7 +130,7 @@ $(INSTSUB): autoloads: lisp $(MAKE) -C $< $@ -repro: cleanall autoloads +repro: cleanall uppkg autoloads -@$(REPRO) & cleandirs: @@ -134,7 +138,7 @@ cleandirs: clean: cleanlisp cleandoc -cleanall: cleandirs cleantest +cleanall: cleandirs cleantest cleanpkg -$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} + -$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} + @@ -159,3 +163,6 @@ cleantest: $(FIND) $(testdir) -type d -exec $(CHMOD) u+w {} + && \ $(RMR) $(testdir) ; \ } + +cleanpkg: + -$(RMR) $(pkgdir_top) -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0002-org-compat-Add-optional-compat.el-support.patch >From f30e75e3b14b3cb955d2dcd11f210cfaceef07b6 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Mon, 3 Apr 2023 10:40:00 +0200 Subject: [PATCH v4 2/8] org-compat: Add optional compat.el support * lisp/org-compat.el (compat): Load Compat library, when available. (org-compat-function): (org-compat-call): Add compatibility macros available even when Compat is not available (Org is a part of Emacs). --- lisp/org-compat.el | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 34b27546d..9c286961a 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -94,6 +94,48 @@ (defvar org-table-tab-recognizes-table.el) (defvar org-table1-hline-regexp) (defvar org-fold-core-style) + +;;; 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))) + ;;; Emacs < 29 compatibility -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0003-Add-compat.el-dependency.patch >From 03902b1efe931145870c64f517442b49f7ec92a3 Mon Sep 17 00:00:00 2001 Message-Id: <03902b1efe931145870c64f517442b49f7ec92a3.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sat, 29 Apr 2023 11:34:00 +0200 Subject: [PATCH v4 3/8] Add compat.el dependency * mk/default.mk (EPACKAGES): Demand compat library during compile time. * lisp/org.el: Add Compat to package-requires. Compat 29.1.3.2 is pre-installed on current Ubuntu 23.04. Do not require later version as it is (1) not yet necessary, (2) will make life slightly easier for people who do not want to download staff unnecessarily. Link: https://list.orgmode.org/orgmode/u09ejk$vi1$1@ciao.gmane.io/ --- lisp/org.el | 2 +- mk/default.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 78040a8e3..162982405 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -7,7 +7,7 @@ ;;; org.el --- Outline-based notes management and organizer -*- lexical-binding: ;; Maintainer: Bastien Guerry ;; Keywords: outlines, hypermedia, calendar, wp ;; URL: https://orgmode.org -;; Package-Requires: ((emacs "26.1")) +;; Package-Requires: ((emacs "26.1") (compat "29.1.3.2")) ;; Version: 9.7-pre diff --git a/mk/default.mk b/mk/default.mk index 393d7336a..cc5775362 100644 --- a/mk/default.mk +++ b/mk/default.mk @@ -41,7 +41,7 @@ pkgdir := $(pkgdir_top)/$(EMACS_VERSION) EMACSFLAGS ?= # Third-party packages to install when running make -EPACKAGES ?= +EPACKAGES ?= compat # Configuration for testing # Verbose ERT summary by default for Emacs-28 and above. -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0004-Use-compat.el-library-instead-of-ad-hoc-compatibi.patch >From 239c8626b95c19ec1ac466b14876b826c37b4986 Mon Sep 17 00:00:00 2001 Message-Id: <239c8626b95c19ec1ac466b14876b826c37b4986.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Mon, 3 Apr 2023 10:41:50 +0200 Subject: [PATCH v4 4/8] Use compat.el library instead of ad-hoc compatibility function set * lisp/org.el (org-fill-paragraph): * lisp/org-compat.el: Obsolete org-* compatibility functions that are already available in compat.el: `org-file-has-changed-p', `org-string-equal-ignore-case', `org-file-name-concat', `org-directory-empty-p', `org-string-clean-whitespace', `org-format-prompt', `org-xor', `org-string-distance', `org-buffer-hash'. * lisp/ob-core.el (org-babel-results-keyword): Use functions provided by compat.el. (org-babel-insert-result): * lisp/oc-basic.el (org-cite-basic--parse-bibliography): * lisp/oc.el (org-cite-adjust-note): * lisp/ol-gnus.el (org-gnus-group-link): (org-gnus-article-link): (org-gnus-store-link): * lisp/ol.el: (org-store-link): * lisp/org-attach.el: * lisp/org-capture.el: (org-capture-fill-template): * lisp/org-fold-core.el (org-fold-core-next-visibility-change): * lisp/org-lint.el: * lisp/org-persist.el (org-persist-directory): (org-persist-read:file): (org-persist-read:url): (org-persist--load-index): (org-persist-write:file): (org-persist-write:index): (org-persist--merge-index-with-disk): (org-persist-read): (org-persist-write): (org-persist-write-all): (org-persist--gc-persist-file): (org-persist-gc): * lisp/org-refile.el (org-refile-get-location): * lisp/ox.el (org-export-resolve-radio-link): * testing/lisp/test-ol.el (test-org-link/toggle-link-display): * testing/lisp/test-org-capture.el (test-org-capture/abort): Link: https://orgmode.org/list/87v8ks6rhf.fsf@localhost --- lisp/ob-core.el | 10 +- lisp/oc-basic.el | 6 +- lisp/oc.el | 2 +- lisp/ol-gnus.el | 8 +- lisp/ol.el | 4 +- lisp/org-attach.el | 2 +- lisp/org-capture.el | 8 +- lisp/org-compat.el | 180 ++++--------------------------- lisp/org-fold-core.el | 2 +- lisp/org-lint.el | 2 +- lisp/org-persist.el | 38 +++---- lisp/org-refile.el | 2 +- lisp/org.el | 4 +- lisp/ox.el | 6 +- testing/lisp/test-ol.el | 10 +- testing/lisp/test-org-capture.el | 2 +- 16 files changed, 74 insertions(+), 212 deletions(-) diff --git a/lisp/ob-core.el b/lisp/ob-core.el index a2a84ad20..9034feb7e 100644 --- a/lisp/ob-core.el +++ b/lisp/ob-core.el @@ -145,7 +145,7 @@ (defcustom org-babel-results-keyword "RESULTS" :type 'string :safe (lambda (v) (and (stringp v) - (org-string-equal-ignore-case "RESULTS" v)))) + (string-equal-ignore-case "RESULTS" v)))) (defcustom org-babel-noweb-wrap-start "<<" "String used to begin a noweb reference in a code block. @@ -927,7 +927,7 @@ (defun org-babel-check-src-block () (match-string 4)))))) (dolist (name names) (when (and (not (string= header name)) - (<= (org-string-distance header name) too-close) + (<= (string-distance header name) too-close) (not (member header names))) (error "Supplied header \"%S\" is suspiciously close to \"%S\"" header name)))) @@ -2521,7 +2521,7 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex ;; Escape contents from "export" wrap. Wrap ;; inline results within an export snippet with ;; appropriate value. - ((org-string-equal-ignore-case type "export") + ((string-equal-ignore-case type "export") (let ((backend (pcase split (`(,_) "none") (`(,_ ,b . ,_) b)))) @@ -2532,14 +2532,14 @@ (defun org-babel-insert-result (result &optional result-params info hash lang ex backend) "@@)}}}"))) ;; Escape contents from "example" wrap. Mark ;; inline results as verbatim. - ((org-string-equal-ignore-case type "example") + ((string-equal-ignore-case type "example") (funcall wrap opening-line closing-line nil nil "{{{results(=" "=)}}}")) ;; Escape contents from "src" wrap. Mark ;; inline results as inline source code. - ((org-string-equal-ignore-case type "src") + ((string-equal-ignore-case type "src") (let ((inline-open (pcase split (`(,_) diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el index fdcb5bda2..88bce4418 100644 --- a/lisp/oc-basic.el +++ b/lisp/oc-basic.el @@ -274,11 +274,11 @@ (defun org-cite-basic--parse-bibliography (&optional info) (dolist (file (org-cite-list-bibliography-files)) (when (file-readable-p file) (with-temp-buffer - (when (or (org-file-has-changed-p file) + (when (or (file-has-changed-p file) (not (gethash file org-cite-basic--file-id-cache))) (insert-file-contents file) (set-visited-file-name file t) - (puthash file (org-buffer-hash) org-cite-basic--file-id-cache)) + (puthash file (buffer-hash) org-cite-basic--file-id-cache)) (condition-case nil (unwind-protect (let* ((file-id (cons file (gethash file org-cite-basic--file-id-cache))) @@ -488,7 +488,7 @@ (defun org-cite-basic--close-keys (key keys) "List cite keys close to KEY in terms of string distance." (seq-filter (lambda (k) (>= org-cite-basic-max-key-distance - (org-string-distance k key))) + (string-distance k key))) keys)) (defun org-cite-basic--set-keymap (beg end suggestions) diff --git a/lisp/oc.el b/lisp/oc.el index 4b1420271..9b96ef8d3 100644 --- a/lisp/oc.el +++ b/lisp/oc.el @@ -1029,7 +1029,7 @@ (defun org-cite-adjust-note (citation info &optional rule punct) (match-string 3 previous))))) ;; Bail you when there is no quote and either no punctuation, or ;; punctuation on both sides. - (when (or quote (org-xor punct final-punct)) + (when (or quote (xor punct final-punct)) ;; Phase 1: handle punctuation rule. (pcase rule ((guard (not quote)) nil) diff --git a/lisp/ol-gnus.el b/lisp/ol-gnus.el index 7c07ce045..e121cfba3 100644 --- a/lisp/ol-gnus.el +++ b/lisp/ol-gnus.el @@ -98,8 +98,8 @@ (defun org-gnus-group-link (group) `org-gnus-prefer-web-links' is reversed." (let ((unprefixed-group (replace-regexp-in-string "^[^:]+:" "" group))) (if (and (string-prefix-p "nntp" group) ;; Only for nntp groups - (org-xor current-prefix-arg - org-gnus-prefer-web-links)) + (xor current-prefix-arg + org-gnus-prefer-web-links)) (concat "https://groups.google.com/group/" unprefixed-group) (concat "gnus:" group)))) @@ -116,7 +116,7 @@ (defun org-gnus-article-link (group newsgroups message-id x-no-archive) If `org-store-link' was called with a prefix arg the meaning of `org-gnus-prefer-web-links' is reversed." - (if (and (org-xor current-prefix-arg org-gnus-prefer-web-links) + (if (and (xor current-prefix-arg org-gnus-prefer-web-links) newsgroups ;make web links only for nntp groups (not x-no-archive)) ;and if X-No-Archive isn't set (format "https://groups.google.com/groups/search?as_umsgid=%s" @@ -169,7 +169,7 @@ (defun org-gnus-store-link () newsgroups x-no-archive) ;; Fetching an article is an expensive operation; newsgroup and ;; x-no-archive are only needed for web links. - (when (org-xor current-prefix-arg org-gnus-prefer-web-links) + (when (xor current-prefix-arg org-gnus-prefer-web-links) ;; Make sure the original article buffer is up-to-date. (save-window-excursion (gnus-summary-select-article)) (setq to (or to (gnus-fetch-original-field "To"))) diff --git a/lisp/ol.el b/lisp/ol.el index e2bf90acd..d7056abde 100644 --- a/lisp/ol.el +++ b/lisp/ol.el @@ -1692,7 +1692,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let* ((element (org-element-at-point)) (name (org-element-property :name element)) (context @@ -1724,7 +1724,7 @@ (defun org-store-link (arg &optional interactive?) (abbreviate-file-name (buffer-file-name (buffer-base-buffer))))) ;; Add a context search string. - (when (org-xor org-link-context-for-files (equal arg '(4))) + (when (xor org-link-context-for-files (equal arg '(4))) (let ((context (org-link--normalize-string (or (org-link--context-from-region) (org-current-line-string)) diff --git a/lisp/org-attach.el b/lisp/org-attach.el index 824af69da..581708f5f 100644 --- a/lisp/org-attach.el +++ b/lisp/org-attach.el @@ -678,7 +678,7 @@ (defun org-attach-sync () (let ((files (org-attach-file-list attach-dir))) (org-attach-tag (not files))) (when org-attach-sync-delete-empty-dir - (when (and (org-directory-empty-p attach-dir) + (when (and (directory-empty-p attach-dir) (if (eq 'query org-attach-sync-delete-empty-dir) (yes-or-no-p "Attachment directory is empty. Delete?") t)) diff --git a/lisp/org-capture.el b/lisp/org-capture.el index b96e9f336..c5b1c6d50 100644 --- a/lisp/org-capture.el +++ b/lisp/org-capture.el @@ -1323,9 +1323,9 @@ (defun org-capture-place-item () ;; prioritize the existing list. (when prepend? (let ((ordered? (eq 'ordered (org-element-property :type item)))) - (when (org-xor ordered? - (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" - template)) + (when (xor ordered? + (string-match-p "\\`[A-Za-z0-9]\\([.)]\\)" + template)) (org-cycle-list-bullet (if ordered? "1." "-"))))) ;; Eventually repair the list for proper indentation and ;; bullets. @@ -1867,7 +1867,7 @@ (defun org-capture-fill-template (&optional template initial annotation) (setq org-capture--prompt-history (gethash prompt org-capture--prompt-history-table)) (push (org-completing-read - (org-format-prompt (or prompt "Enter string") default) + (format-prompt (or prompt "Enter string") default) completions nil nil nil 'org-capture--prompt-history default) strings) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index 9c286961a..c40510c35 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -79,9 +79,6 @@ (declare-function org-fold-region "org-fold" (from to flag &optional spec)) (declare-function org-fold-show-all "org-fold" (&optional types)) (declare-function org-fold-show-children "org-fold" (&optional level)) (declare-function org-fold-show-entry "org-fold" (&optional hide-drawers)) -;; `org-string-equal-ignore-case' is in _this_ file but isn't at the -;; top-level. -(declare-function org-string-equal-ignore-case "org-compat" (string1 string2)) (defvar calendar-mode-map) (defvar org-complex-heading-regexp) @@ -136,105 +133,26 @@ (defmacro org-compat-call (fun &rest args) (let ((compat (intern (format "compat--%s" fun)))) `(,(if (fboundp compat) compat fun) ,@args))) - -;;; 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)))) - - -;;; Emacs < 28.1 compatibility - -(if (fboundp 'file-name-concat) - (defalias 'org-file-name-concat #'file-name-concat) - (defun org-file-name-concat (directory &rest components) - "Append COMPONENTS to DIRECTORY and return the resulting string. - -Elements in COMPONENTS must be a string or nil. -DIRECTORY or the non-final elements in COMPONENTS may or may not end -with a slash -- if they don't end with a slash, a slash will be -inserted before contatenating." - (save-match-data - (mapconcat - #'identity - (delq nil - (mapcar - (lambda (str) - (when (and str (not (seq-empty-p str)) - (string-match "\\(.+\\)/?" str)) - (match-string 1 str))) - (cons directory components))) - "/")))) - -(if (fboundp 'directory-empty-p) - (defalias 'org-directory-empty-p #'directory-empty-p) - (defun org-directory-empty-p (dir) - "Return t if DIR names an existing directory containing no other files." - (and (file-directory-p dir) - (null (directory-files dir nil directory-files-no-dot-files-regexp t))))) - -(if (fboundp 'string-clean-whitespace) - (defalias 'org-string-clean-whitespace #'string-clean-whitespace) - ;; From Emacs subr-x.el. - (defun org-string-clean-whitespace (string) - "Clean up whitespace in STRING. -All sequences of whitespaces in STRING are collapsed into a -single space character, and leading/trailing whitespace is -removed." - (let ((blank "[[:blank:]\r\n]+")) - (string-trim (replace-regexp-in-string blank " " string t t) - blank blank)))) - -(if (fboundp 'format-prompt) - (defalias 'org-format-prompt #'format-prompt) - ;; From Emacs minibuffer.el, inlining - ;; `minibuffer-default-prompt-format' value and replacing `length<' - ;; (both new in Emacs 28.1). - (defun org-format-prompt (prompt default &rest format-args) - "Compatibility substitute for `format-prompt'." - (concat - (if (null format-args) - prompt - (apply #'format prompt format-args)) - (and default - (or (not (stringp default)) - (> (length default) 0)) - (format " (default %s)" - (if (consp default) - (car default) - default))) - ": "))) +;; Obsolete compatibility wrappers used before inclusion of compat.el. + +(define-obsolete-function-alias 'org-file-has-changed-p + 'file-has-changed-p "9.7") +(define-obsolete-function-alias 'org-string-equal-ignore-case + 'string-equal-ignore-case "9.7") +(define-obsolete-function-alias 'org-file-name-concat + 'file-name-concat "9.7") +(define-obsolete-function-alias 'org-directory-empty-p + 'directory-empty-p "9.7") +(define-obsolete-function-alias 'org-string-clean-whitespace + 'string-clean-whitespace "9.7") +(define-obsolete-function-alias 'org-format-prompt + 'format-prompt "9.7") +(define-obsolete-function-alias 'org-xor + 'xor "9.7") +(define-obsolete-function-alias 'org-string-distance + 'string-distance "9.7") +(define-obsolete-function-alias 'org-buffer-hash + 'buffer-hash "9.7") ;;; Emacs < 27.1 compatibility @@ -252,22 +170,6 @@ (if (version< emacs-version "27.1") (replace-buffer-contents source)) (defalias 'org-replace-buffer-contents #'replace-buffer-contents)) -(unless (fboundp 'proper-list-p) - ;; `proper-list-p' was added in Emacs 27.1. The function below is - ;; taken from Emacs subr.el 200195e824b^. - (defun proper-list-p (object) - "Return OBJECT's length if it is a proper list, nil otherwise. -A proper list is neither circular nor dotted (i.e., its last cdr -is nil)." - (and (listp object) (ignore-errors (length object))))) - -(if (fboundp 'xor) - ;; `xor' was added in Emacs 27.1. - (defalias 'org-xor #'xor) - (defsubst org-xor (a b) - "Exclusive `or'." - (if a (not b) b))) - (unless (fboundp 'pcomplete-uniquify-list) ;; The misspelled variant was made obsolete in Emacs 27.1 (defalias 'pcomplete-uniquify-list 'pcomplete-uniqify-list)) @@ -297,29 +199,6 @@ (defun org--set-faces-extend (faces extend-p) (when (fboundp 'set-face-extend) (mapc (lambda (f) (set-face-extend f extend-p)) faces))) -(if (fboundp 'string-distance) - (defalias 'org-string-distance 'string-distance) - (defun org-string-distance (s1 s2) - "Return the edit (levenshtein) distance between strings S1 S2." - (let* ((l1 (length s1)) - (l2 (length s2)) - (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) - (number-sequence 1 (1+ l1))))) - (in (lambda (i j) (aref (aref dist i) j)))) - (setf (aref (aref dist 0) 0) 0) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist 0) j) j)) - (dolist (i (number-sequence 1 l1)) - (setf (aref (aref dist i) 0) i) - (dolist (j (number-sequence 1 l2)) - (setf (aref (aref dist i) j) - (min - (1+ (funcall in (1- i) j)) - (1+ (funcall in i (1- j))) - (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) - (funcall in (1- i) (1- j))))))) - (funcall in l1 l2)))) - (define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance "9.5") @@ -340,23 +219,6 @@ (if (fboundp 'line-number-display-width) (defalias 'org-line-number-display-width 'line-number-display-width) (defun org-line-number-display-width (&rest _) 0)) -(if (fboundp 'buffer-hash) - (defalias 'org-buffer-hash 'buffer-hash) - (defun org-buffer-hash () (md5 (current-buffer)))) - -(unless (fboundp 'file-attribute-modification-time) - (defsubst file-attribute-modification-time (attributes) - "The modification time in ATTRIBUTES returned by `file-attributes'. -This is the time of the last change to the file's contents, and -is a Lisp timestamp in the same style as `current-time'." - (nth 5 attributes))) - -(unless (fboundp 'file-attribute-size) - (defsubst file-attribute-size (attributes) - "The size (in bytes) in ATTRIBUTES returned by `file-attributes'. -This is a floating point number if the size is too large for an integer." - (nth 7 attributes))) - ;;; Obsolete aliases (remove them after the next major release). @@ -1460,7 +1322,7 @@ (defun org-mode-flyspell-verify () (and log (let ((drawer (org-element-lineage element '(drawer)))) (and drawer - (org-string-equal-ignore-case + (string-equal-ignore-case log (org-element-property :drawer-name drawer)))))) nil) (t diff --git a/lisp/org-fold-core.el b/lisp/org-fold-core.el index 43c6b2b74..c699c115b 100644 --- a/lisp/org-fold-core.el +++ b/lisp/org-fold-core.el @@ -841,7 +841,7 @@ (defun org-fold-core-next-visibility-change (&optional pos limit ignore-hidden-p (lambda (p) (next-single-char-property-change p 'invisible nil limit))))) (next pos)) (while (and (funcall cmp next limit) - (not (org-xor + (not (xor invisible-initially? (funcall invisible-p (if previous-p diff --git a/lisp/org-lint.el b/lisp/org-lint.el index dc18b657c..3aa148e69 100644 --- a/lisp/org-lint.el +++ b/lisp/org-lint.el @@ -383,7 +383,7 @@ (defun org-lint-duplicate-custom-id (ast) ast 'node-property (lambda (property) - (and (org-string-equal-ignore-case + (and (string-equal-ignore-case "CUSTOM_ID" (org-element-property :key property)) (org-element-property :value property))) (lambda (property _) (org-element-property :begin property)) diff --git a/lisp/org-persist.el b/lisp/org-persist.el index d8b7dc4a1..45031c1dc 100644 --- a/lisp/org-persist.el +++ b/lisp/org-persist.el @@ -279,12 +279,12 @@ (defgroup org-persist nil (defcustom org-persist-directory (expand-file-name - (org-file-name-concat + (file-name-concat (let ((cache-dir (when (fboundp 'xdg-cache-home) (xdg-cache-home)))) (if (or (seq-empty-p cache-dir) (not (file-exists-p cache-dir)) - (file-exists-p (org-file-name-concat + (file-exists-p (file-name-concat user-emacs-directory "org-persist"))) user-emacs-directory @@ -675,13 +675,13 @@ (defalias 'org-persist-read:version #'org-persist-read:elisp-data) (defun org-persist-read:file (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:url (_ path __) "Read file container from PATH." - (when (and path (file-exists-p (org-file-name-concat org-persist-directory path))) - (org-file-name-concat org-persist-directory path))) + (when (and path (file-exists-p (file-name-concat org-persist-directory path))) + (file-name-concat org-persist-directory path))) (defun org-persist-read:index (cont index-file _) "Read index container CONT from INDEX-FILE." @@ -750,7 +750,7 @@ (defun org-persist--load-index () "Load `org-persist--index'." (org-persist-load:index `(index ,org-persist--storage-version) - (org-file-name-concat org-persist-directory org-persist-index-file) + (file-name-concat org-persist-directory org-persist-index-file) nil)) ;;;; Writing container data @@ -805,7 +805,7 @@ (defun org-persist-write:file (c collection) (setq path (cadr c))) (let* ((persist-file (plist-get collection :persist-file)) (ext (file-name-extension path)) - (file-copy (org-file-name-concat + (file-copy (file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) (unless (file-exists-p file-copy) @@ -851,7 +851,7 @@ (defun org-persist-write:index (container _) org-persist-directory)))) (when (file-exists-p org-persist-directory) (let ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file))) + (file-name-concat org-persist-directory org-persist-index-file))) (org-persist--merge-index-with-disk) (org-persist--write-elisp-file index-file org-persist--index t t) (setq org-persist--index-age @@ -866,7 +866,7 @@ (defun org-persist--save-index () (defun org-persist--merge-index-with-disk () "Merge `org-persist--index' with the current index file on disk." (let* ((index-file - (org-file-name-concat org-persist-directory org-persist-index-file)) + (file-name-concat org-persist-directory org-persist-index-file)) (disk-index (and (file-exists-p index-file) (org-file-newer-than-p index-file org-persist--index-age) @@ -888,8 +888,8 @@ (defun org-persist--merge-index (base other) (dolist (item (nreverse new)) (unless (or (memq 'index (mapcar #'car (plist-get item :container))) (not (file-exists-p - (org-file-name-concat org-persist-directory - (plist-get item :persist-file)))) + (file-name-concat org-persist-directory + (plist-get item :persist-file)))) (member (plist-get item :persist-file) base-files)) (push item combined))) (nreverse combined)) @@ -990,7 +990,7 @@ (cl-defun org-persist-read (container &optional associated hash-must-match load (let* ((collection (org-persist--find-index `(:container ,container :associated ,associated))) (persist-file (when collection - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (data nil)) @@ -1078,7 +1078,7 @@ (defun org-persist-write (container &optional associated ignore-return) (run-hook-with-args-until-success 'org-persist-before-write-hook v associated)) (plist-get collection :container))) (when (or (file-exists-p org-persist-directory) (org-persist--save-index)) - (let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file))) + (let ((file (file-name-concat org-persist-directory (plist-get collection :persist-file))) (data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection))) (plist-get collection :container)))) (puthash file data org-persist--write-cache) @@ -1098,11 +1098,11 @@ (defun org-persist-write-all (&optional associated) ;; The container is an `index' container. (eq 'index (caar (plist-get (car org-persist--index) :container))) (or (not (file-exists-p org-persist-directory)) - (org-directory-empty-p org-persist-directory))) + (directory-empty-p org-persist-directory))) ;; Do not write anything, and clear up `org-persist-directory' to reduce ;; clutter. (when (and (file-exists-p org-persist-directory) - (org-directory-empty-p org-persist-directory)) + (directory-empty-p org-persist-directory)) (delete-directory org-persist-directory)) ;; Write the data. (let (all-containers) @@ -1143,7 +1143,7 @@ (defun org-persist--gc-persist-file (persist-file) "Garbage collect PERSIST-FILE." (when (file-exists-p persist-file) (delete-file persist-file) - (when (org-directory-empty-p (file-name-directory persist-file)) + (when (directory-empty-p (file-name-directory persist-file)) (delete-directory (file-name-directory persist-file))))) (defmacro org-persist-associated-files:generic (container collection) @@ -1181,7 +1181,7 @@ (defun org-persist-gc () (let (new-index (remote-files-num 0) (orphan-files - (delete (org-file-name-concat org-persist-directory org-persist-index-file) + (delete (file-name-concat org-persist-directory org-persist-index-file) (when (file-exists-p org-persist-directory) (directory-files-recursively org-persist-directory ".+"))))) (dolist (collection org-persist--index) @@ -1189,7 +1189,7 @@ (defun org-persist-gc () (web-file (and file (string-match-p "\\`https?://" file))) (file-remote (when file (file-remote-p file))) (persist-file (when (plist-get collection :persist-file) - (org-file-name-concat + (file-name-concat org-persist-directory (plist-get collection :persist-file)))) (expired? (org-persist--gc-expired-p diff --git a/lisp/org-refile.el b/lisp/org-refile.el index 03c351cf6..9797a0633 100644 --- a/lisp/org-refile.el +++ b/lisp/org-refile.el @@ -666,7 +666,7 @@ (defun org-refile-get-location (&optional prompt default-buffer new-nodes) (prompt (let ((default (or (car org-refile-history) (and (assoc cbnex tbl) (setq cdef cbnex) cbnex)))) - (org-format-prompt prompt default))) + (format-prompt prompt default))) pa answ parent-target child parent old-hist) (setq old-hist org-refile-history) (setq answ (funcall cfunc prompt tbl nil (not new-nodes) diff --git a/lisp/org.el b/lisp/org.el index 162982405..15fdd2212 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -19486,7 +19486,7 @@ (defun org-fill-paragraph (&optional justify region) (barf-if-buffer-read-only) (list (when current-prefix-arg 'full) t))) (let ((hash (and (not (buffer-modified-p)) - (org-buffer-hash)))) + (buffer-hash)))) (cond ((and region transient-mark-mode mark-active (not (eq (region-beginning) (region-end)))) @@ -19511,7 +19511,7 @@ (defun org-fill-paragraph (&optional justify region) ;; If we didn't change anything in the buffer (and the buffer was ;; previously unmodified), then flip the modification status back ;; to "unchanged". - (when (and hash (equal hash (org-buffer-hash))) + (when (and hash (equal hash (buffer-hash))) (set-buffer-modified-p nil)) ;; Return non-nil. t)) diff --git a/lisp/ox.el b/lisp/ox.el index d75a80a2e..a3f37b5e8 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -4643,11 +4643,11 @@ (defun org-export-resolve-radio-link (link info) Return value can be a radio-target object or nil. Assume LINK has type \"radio\"." - (let ((path (org-string-clean-whitespace (org-element-property :path link)))) + (let ((path (string-clean-whitespace (org-element-property :path link)))) (org-element-map (plist-get info :parse-tree) 'radio-target (lambda (radio) - (and (org-string-equal-ignore-case - (org-string-clean-whitespace (org-element-property :value radio)) + (and (string-equal-ignore-case + (string-clean-whitespace (org-element-property :value radio)) path) radio)) info 'first-match))) diff --git a/testing/lisp/test-ol.el b/testing/lisp/test-ol.el index a38d9f979..565539571 100644 --- a/testing/lisp/test-ol.el +++ b/testing/lisp/test-ol.el @@ -63,19 +63,19 @@ (ert-deftest test-org-link/toggle-link-display () (dotimes (_ 2) (goto-char 1) (re-search-forward "\\[") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "example") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "com") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (re-search-forward "\\[") (should-not (org-invisible-p)) (re-search-forward "link") (should-not (org-invisible-p)) (re-search-forward "]") - (should-not (org-xor org-link-descriptive (org-invisible-p))) + (should-not (xor org-link-descriptive (org-invisible-p))) (org-toggle-link-display))))) diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el index 0ed44c6af..6a47b3384 100644 --- a/testing/lisp/test-org-capture.el +++ b/testing/lisp/test-org-capture.el @@ -154,7 +154,7 @@ (ert-deftest test-org-capture/abort () "Test aborting a capture process." ;; Newly create capture buffer should not be saved. (let ((capture-file (make-temp-name - (org-file-name-concat + (file-name-concat temporary-file-directory "org-test")))) (unwind-protect -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0005-org-manual.org-Document-compat-library-installati.patch >From 1f086a879fcaeaca3e8b4e1c6a9b6c686e3a2fdf Mon Sep 17 00:00:00 2001 Message-Id: <1f086a879fcaeaca3e8b4e1c6a9b6c686e3a2fdf.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sat, 1 Apr 2023 12:18:57 +0200 Subject: [PATCH v4 5/8] org-manual.org: Document compat library installation * doc/org-manual.org (Using Org's git repository): Document that users must also install compat library when using git version of Org. * etc/ORG-NEWS (Org mode now uses =compat.el= third-party package to support older Emacs versions): Announce amendments to the Org installation from git sources. --- doc/org-manual.org | 4 ++++ etc/ORG-NEWS | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/doc/org-manual.org b/doc/org-manual.org index 007126714..89fdd3d0f 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -140,6 +140,10 @@ *** Using Org's git repository (add-to-list 'load-path "~/src/org-mode/lisp") #+end_src +You must also manually install =compat= library required by Org mode. +Using built-in =package.el=, you can run =M-x package-install +compat =. + You can also compile with =make=, generate the documentation with =make doc=, create a local configuration with =make config= and install Org with =make install=. Please run =make help= to get the diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 03894f128..6fd117ef7 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,13 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Org mode now uses =compat.el= third-party package to support older Emacs versions + +This change is mostly technical and should not affect most users. +However, people who install Org from git source might be affected. +It is now necessary to manually install =compat.el= using Emacs' +package manager. + *** "Priority" used to sort items in agenda is renamed to "urgency" Previously, ~priority-up~ and ~priority-down~ in -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0006-mk-Echo-main-compilation-states-when-running-make.patch >From 3ff50698fd9c0d9cf9795f3a7fcef9b3b7730061 Mon Sep 17 00:00:00 2001 Message-Id: <3ff50698fd9c0d9cf9795f3a7fcef9b3b7730061.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sun, 2 Apr 2023 14:05:22 +0200 Subject: [PATCH v4 6/8] mk: Echo main compilation states when running make * lisp/Makefile (all compile compile-dirty): ($(LISPV)): ($(LISPI)): Echo compile stage. * mk/targets.mk (uppkg): Echo compile stage and hide the installation command. --- lisp/Makefile | 7 +++++-- mk/targets.mk | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/Makefile b/lisp/Makefile index f507f18a2..45d8109f0 100644 --- a/lisp/Makefile +++ b/lisp/Makefile @@ -20,6 +20,7 @@ _ORGCM_ := dirall single source slint1 slint2 # do not clean here, done in toplevel make all compile compile-dirty:: autoloads + @$(info ========= Compiling lisp files using '$(ORGCM)' target) ifeq ($(filter-out $(_ORGCM_),$(ORGCM)),) $(MAKE) compile-$(ORGCM) else @@ -52,12 +53,14 @@ slint1: autoloads: cleanauto $(LISPI) $(LISPV) $(LISPV): $(LISPF) - @echo "org-version: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org version number) + @$(info org-version: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_VERSION) $(LISPI): $(LISPV) $(LISPF) - @echo "org-loaddefs: $(ORGVERSION) ($(GITVERSION))" + @$(info ========= Auto-generating Org loaddefs) + @$(info org-loaddefs: $(ORGVERSION) ($(GITVERSION))) @$(RM) $(@) @$(MAKE_ORG_INSTALL) diff --git a/mk/targets.mk b/mk/targets.mk index 18140c5c0..ddd959c61 100644 --- a/mk/targets.mk +++ b/mk/targets.mk @@ -103,6 +103,7 @@ ifeq ($(TEST_NO_AUTOCLEAN),) # define this variable to leave $(testdir) around f endif uppkg:: + $(info ========= Installing required third-party packages) @$(MKDIR) -p $(pkgdir) -@$(INSTALL_PACKAGES) -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0007-Makefile-Document-new-targets-in-make-helpall.patch >From 6e0254d985970e6a96ad9f0f9a8f9ec377b9dce2 Mon Sep 17 00:00:00 2001 Message-Id: <6e0254d985970e6a96ad9f0f9a8f9ec377b9dce2.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Thu, 13 Apr 2023 14:33:16 +0200 Subject: [PATCH v4 7/8] * Makefile: Document new targets in make helpall Document the newly added cleanpkg and uppkg targets. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index f476a3ea7..5e0e0fdff 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ helpall:: $(info Cleaning) $(info ========) $(info make clean - remove built Org ELisp files and documentation) + $(info make cleanpkg - remove third-party packages downloaded via make uppkg) $(info make cleanall - remove everything that can be built and all remnants) $(info make clean-install - remove previous Org installation) $(info ) @@ -81,6 +82,7 @@ helpall:: $(info Convenience) $(info ===========) $(info make up0 - pull from upstream) + $(info make uppkg - download third-party packages required for compilation) $(info make up1 - pull from upstream, build and check) $(info make up2 - pull from upstream, build, check and install) $(info make update - pull from upstream and build) -- 2.40.0 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v4-0008-lisp-org-compat.el-Throw-error-without-compat-in-.patch >From 4316fc76877bea60d89e32af0caf14d4da363f69 Mon Sep 17 00:00:00 2001 Message-Id: <4316fc76877bea60d89e32af0caf14d4da363f69.1682849409.git.yantar92@posteo.net> In-Reply-To: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> References: <3946dbb956afcd005cba0f1899acae5a74a109d4.1682849409.git.yantar92@posteo.net> From: Ihor Radchenko Date: Tue, 18 Apr 2023 13:05:53 +0200 Subject: [PATCH v4 8/8] * lisp/org-compat.el: Throw error without compat in older Emacs Demand compat when using older Emacs. This is a better approach compared to (require 'compat nil 'noerror) because not erring on the `require' would generate a bunch of cryptic errors about functions not being defined from user perspective. --- lisp/org-compat.el | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lisp/org-compat.el b/lisp/org-compat.el index c40510c35..205fb30af 100644 --- a/lisp/org-compat.el +++ b/lisp/org-compat.el @@ -94,9 +94,10 @@ (defvar org-fold-core-style) ;;; compat.el -;; Do not throw an error when not available - assume latest Emacs -;; version (built-in Org). -(require 'compat nil 'noerror) +;; Use compat for older Emacs, supplying helpful error message if +;; compat is not available. +(when (version< emacs-version "29") + (org-require-package 'compat)) ;; Provide compatibility macros when we are a part of Emacs. ;; See https://elpa.gnu.org/packages/doc/compat.html#Usage -- 2.40.0 --=-=-= Content-Type: text/plain -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at . Support Org development at , or support my work at --=-=-=--