From: Lin Sun <sunlin7.mail@gmail.com>
To: kobarity <kobarity@gmail.com>
Cc: Eli Zaretskii <eliz@gnu.org>,
Stefan Kangas <stefankangas@gmail.com>,
70815@debbugs.gnu.org
Subject: bug#70815: [PATCH] ; Enahnce python-tests.el to adapt different python interpreters
Date: Tue, 21 May 2024 15:34:12 +0000 [thread overview]
Message-ID: <CABCREdoDyTQo=7_27Mvx2Ki4x-FuADeVT3ZL=A-oKxkCapmtKg@mail.gmail.com> (raw)
In-Reply-To: <eke7a5kjl0rq.wl-kobarity@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2630 bytes --]
On Tue, May 21, 2024 at 2:04 PM kobarity <kobarity@gmail.com> wrote:
>
>
> Lin Sun wrote:
> > On Mon, May 20, 2024 at 3:53 PM kobarity <kobarity@gmail.com> wrote:
> > > Eli Zaretskii wrote:
> > > > > Cc: kobarity <kobarity@gmail.com>
> > > > > From: Stefan Kangas <stefankangas@gmail.com>
> > > > > Date: Sat, 18 May 2024 22:20:44 +0000
> > > > >
> > > > > It makes sense to look for "python3", but is it really useful to look
> > > > > for "python2" at this point?
> > > > I don't think we want to drop Python 2.x support, not yet.
> > >
> > > I don't want to drop Python 2 support either, but I don't think the
> > > addition of the "python2" command is mandatory. As the current master
> > > does not run the "python2" command either. However, I don't think it
> > > is a bad idea to add the "python2" command.
> > >
> > > Lin Sun wrote:
> > > > Hi,
> > > > I attached the latest patch, hope it resolved all your concerns.
> > >
> > > Hi Lin,
> > > There is still a typo "Enahnce" in the summary line, and there is a
> > > typo in the docstring of `python-tests-get-shell-interpreter' as well.
> > >
> > > > > If there is only python2 in the PATH and no python or python3, some tests will fail.
> > > > It's caused by the python.el didn't search "python2", so it may need
> > > > another patch to change python.el.
> > >
> > > I don't think so. Attached is a diff to your patch to resolve this
> > > issue. It let-binds `python-shell-interpreter' in some ERTs. It
> > > also includes the fix of the typo in the docstring of
> > > `python-tests-get-shell-interpreter'.
> > >
> > > Without these modifications, EMACS_PYTHON_INTERPRETER will not work as
> > > expected either on those ERTs.
> > >
> > > As for EMACS_PYTHON_INTERPRETER, I am a little doubtful that it is the
> > > right thing to introduce. It allows the ERT runner to specify the
> > > interpreter. It's OK for ERTs that can be run on both Python 2 and 3,
> > > but you may want to write an ERT that can only be run on Python 3.
> >
> > Thank you for the comments, now get your points and agree with you.
> > I merged your patch together, also corrected the typo in the commit message.
> > Please help review the attached patch. Thank you !
>
> Sorry, there was a problem in my diff. Two tests fail when
> EMACS_PYTHON_INTERPRETER is not found. Please apply the attached
> diff. It also includes a suggestion for improving the error message.
> Please consider.
Merged your changes and tested on my local (with python/python3), it
works perfectly. Thank you.
And the patch file is attached .
[-- Attachment #2: 0001-Enhance-python-tests.el-to-adapt-different-python-in.patch --]
[-- Type: text/x-patch, Size: 17745 bytes --]
From 918de75b5e5de1c052c6d8067b8232d04d9869ce Mon Sep 17 00:00:00 2001
From: Lin Sun <sunlin7@hotmail.com>
Date: Fri, 3 May 2024 06:52:22 +0000
Subject: [PATCH] Enhance python-tests.el to adapt different python
interpreters (bug#70815)
* test/lisp/progmodes/python-tests.el
(python-tests-get-shell-interpreter): New function to get python
interpreter for testing; and also introduce new env variable
EMACS_PYTHON_INTERPRETER to support customer python interpreter.
Co-authored-by: kobarity <kobarity@gmail.com>
---
test/lisp/progmodes/python-tests.el | 102 ++++++++++++++++------------
1 file changed, 60 insertions(+), 42 deletions(-)
diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el
index f50797953c3..4364c11a76b 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -21,6 +21,7 @@
;;; Code:
+(require 'cl-extra)
(require 'ert)
(require 'ert-x)
(require 'python)
@@ -58,7 +59,8 @@ turned off. Shell buffer will be killed on exit."
(let ((dir (make-symbol "dir")))
`(with-temp-buffer
(let ((python-indent-guess-indent-offset nil)
- (python-shell-completion-native-enable nil))
+ (python-shell-completion-native-enable nil)
+ (python-shell-interpreter (python-tests-get-shell-interpreter)))
(python-mode)
(unwind-protect
;; Prevent test failures when Jedi is used as a completion
@@ -3718,7 +3720,19 @@ if x:
\f
;;; Shell integration
-(defvar python-tests-shell-interpreter "python")
+(defvar python-tests-shell-interpreter nil)
+
+(defun python-tests-get-shell-interpreter ()
+ "Get the shell interpreter.
+If env string EMACS_PYTHON_INTERPRETER exists, use it as preferred one."
+ (if python-tests-shell-interpreter
+ python-tests-shell-interpreter
+ (setq python-tests-shell-interpreter
+ (or (when-let ((interpreter (getenv "EMACS_PYTHON_INTERPRETER")))
+ (or (executable-find interpreter)
+ (error "Couldn't find EMACS_PYTHON_INTERPRETER(%s) in path"
+ interpreter)))
+ (cl-some #'executable-find '("python" "python3" "python2"))))))
(ert-deftest python-shell-get-process-name-1 ()
"Check process name calculation sans `buffer-file-name'."
@@ -3980,13 +3994,13 @@ if x:
(ert-deftest python-shell-make-comint-1 ()
"Check comint creation for global shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
;; The interpreter can get killed too quickly to allow it to clean
;; up the tempfiles that the default python-shell-setup-codes create,
;; so it leaves tempfiles behind, which is a minor irritation.
(let* ((python-shell-setup-codes nil)
(python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
+ (python-tests-get-shell-interpreter))
(proc-name (python-shell-get-process-name nil))
(shell-buffer
(python-tests-with-temp-buffer
@@ -4004,10 +4018,10 @@ if x:
(ert-deftest python-shell-make-comint-2 ()
"Check comint creation for internal shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((python-shell-setup-codes nil)
(python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
+ (python-tests-get-shell-interpreter))
(proc-name (python-shell-internal-get-process-name))
(shell-buffer
(python-tests-with-temp-buffer
@@ -4028,13 +4042,13 @@ if x:
The command passed to `python-shell-make-comint' as argument must
locally override global values set in `python-shell-interpreter'
and `python-shell-interpreter-args' in the new shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((python-shell-setup-codes nil)
(python-shell-interpreter "interpreter")
(python-shell-interpreter-args "--some-args")
(proc-name (python-shell-get-process-name nil))
(interpreter-override
- (concat (executable-find python-tests-shell-interpreter) " " "-i"))
+ (concat (python-tests-get-shell-interpreter) " " "-i"))
(shell-buffer
(python-tests-with-temp-buffer
"" (python-shell-make-comint interpreter-override proc-name nil)))
@@ -4047,17 +4061,17 @@ and `python-shell-interpreter-args' in the new shell buffer."
(should (eq major-mode 'inferior-python-mode))
(should (file-equal-p
python-shell-interpreter
- (executable-find python-tests-shell-interpreter)))
+ (python-tests-get-shell-interpreter)))
(should (string= python-shell-interpreter-args "-i"))))
(kill-buffer shell-buffer))))
(ert-deftest python-shell-make-comint-4 ()
"Check shell calculated prompts regexps are set."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((process-environment process-environment)
(python-shell-setup-codes nil)
(python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
+ (python-tests-get-shell-interpreter))
(python-shell-interpreter-args "-i")
(python-shell--prompt-calculated-input-regexp nil)
(python-shell--prompt-calculated-output-regexp nil)
@@ -4099,12 +4113,12 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-get-process-1 ()
"Check dedicated shell process preference over global."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-file
""
(let* ((python-shell-setup-codes nil)
(python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
+ (python-tests-get-shell-interpreter))
(global-proc-name (python-shell-get-process-name nil))
(dedicated-proc-name (python-shell-get-process-name t))
(global-shell-buffer
@@ -4132,12 +4146,12 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-internal-get-or-create-process-1 ()
"Check internal shell process creation fallback."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-file
""
(should (not (process-live-p (python-shell-internal-get-process-name))))
(let* ((python-shell-interpreter
- (executable-find python-tests-shell-interpreter))
+ (python-tests-get-shell-interpreter))
(internal-process-name (python-shell-internal-get-process-name))
(internal-process (python-shell-internal-get-or-create-process))
(internal-shell-buffer (process-buffer internal-process)))
@@ -4155,8 +4169,9 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-1 ()
"Check prompt autodetection."
- (skip-unless (executable-find python-tests-shell-interpreter))
- (let ((process-environment process-environment))
+ (skip-unless (python-tests-get-shell-interpreter))
+ (let ((process-environment process-environment)
+ (python-shell-interpreter (python-tests-get-shell-interpreter)))
;; Ensure no startup file is enabled
(setenv "PYTHONSTARTUP" "")
(should python-shell-prompt-detect-enabled)
@@ -4164,8 +4179,9 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-2 ()
"Check prompt autodetection with startup file. Bug#17370."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((process-environment process-environment)
+ (python-shell-interpreter (python-tests-get-shell-interpreter))
(startup-code (concat "import sys\n"
"sys.ps1 = 'py> '\n"
"sys.ps2 = '..> '\n"
@@ -4181,7 +4197,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-3 ()
"Check prompts are not autodetected when feature is disabled."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let ((process-environment process-environment)
(python-shell-prompt-detect-enabled nil))
;; Ensure no startup file is enabled
@@ -4190,7 +4206,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-4 ()
"Check warning is shown when detection fails."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((process-environment process-environment)
;; Trigger failure by removing prompts in the startup file
(startup-code (concat "import sys\n"
@@ -4211,7 +4227,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-5 ()
"Check disabled warnings are not shown when detection fails."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((process-environment process-environment)
(startup-code (concat "import sys\n"
"sys.ps1 = ''\n"
@@ -4232,7 +4248,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-detect-6 ()
"Warnings are not shown when detection is disabled."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((process-environment process-environment)
(startup-code (concat "import sys\n"
"sys.ps1 = ''\n"
@@ -4396,7 +4412,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(ert-deftest python-shell-prompt-set-calculated-regexps-6 ()
"Check detected prompts are included `regexp-quote'd."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(let* ((python-shell-prompt-input-regexps '(""))
(python-shell-prompt-output-regexps '(""))
(python-shell-prompt-regexp "")
@@ -4406,6 +4422,7 @@ and `python-shell-interpreter-args' in the new shell buffer."
(python-shell--prompt-calculated-input-regexp nil)
(python-shell--prompt-calculated-output-regexp nil)
(python-shell-prompt-detect-enabled t)
+ (python-shell-interpreter (python-tests-get-shell-interpreter))
(process-environment process-environment)
(startup-code (concat "import sys\n"
"sys.ps1 = 'p.> '\n"
@@ -4779,7 +4796,7 @@ def foo():
(should (python-shell-completion-native-interpreter-disabled-p))))
(ert-deftest python-shell-completion-at-point-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
""
(python-shell-with-shell-buffer
@@ -4793,7 +4810,7 @@ def foo():
(should-not (nth 2 (python-shell-completion-at-point))))))
(ert-deftest python-shell-completion-at-point-native-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
""
(python-shell-completion-native-turn-on)
@@ -4872,14 +4889,14 @@ def foo():
"Return Jedi readline setup file if PYTHONSTARTUP is not set."
(or (getenv "PYTHONSTARTUP")
(with-temp-buffer
- (if (eql 0 (call-process python-tests-shell-interpreter
+ (if (eql 0 (call-process (python-tests-get-shell-interpreter)
nil t nil "-m" "jedi" "repl"))
(string-trim (buffer-string))
""))))
(ert-deftest python-shell-completion-at-point-jedi-completer ()
"Check if Python shell completion works when Jedi completer is used."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(with-environment-variables
(("PYTHONSTARTUP" (python-tests--pythonstartup-file)))
(python-tests-with-temp-buffer-with-shell
@@ -4924,7 +4941,7 @@ def foo():
;;; Symbol completion
(ert-deftest python-completion-at-point-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -4942,7 +4959,7 @@ import abc
(ert-deftest python-completion-at-point-2 ()
"Should work regardless of the point in the Shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -4960,7 +4977,7 @@ import abc
(ert-deftest python-completion-at-point-pdb-1 ()
"Should not complete PDB commands in Python buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import pdb
@@ -4979,7 +4996,7 @@ print('Hello')
(ert-deftest python-completion-at-point-while-running-1 ()
"Should not try to complete when a program is running in the Shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import time
@@ -4995,7 +5012,7 @@ time.sleep(3)
(should-not (with-timeout (1 t) (completion-at-point))))))
(ert-deftest python-completion-at-point-native-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5014,7 +5031,7 @@ import abc
(ert-deftest python-completion-at-point-native-2 ()
"Should work regardless of the point in the Shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5032,7 +5049,7 @@ import abc
(should (completion-at-point)))))
(ert-deftest python-completion-at-point-native-with-ffap-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5050,7 +5067,7 @@ import abc
(should (completion-at-point)))))
(ert-deftest python-completion-at-point-native-with-eldoc-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5077,7 +5094,7 @@ import abc
;;; FFAP
(ert-deftest python-ffap-module-path-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5089,7 +5106,7 @@ import abc
(ert-deftest python-ffap-module-path-while-running-1 ()
"Should not get module path when a program is running in the Shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import abc
@@ -5165,7 +5182,7 @@ some_symbol some_other_symbol
"some_symbol"))))
(ert-deftest python-eldoc--get-doc-at-point-1 ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import time
@@ -5178,7 +5195,7 @@ import time
(ert-deftest python-eldoc--get-doc-at-point-while-running-1 ()
"Should not get documentation when a program is running in the Shell buffer."
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"
import time
@@ -7396,8 +7413,9 @@ buffer with overlapping strings."
;; interpreter.
(ert-deftest python-tests--run-python-selects-window ()
"Test for bug#31398. See also bug#44421 and bug#52380."
- (skip-unless (executable-find python-tests-shell-interpreter))
- (let* ((buffer (process-buffer (run-python nil nil 'show)))
+ (skip-unless (python-tests-get-shell-interpreter))
+ (let* ((python-shell-interpreter (python-tests-get-shell-interpreter))
+ (buffer (process-buffer (run-python nil nil 'show)))
(window (get-buffer-window buffer)))
;; We look at `selected-window' rather than `current-buffer'
;; because as `(elisp)Current buffer' says, the latter will only
@@ -7467,7 +7485,7 @@ buffer with overlapping strings."
"W0611: Unused import a.b.c (unused-import)"))))))
(ert-deftest python-test--shell-send-block ()
- (skip-unless (executable-find python-tests-shell-interpreter))
+ (skip-unless (python-tests-get-shell-interpreter))
(python-tests-with-temp-buffer-with-shell
"print('current 0')
for x in range(1,3):
--
2.20.5
next prev parent reply other threads:[~2024-05-21 15:34 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-07 6:53 bug#70815: [PATCH] ; Enahnce python-tests.el to adapt different python interpreters Lin Sun
2024-05-11 9:05 ` Eli Zaretskii
2024-05-11 13:37 ` kobarity
2024-05-11 14:27 ` Lin Sun
2024-05-12 2:06 ` kobarity
2024-05-18 22:20 ` Stefan Kangas
2024-05-19 5:54 ` Eli Zaretskii
2024-05-20 0:08 ` Lin Sun
2024-05-20 15:52 ` kobarity
2024-05-20 17:51 ` Lin Sun
2024-05-21 14:04 ` kobarity
2024-05-21 15:34 ` Lin Sun [this message]
2024-05-22 14:38 ` kobarity
2024-05-23 13:09 ` Eli Zaretskii
2024-05-26 10:52 ` Mattias Engdegård
2024-05-26 12:05 ` kobarity
2024-05-26 12:21 ` Mattias Engdegård
2024-05-26 12:36 ` kobarity
2024-05-26 13:23 ` Mattias Engdegård
2024-05-26 14:15 ` kobarity
2024-05-26 15:00 ` kobarity
2024-05-26 15:24 ` Mattias Engdegård
2024-05-27 12:33 ` kobarity
2024-05-27 12:45 ` Eli Zaretskii
2024-05-28 12:30 ` Mattias Engdegård
2024-05-28 15:17 ` kobarity
2024-05-28 16:09 ` Mattias Engdegård
2024-05-29 14:56 ` kobarity
2024-05-30 10:09 ` Mattias Engdegård
2024-06-02 13:20 ` kobarity
2024-06-03 14:02 ` Mattias Engdegård
2024-06-03 14:34 ` kobarity
2024-06-03 16:24 ` kobarity
2024-06-04 14:29 ` kobarity
2024-06-05 10:25 ` Mattias Engdegård
2024-06-05 11:52 ` kobarity
2024-06-08 15:34 ` kobarity
2024-06-09 13:58 ` Mattias Engdegård
2024-06-10 14:57 ` kobarity
2024-06-10 15:44 ` Mattias Engdegård
2024-05-26 15:56 ` Eli Zaretskii
2024-05-26 23:06 ` Stefan Kangas
2024-05-27 11:18 ` Eli Zaretskii
2024-05-27 12:20 ` Mattias Engdegård
2024-05-27 12:43 ` Eli Zaretskii
2024-05-26 15:52 ` Eli Zaretskii
2024-05-27 10:24 ` Mattias Engdegård
2024-05-27 11:19 ` Lin Sun
2024-05-26 15:36 ` Eli Zaretskii
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CABCREdoDyTQo=7_27Mvx2Ki4x-FuADeVT3ZL=A-oKxkCapmtKg@mail.gmail.com' \
--to=sunlin7.mail@gmail.com \
--cc=70815@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=kobarity@gmail.com \
--cc=stefankangas@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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.